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
31 _timer_periodic = NULL;
\r
34 Streaming::~Streaming()
\r
37 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
39 _timer_periodic->invalidate();
\r
43 RELEASE(_timer_periodic);
\r
46 DebugLog2("%s", __FUNCTION__);
\r
49 Streaming *Streaming::alloc()
\r
51 return new Streaming();
\r
54 Streaming *Streaming::initWithController(Controller *controller)
\r
56 _controller = controller;
\r
57 _tuners = controller->_tuners;
\r
60 _ctrls = Dictionary::alloc()->initWithCapacity(0);
\r
68 _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, NULL, true);
\r
69 if (_timer_periodic == NULL)
\r
75 _timer_periodic->fire();
\r
80 void Streaming::systemWillSuspend()
\r
84 void Streaming::systemResumed()
\r
88 void Streaming::mapping(int tuner, int channel, int port)
\r
90 Dictionary *udp_to_tuner_channel = _ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
91 if (udp_to_tuner_channel == NULL)
\r
93 udp_to_tuner_channel = Dictionary::dictionaryWithCapacity(0);
\r
94 _ctrls->setObject(udp_to_tuner_channel, KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
97 Dictionary *tuner_channel_to_udp = _ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
98 if (tuner_channel_to_udp == NULL)
\r
100 tuner_channel_to_udp = Dictionary::dictionaryWithCapacity(0);
\r
101 _ctrls->setObject(tuner_channel_to_udp, KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
105 sprintf_s(port_str, "%d", port);
\r
106 char tuner_and_channel[10];
\r
107 sprintf_s(tuner_and_channel, "%d,%d", tuner, channel);
\r
109 udp_to_tuner_channel->setString(tuner_and_channel, port_str);
\r
110 tuner_channel_to_udp->setString(port_str, tuner_and_channel);
\r
113 void Streaming::timerExpired(Timer *timer, void *user_info)
\r
115 DebugLog2("%s", __FUNCTION__);
\r
121 // マッピング(UDPPort:tuner,ch)情報取得
\r
122 Dictionary *mapping = NULL;
\r
123 if ((_ctrls != NULL) && ((mapping = _ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL)) != NULL))
\r
128 // どれだけ使用中なのか不明なので、まずは必要サイズを調べる
\r
130 if (GetExtendedUdpTable(NULL, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
132 // ERROR_INSUFFICIENT_BUFFER の場合、必要なバッファサイズが size に格納される
\r
135 PMIB_UDPTABLE_OWNER_PID udptable = (PMIB_UDPTABLE_OWNER_PID)malloc(size);
\r
136 if (udptable != NULL)
\r
141 if (GetExtendedUdpTable(udptable, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == NO_ERROR)
\r
144 DebugLog3("udptable->dwNumEntries: %d", udptable->dwNumEntries);
\r
147 Dictionary *using_port = _ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
148 if (using_port != NULL)
\r
151 Array *using_ports = using_port->allKeys();
\r
152 if (using_ports != NULL)
\r
155 for (uint i = 0; i < using_ports->count(); ++i)
\r
158 bool stop_need = true;
\r
161 for (uint j = 0; j < udptable->dwNumEntries; ++j)
\r
163 if (((String *)using_ports->objectAtIndex(i))->intValue() == ntohs((WORD)udptable->table[j].dwLocalPort))
\r
175 String *tuner_and_channel = mapping->stringForKey((String *)using_ports->objectAtIndex(i));
\r
176 if (tuner_and_channel != NULL)
\r
179 Range r = tuner_and_channel->rangeOfString(",");
\r
180 if (r.location != NotFound)
\r
182 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
183 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
184 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
186 DebugLog0("auto streaming stop: %s", ((String *)using_ports->objectAtIndex(i))->cString());
\r
188 _tuners[tuner]->stopStreaming();
\r
189 using_port->removeObjectForKey((String *)using_ports->objectAtIndex(i));
\r
199 for (uint i = 0; i < udptable->dwNumEntries; ++i)
\r
203 sprintf_s(port, "%d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
204 DebugLog3("port = %s", port);
\r
207 String *tuner_and_channel = mapping->stringForKey(port);
\r
208 if (tuner_and_channel != NULL)
\r
210 // 取得OK: 監視対象ポートが使用されている
\r
213 bool auto_streaming = false;
\r
214 char exec_path[MAX_PATH];
\r
215 memset(exec_path, 0, sizeof(exec_path));
\r
218 size_t returnValue;
\r
219 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, udptable->table[i].dwOwningPid);
\r
220 if (hProcess != NULL)
\r
222 TCHAR exec[MAX_PATH];
\r
223 memset(exec, 0, sizeof(exec));
\r
224 DWORD len = sizeof(exec) - 1;
\r
227 if (QueryFullProcessImageName(hProcess, 0, exec, &len))
\r
230 if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) == 0)
\r
234 // とりあえず、、、現状は "ffmpeg.exe" / "vlc.exe" / "Kodi.exe" があったら auto_streaming を true にする
\r
235 if ((strstr(exec_path, "ffmpeg.exe") != NULL) ||
\r
236 (strstr(exec_path, "vlc.exe") != NULL) ||
\r
237 (strstr(exec_path, "Kodi.exe") != NULL))
\r
239 auto_streaming = true;
\r
245 CloseHandle(hProcess);
\r
248 if (auto_streaming)
\r
251 Range r = tuner_and_channel->rangeOfString(",");
\r
252 if (r.location != NotFound)
\r
254 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
255 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
256 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
258 RaymLock(_controller);
\r
260 // 非ストリーミング中 かつ 非レコーディング中 または チャンネルが同じ 場合
\r
261 if (!_tuners[tuner]->isStreaming() && (!_tuners[tuner]->isRecording() || _tuners[tuner]->channel() == channel))
\r
265 if (_tuners[tuner]->channel() != channel)
\r
267 _controller->setChannel(tuner, channel);
\r
270 SOCKADDR_IN dst_addr;
\r
271 dst_addr.sin_family = AF_INET;
\r
272 dst_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
\r
273 dst_addr.sin_port = (WORD)udptable->table[i].dwLocalPort;
\r
275 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
278 DebugLog0("auto streaming start: %d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
281 using_port = _ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
282 if (using_port == NULL)
\r
284 using_port = Dictionary::dictionaryWithCapacity(0);
\r
285 _ctrls->setObject(using_port, KEY_UDP_IN_USE);
\r
287 using_port->setBool(true, port);
\r
291 RaymUnlock(_controller);
\r
306 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
308 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
309 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
311 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
315 GetSystemTimeAsFileTime(&ft);
\r
318 __time64_t now_sec;
\r
319 __time64_t now_usec;
\r
320 now_sec = ft.dwHighDateTime;
\r
322 now_sec |= ft.dwLowDateTime;
\r
323 now_sec /= 10; /*convert into microseconds*/
\r
324 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
325 now_usec = (now_sec % 1000000UL);
\r
326 now_sec = now_sec / 1000000UL;
\r
328 TimeInterval interval = (TimeInterval)now_usec;
\r
329 interval = interval / 1000000;
\r
330 _timer_periodic->setTimeInterval(1.005 - interval);
\r