2 * @file Streaming.cpp
\r
7 #include <Iphlpapi.h>
\r
11 #include "Raym/Log.h"
\r
14 #include "ry0/iPTd/Streaming.h"
\r
15 #include "ry0/iPTd/Controller.h"
\r
17 using namespace Raym;
\r
24 Streaming::Streaming()
\r
26 DebugLog2("%s", __FUNCTION__);
\r
30 _timer_periodic = NULL;
\r
33 Streaming::~Streaming()
\r
36 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
38 _timer_periodic->invalidate();
\r
42 RELEASE(_timer_periodic);
\r
45 DebugLog2("%s", __FUNCTION__);
\r
48 Streaming *Streaming::alloc()
\r
50 return new Streaming();
\r
53 Streaming *Streaming::initWithController(Controller *controller)
\r
55 _controller = controller;
\r
58 _ctrls = Dictionary::alloc()->initWithCapacity(0);
\r
61 _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, NULL, true);
\r
62 _timer_periodic->fire();
\r
67 void Streaming::mapping(int tuner, int channel, int port)
\r
69 Dictionary *udp_to_tuner_channel = _ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
70 if (udp_to_tuner_channel == NULL)
\r
72 udp_to_tuner_channel = Dictionary::dictionaryWithCapacity(0);
\r
73 _ctrls->setObject(udp_to_tuner_channel, KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
76 Dictionary *tuner_channel_to_udp = _ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
77 if (tuner_channel_to_udp == NULL)
\r
79 tuner_channel_to_udp = Dictionary::dictionaryWithCapacity(0);
\r
80 _ctrls->setObject(tuner_channel_to_udp, KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
84 sprintf_s(port_str, "%d", port);
\r
85 char tuner_and_channel[10];
\r
86 sprintf_s(tuner_and_channel, "%d,%d", tuner, channel);
\r
88 udp_to_tuner_channel->setString(tuner_and_channel, port_str);
\r
89 tuner_channel_to_udp->setString(port_str, tuner_and_channel);
\r
92 void Streaming::timerExpired(Timer *timer, void *userInfo)
\r
94 DebugLog2("%s", __FUNCTION__);
\r
100 // マッピング(UDPPort:tuner,ch)情報取得
\r
101 Dictionary *mapping = NULL;
\r
102 if ((_ctrls != NULL) && ((mapping = _ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL)) != NULL))
\r
107 // どれだけ使用中なのか不明なので、まずは必要サイズを調べる
\r
109 if (GetExtendedUdpTable(NULL, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
111 // ERROR_INSUFFICIENT_BUFFER の場合、必要なバッファサイズが size に格納される
\r
114 PMIB_UDPTABLE_OWNER_PID udptable = (PMIB_UDPTABLE_OWNER_PID)malloc(size);
\r
115 if (udptable != NULL)
\r
120 if (GetExtendedUdpTable(udptable, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == NO_ERROR)
\r
123 DebugLog3("udptable->dwNumEntries: %d", udptable->dwNumEntries);
\r
126 Dictionary *using_port = _ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
127 if (using_port != NULL)
\r
130 Array *using_ports = using_port->allKeys();
\r
131 if (using_ports != NULL)
\r
134 for (uint i = 0; i < using_ports->count(); ++i)
\r
137 bool stop_need = true;
\r
140 for (uint j = 0; j < udptable->dwNumEntries; ++j)
\r
142 if (((String *)using_ports->objectAtIndex(i))->intValue() == ntohs((WORD)udptable->table[j].dwLocalPort))
\r
154 String *tuner_and_channel = mapping->stringForKey((String *)using_ports->objectAtIndex(i));
\r
155 if (tuner_and_channel != NULL)
\r
158 Range r = tuner_and_channel->rangeOfString(",");
\r
159 if (r.location != NotFound)
\r
161 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
162 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
163 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
165 DebugLog0("auto streaming stop: %s", ((String *)using_ports->objectAtIndex(i))->cString());
\r
167 _controller->_tuners[tuner]->stopStreaming();
\r
168 using_port->removeObjectForKey((String *)using_ports->objectAtIndex(i));
\r
178 for (uint i = 0; i < udptable->dwNumEntries; ++i)
\r
182 sprintf_s(port, "%d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
183 DebugLog3("port = %s", port);
\r
186 String *tuner_and_channel = mapping->stringForKey(port);
\r
187 if (tuner_and_channel != NULL)
\r
189 // 取得OK: 監視対象ポートが使用されている
\r
192 bool auto_streaming = false;
\r
193 char exec_path[MAX_PATH];
\r
194 memset(exec_path, 0, sizeof(exec_path));
\r
197 size_t returnValue;
\r
198 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, udptable->table[i].dwOwningPid);
\r
199 if (hProcess != NULL)
\r
201 TCHAR exec[MAX_PATH];
\r
202 memset(exec, 0, sizeof(exec));
\r
203 DWORD len = sizeof(exec) - 1;
\r
206 if (QueryFullProcessImageName(hProcess, 0, exec, &len))
\r
209 if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) == 0)
\r
213 // とりあえず、、、現状は "ffmpeg.exe" / "vlc.exe" / "Kodi.exe" があったら auto_streaming を true にする
\r
214 if ((strstr(exec_path, "ffmpeg.exe") != NULL) ||
\r
215 (strstr(exec_path, "vlc.exe") != NULL) ||
\r
216 (strstr(exec_path, "Kodi.exe") != NULL))
\r
218 auto_streaming = true;
\r
224 CloseHandle(hProcess);
\r
227 if (auto_streaming)
\r
230 Range r = tuner_and_channel->rangeOfString(",");
\r
231 if (r.location != NotFound)
\r
233 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
234 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
235 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
238 EnterCriticalSection(&_cs);
\r
240 // 非ストリーミング中 かつ 非レコーディング中 または チャンネルが同じ 場合
\r
241 if (!_controller->_tuners[tuner]->isStreaming() && (!_controller->_tuners[tuner]->isRecording() || _controller->_tuners[tuner]->channel() == channel))
\r
245 if (_controller->_tuners[tuner]->channel() != channel)
\r
247 _controller->setChannel(tuner, channel);
\r
250 SOCKADDR_IN dst_addr;
\r
251 dst_addr.sin_family = AF_INET;
\r
252 dst_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
\r
253 dst_addr.sin_port = (WORD)udptable->table[i].dwLocalPort;
\r
255 if (_controller->_tuners[tuner]->startStreaming(&dst_addr))
\r
258 DebugLog0("auto streaming start: %d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
261 using_port = _ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
262 if (using_port == NULL)
\r
264 using_port = Dictionary::dictionaryWithCapacity(0);
\r
265 _ctrls->setObject(using_port, KEY_UDP_IN_USE);
\r
267 using_port->setBool(true, port);
\r
272 LeaveCriticalSection(&_cs);
\r
287 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
289 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
290 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
292 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
296 GetSystemTimeAsFileTime(&ft);
\r
299 __time64_t now_sec;
\r
300 __time64_t now_usec;
\r
301 now_sec = ft.dwHighDateTime;
\r
303 now_sec |= ft.dwLowDateTime;
\r
304 now_sec /= 10; /*convert into microseconds*/
\r
305 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
306 now_usec = (now_sec % 1000000UL);
\r
307 now_sec = now_sec / 1000000UL;
\r
309 TimeInterval interval = (TimeInterval)now_usec;
\r
310 interval = interval / 1000000;
\r
311 _timer_periodic->setTimeInterval(1.005 - interval);
\r