Пример #1
0
int hdhomerun_device_selector_load_from_windows_registry(struct hdhomerun_device_selector_t *hds, wchar_t *wsource)
{
	HKEY tuners_key;
	LONG ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Silicondust\\HDHomeRun\\Tuners", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &tuners_key);
	if (ret != ERROR_SUCCESS) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open tuners registry key (%ld)\n", (long)ret);
		return 0;
	}

	DWORD index = 0;
	while (1) {
		/* Next tuner device. */
		wchar_t wdevice_name[32];
		DWORD size = sizeof(wdevice_name);
		ret = RegEnumKeyEx(tuners_key, index++, wdevice_name, &size, NULL, NULL, NULL, NULL);
		if (ret != ERROR_SUCCESS) {
			break;
		}

		/* Check device configuation. */
		HKEY device_key;
		ret = RegOpenKeyEx(tuners_key, wdevice_name, 0, KEY_QUERY_VALUE, &device_key);
		if (ret != ERROR_SUCCESS) {
			hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: failed to open registry key for %S (%ld)\n", wdevice_name, (long)ret);
			continue;
		}

		wchar_t wsource_test[32];
		size = sizeof(wsource_test);
		if (RegQueryValueEx(device_key, L"Source", NULL, NULL, (LPBYTE)&wsource_test, &size) != ERROR_SUCCESS) {
			wsprintf(wsource_test, L"Unknown");
		}

		RegCloseKey(device_key);

		if (_wcsicmp(wsource_test, wsource) != 0) {
			continue;
		}

		/* Create and add device. */
		char device_name[32];
		sprintf(device_name, "%S", wdevice_name);

		struct hdhomerun_device_t *hd = hdhomerun_device_create_from_str(device_name, hds->dbg);
		if (!hd) {
			hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_load_from_windows_registry: invalid device name '%s' / failed to create device object\n", device_name);
			continue;
		}

		hdhomerun_device_selector_add_device(hds, hd);
	}

	RegCloseKey(tuners_key);
	return (int)hds->hd_count;
}
struct hdhomerun_device_t *hdhomerun_device_selector_choose_and_lock(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *prefered)
{
	/* Test prefered device first. */
	if (prefered) {
		if (hdhomerun_device_selector_choose_test(hds, prefered)) {
			return prefered;
		}
	}

	/* Test other tuners. */
	size_t index;
	for (index = 0; index < hds->hd_count; index++) {
		struct hdhomerun_device_t *entry = hds->hd_list[index];
		if (entry == prefered) {
			continue;
		}

		if (hdhomerun_device_selector_choose_test(hds, entry)) {
			return entry;
		}
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_and_lock: no devices available\n");
	return NULL;
}
int hdhomerun_video_join_multicast_group(struct hdhomerun_video_sock_t *vs, uint32_t multicast_ip, uint32_t local_ip)
{
	if (!hdhomerun_sock_join_multicast_group(vs->sock, multicast_ip, local_ip)) {
		hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_join_multicast_group: setsockopt failed (%d)\n", hdhomerun_sock_getlasterror());
		return -1;
	}

	return 1;
}
Пример #4
0
uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs)
{
	struct sockaddr_in sock_addr;
	socklen_t sockaddr_size = sizeof(sock_addr);
	if (getsockname(vs->sock, (struct sockaddr*)&sock_addr, &sockaddr_size) != 0) {
		hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_get_local_port: getsockname failed (%d)\n", sock_getlasterror);
		return 0;
	}
	return ntohs(sock_addr.sin_port);
}
uint16_t hdhomerun_video_get_local_port(struct hdhomerun_video_sock_t *vs)
{
	uint16_t port = hdhomerun_sock_getsockname_port(vs->sock);
	if (port == 0) {
		hdhomerun_debug_printf(vs->dbg, "hdhomerun_video_get_local_port: getsockname failed (%d)\n", hdhomerun_sock_getlasterror());
		return 0;
	}

	return port;
}
Пример #6
0
void hdhomerun_video_debug_print_stats(struct hdhomerun_video_sock_t *vs)
{
	struct hdhomerun_video_stats_t stats;
	hdhomerun_video_get_stats(vs, &stats);

	hdhomerun_debug_printf(vs->dbg, "video sock: pkt=%ld net=%ld te=%ld miss=%ld drop=%ld\n",
		stats.packet_count, stats.network_error_count,
		stats.transport_error_count, stats.sequence_error_count,
		stats.overflow_error_count
	);
}
struct hdhomerun_device_selector_t *hdhomerun_device_selector_create(struct hdhomerun_debug_t *dbg)
{
	struct hdhomerun_device_selector_t *hds = (struct hdhomerun_device_selector_t *)calloc(1, sizeof(struct hdhomerun_device_selector_t));
	if (!hds) {
		hdhomerun_debug_printf(dbg, "hdhomerun_device_selector_create: failed to allocate selector object\n");
		return NULL;
	}

	hds->dbg = dbg;

	return hds;
}
Пример #8
0
void hdhomerun_device_selector_add_device(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *hd)
{
	size_t index;
	for (index = 0; index < hds->hd_count; index++) {
		struct hdhomerun_device_t *entry = hds->hd_list[index];
		if (entry == hd) {
			return;
		}
	}

	hds->hd_list = (struct hdhomerun_device_t **)realloc(hds->hd_list, (hds->hd_count + 1) * sizeof(struct hdhomerun_device_selector_t *));
	if (!hds->hd_list) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_add_device: failed to allocate device list\n");
		return;
	}

	hds->hd_list[hds->hd_count++] = hd;
}
static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *test_hd)
{
	const char *name = hdhomerun_device_get_name(test_hd);

	/*
	 * Attempt to aquire lock.
	 */
	char *error = NULL;
	int ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
	if (ret > 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
		return TRUE;
	}
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}

	/*
	 * In use - check target.
	 */
	char *target;
	ret = hdhomerun_device_get_tuner_target(test_hd, &target);
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}
	if (ret == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to read target\n", name);
		return FALSE;
	}

	if (strcmp(target, "none") == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, no target set\n", name);
		return FALSE;
	}

	if ((strncmp(target, "udp://", 6) != 0) && (strncmp(target, "rtp://", 6) != 0)) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target);
		return FALSE;
	}

	unsigned int a[4];
	unsigned int target_port;
	if (sscanf(target + 6, "%u.%u.%u.%u:%u", &a[0], &a[1], &a[2], &a[3], &target_port) != 5) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, unexpected target set (%s)\n", name, target);
		return FALSE;
	}

	uint32_t target_ip = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
	uint32_t local_ip = hdhomerun_device_get_local_machine_addr(test_hd);
	if (target_ip != local_ip) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target);
		return FALSE;
	}

	/*
	 * Test local port.
	 */
	struct hdhomerun_sock_t *test_sock = hdhomerun_sock_create_udp();
	if (!test_sock) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name);
		return FALSE;
	}

	bool_t inuse = (hdhomerun_sock_bind(test_sock, INADDR_ANY, (uint16_t)target_port, FALSE) == FALSE);
	hdhomerun_sock_destroy(test_sock);

	if (inuse) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name);
		return FALSE;
	}

	/*
	 * Dead local target, force clear lock.
	 */
	ret = hdhomerun_device_tuner_lockkey_force(test_hd);
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}
	if (ret == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, failed to force release lockkey\n", name);
		return FALSE;
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, lockkey force successful\n", name);

	/*
	 * Attempt to aquire lock.
	 */
	ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
	if (ret > 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
		return TRUE;
	}
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s still in use after lockkey force (%s)\n", name, error);
	return FALSE;
}
Пример #10
0
static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *test_hd)
{
	const char *name = hdhomerun_device_get_name(test_hd);

	/*
	 * Attempt to aquire lock.
	 */
	char *error;
	int ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
	if (ret > 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
		return TRUE;
	}
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}

	/*
	 * In use - check target.
	 */
	char *target;
	ret = hdhomerun_device_get_tuner_target(test_hd, &target);
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}
	if (ret == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to read target\n", name);
		return FALSE;
	}

	char *ptr = strstr(target, "//");
	if (ptr) {
		target = ptr + 2;
	}
	ptr = strchr(target, ' ');
	if (ptr) {
		*ptr = 0;
	}

	unsigned long a[4];
	unsigned long target_port;
	if (sscanf(target, "%lu.%lu.%lu.%lu:%lu", &a[0], &a[1], &a[2], &a[3], &target_port) != 5) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, no target set (%s)\n", name, target);
		return FALSE;
	}

	uint32_t target_ip = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
	uint32_t local_ip = hdhomerun_device_get_local_machine_addr(test_hd);
	if (target_ip != local_ip) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target);
		return FALSE;
	}

	/*
	 * Test local port.
	 */
	hdhomerun_sock_t test_sock = hdhomerun_sock_create_udp();
	if (test_sock == HDHOMERUN_SOCK_INVALID) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name);
		return FALSE;
	}

	bool_t inuse = (hdhomerun_sock_bind(test_sock, INADDR_ANY, (uint16_t)target_port, FALSE) == FALSE);
	hdhomerun_sock_destroy(test_sock);

	if (inuse) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name);
		return FALSE;
	}

	/*
	 * Dead local target, force clear lock.
	 */
	ret = hdhomerun_device_tuner_lockkey_force(test_hd);
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}
	if (ret == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, failed to force release lockkey\n", name);
		return FALSE;
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, lockkey force successful\n", name);

	/*
	 * Attempt to aquire lock.
	 */
	ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
	if (ret > 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
		return TRUE;
	}
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s still in use after lockkey force (%s)\n", name, error);
	return FALSE;
}
struct hdhomerun_video_sock_t *hdhomerun_video_create(uint16_t listen_port, bool_t allow_port_reuse, size_t buffer_size, struct hdhomerun_debug_t *dbg)
{
	/* Create object. */
	struct hdhomerun_video_sock_t *vs = (struct hdhomerun_video_sock_t *)calloc(1, sizeof(struct hdhomerun_video_sock_t));
	if (!vs) {
		hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate video object\n");
		return NULL;
	}

	vs->dbg = dbg;
	vs->sock = HDHOMERUN_SOCK_INVALID;
	pthread_mutex_init(&vs->lock, NULL);

	/* Reset sequence tracking. */
	hdhomerun_video_flush(vs);

	/* Buffer size. */
	vs->buffer_size = (buffer_size / VIDEO_DATA_PACKET_SIZE) * VIDEO_DATA_PACKET_SIZE;
	if (vs->buffer_size == 0) {
		hdhomerun_debug_printf(dbg, "hdhomerun_video_create: invalid buffer size (%lu bytes)\n", (unsigned long)buffer_size);
		goto error;
	}
	vs->buffer_size += VIDEO_DATA_PACKET_SIZE;

	/* Create buffer. */
	vs->buffer = (uint8_t *)malloc(vs->buffer_size);
	if (!vs->buffer) {
		hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate buffer (%lu bytes)\n", (unsigned long)vs->buffer_size);
		goto error;
	}
	
	/* Create socket. */
	vs->sock = hdhomerun_sock_create_udp();
	if (vs->sock == HDHOMERUN_SOCK_INVALID) {
		hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to allocate socket\n");
		goto error;
	}

	/* Expand socket buffer size. */
	int rx_size = 1024 * 1024;
	setsockopt(vs->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rx_size, sizeof(rx_size));

	/* Bind socket. */
	if (!hdhomerun_sock_bind(vs->sock, INADDR_ANY, listen_port, allow_port_reuse)) {
		hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to bind socket (port %u)\n", listen_port);
		goto error;
	}

	/* Start thread. */
	if (pthread_create(&vs->thread, NULL, &hdhomerun_video_thread_execute, vs) != 0) {
		hdhomerun_debug_printf(dbg, "hdhomerun_video_create: failed to start thread\n");
		goto error;
	}

	/* Success. */
	return vs;

error:
	if (vs->sock != HDHOMERUN_SOCK_INVALID) {
		hdhomerun_sock_destroy(vs->sock);
	}
	if (vs->buffer) {
		free(vs->buffer);
	}
	free(vs);
	return NULL;
}
Пример #12
0
static bool_t hdhomerun_device_selector_choose_test(struct hdhomerun_device_selector_t *hds, struct hdhomerun_device_t *test_hd)
{
	const char *name = hdhomerun_device_get_name(test_hd);

	/*
	 * Attempt to aquire lock.
	 */
	char *error;
	int ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
	if (ret > 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
		return TRUE;
	}
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}

	/*
	 * In use - check target.
	 */
	char *target;
	ret = hdhomerun_device_get_tuner_target(test_hd, &target);
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}
	if (ret == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to read target\n", name);
		return FALSE;
	}

	char *ptr = strstr(target, "//");
	if (ptr) {
		target = ptr + 2;
	}
	ptr = strchr(target, ' ');
	if (ptr) {
		*ptr = 0;
	}

	unsigned long a[4];
	unsigned long target_port;
	if (sscanf(target, "%lu.%lu.%lu.%lu:%lu", &a[0], &a[1], &a[2], &a[3], &target_port) != 5) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, no target set (%s)\n", name, target);
		return FALSE;
	}

	uint32_t target_ip = (uint32_t)((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
	uint32_t local_ip = hdhomerun_device_get_local_machine_addr(test_hd);
	if (target_ip != local_ip) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by %s\n", name, target);
		return FALSE;
	}

	/*
	 * Test local port.
	 */
	int test_sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
	if (test_sock == -1) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use, failed to create test sock\n", name);
		return FALSE;
	}

	struct sockaddr_in sock_addr;
	memset(&sock_addr, 0, sizeof(sock_addr));
	sock_addr.sin_family = AF_INET;
	sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	sock_addr.sin_port = htons((uint16_t)target_port);
	ret = bind(test_sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
	close(test_sock);

	if (ret != 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine\n", name);
		return FALSE;
	}

	/*
	 * Dead local target, force clear lock.
	 */
	ret = hdhomerun_device_tuner_lockkey_force(test_hd);
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}
	if (ret == 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, failed to force release lockkey\n", name);
		return FALSE;
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s in use by local machine, dead target, lockkey force successful\n", name);

	/*
	 * Attempt to aquire lock.
	 */
	ret = hdhomerun_device_tuner_lockkey_request(test_hd, &error);
	if (ret > 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s chosen\n", name);
		return TRUE;
	}
	if (ret < 0) {
		hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s communication error\n", name);
		return FALSE;
	}

	hdhomerun_debug_printf(hds->dbg, "hdhomerun_device_selector_choose_test: device %s still in use after lockkey force (%s)\n", name, error);
	return FALSE;
}