static const TimeInterval DEF_COLLECT_EPG_DELAY = 1.0;\r
static const TimeInterval DEF_COLLECT_EPG_RETRY = 60.0;\r
\r
-static const time_t DEF_COLLECT_EPG_LIMIT_S = 30;\r
-static const time_t DEF_COLLECT_EPG_LIMIT_T = 75;\r
+static const time_t DEF_COLLECT_EPG_LIMIT_S = 10;\r
+static const time_t DEF_COLLECT_EPG_LIMIT_T = 20;\r
\r
static const time_t OFFSET_OF_START_TIME = -2; // 録画開始時刻の補正(秒単位)\r
static const time_t OFFSET_OF_END_TIME = -3; // 録画停止時刻の補正(秒単位)\r
{\r
DebugLog2("Controller::removePastEPGs()");\r
\r
- // 現在時刻\r
time_t now = time(NULL);\r
\r
- // lock\r
RaymLock(_epgs);\r
\r
- Array *epg_list = Array::arrayWithCapacity(0);\r
+ Dictionary *temp_data = _epgs->dictionaryForKey(KEY_TEMP_DATA);\r
+ if (temp_data != NULL)\r
+ {\r
+ temp_data->retain();\r
+ _epgs->removeObjectForKey(KEY_TEMP_DATA);\r
+ }\r
+ else\r
+ {\r
+ temp_data = Dictionary::alloc()->initWithCapacity(0);\r
+ }\r
\r
- // サービスIDでループ\r
- Array *keys1 = _epgs->allKeys();\r
- for (uint i = 0; i < keys1->count(); ++i)\r
+ Dictionary *services = _epgs->dictionaryForKey(KEY_SERVICES);\r
+ if (services != NULL)\r
{\r
- // イベント取得\r
- Dictionary *events = _epgs->dictionaryForKey((String *)keys1->objectAtIndex(i));\r
- if (events != NULL)\r
+ Array *keys = services->allKeys();\r
+ for (uint i = 0; i < keys->count(); ++i)\r
{\r
- // イベントでループ\r
- Array *keys2 = events->allKeys();\r
- for (uint j = 0; j < keys2->count(); ++j)\r
+ String *key = (String *)keys->objectAtIndex(i);\r
+\r
+ std::string xmltv_programs;\r
+ Dictionary *temp_service = temp_data->dictionaryForKey(key);\r
+ if (temp_service == NULL)\r
+ {\r
+ temp_service = Dictionary::dictionaryWithCapacity(0);\r
+ temp_data->setObject(temp_service, key);\r
+ }\r
+\r
+ Array *old_epgs = services->arrayForKey(key);\r
+ Array *new_epgs = Array::arrayWithCapacity(0);\r
+ for (uint j = 0; j < old_epgs->count(); ++j)\r
{\r
- // キーとEPG取得\r
- String *key = (String *)keys2->objectAtIndex(j);\r
- Dictionary *epg = events->dictionaryForKey(key);\r
- if (epg != NULL)\r
+ Dictionary *epg = (Dictionary *)old_epgs->objectAtIndex(j);\r
+ time_t start = 0;\r
+ time_t end = 0;\r
+ getTimeWithEPG(epg, &start, &end);\r
+ if (now <= end)\r
{\r
- // EPG取得できた場合\r
- time_t start = 0;\r
- time_t end = 0;\r
- getTimeWithEPG(epg, &start, &end);\r
+ new_epgs->addObject(epg);\r
\r
- // 終了時刻が過ぎていたら\r
- if (now > end)\r
+ Array *ch_list = temp_service->arrayForKey(KEY_CHANNELS);\r
+ if (ch_list != NULL)\r
{\r
- // 削除する\r
- events->removeObjectForKey(key);\r
- }\r
- else\r
- {\r
- epg_list->addObject(epg);\r
+ std::string epg_date = epg->stringForKey(KEY_EPG_DATE)->stringByReplacingOccurrencesOfString("/", "")->cString();\r
+ std::string epg_start = epg->stringForKey(KEY_EPG_START)->stringByReplacingOccurrencesOfString(":", "")->cString();\r
+ std::string epg_end = epg->stringForKey(KEY_EPG_END)->stringByReplacingOccurrencesOfString(":", "")->cString();\r
+ std::string epg_event_id = epg->stringForKey(KEY_EPG_EVENT_ID)->cString();\r
+ std::string epg_duration = epg->stringForKey(KEY_EPG_DURATION)->cString();\r
+ std::string epg_title = epg->stringForKey(KEY_EPG_TITLE)->cString();\r
+\r
+ for (uint ch_idx = 0; ch_idx < ch_list->count(); ++ch_idx)\r
+ {\r
+ xmltv_programs += " <programme start=\"" + epg_date + epg_start + " +0900\" stop=\"";\r
+ xmltv_programs += epg_date + epg_end + " +0900\" channel=\"";\r
+ xmltv_programs += ((String *)ch_list->objectAtIndex(ch_idx))->cString();\r
+ xmltv_programs += "\" event_id=\"" + epg_event_id + "\" duration=\"" + epg_duration + "\">\r\n";\r
+\r
+ xmltv_programs += " <title lang=\"ja_JP\">" + epg_title + "</title>\r\n";\r
+\r
+ xmltv_programs += " </programme>\r\n";\r
+ }\r
}\r
}\r
}\r
- }\r
- }\r
-\r
- epg_list = epg_list->sortedArrayUsingFunction(compareFunction, this);\r
- std::string xmltv_programs;\r
- for (uint i = 0; i < epg_list->count(); ++i)\r
- {\r
- Dictionary *epg = (Dictionary *)epg_list->objectAtIndex(i);\r
+ services->setObject(new_epgs, key);\r
\r
- std::string epg_date = epg->stringForKey(KEY_EPG_DATE)->stringByReplacingOccurrencesOfString("/", "")->cString();\r
- std::string epg_start = epg->stringForKey(KEY_EPG_START)->stringByReplacingOccurrencesOfString(":", "")->cString();\r
- std::string epg_end = epg->stringForKey(KEY_EPG_END)->stringByReplacingOccurrencesOfString(":", "")->cString();\r
- std::string epg_event_id = epg->stringForKey(KEY_EPG_EVENT_ID)->cString();\r
- std::string epg_duration = epg->stringForKey(KEY_EPG_DURATION)->cString();\r
- std::string epg_title = epg->stringForKey(KEY_EPG_TITLE)->cString();\r
-\r
- Array *ch_list = _service_to_channels->arrayForKey(epg->stringForKey(KEY_EPG_SERVICE_ID));\r
- for (uint ch_idx = 0; (ch_list != NULL) && (ch_idx < ch_list->count()); ++ch_idx)\r
- {\r
- xmltv_programs += " <programme start=\"" + epg_date + epg_start + " +0900\" stop=\"";\r
- xmltv_programs += epg_date + epg_end + " +0900\" channel=\"";\r
- xmltv_programs += ((String *)ch_list->objectAtIndex(ch_idx))->cString();\r
- xmltv_programs += "\" event_id=\"" + epg_event_id + "\" duration=\"" + epg_duration + "\">\r\n";\r
-\r
- xmltv_programs += " <title lang=\"ja_JP\">" + epg_title + "</title>\r\n";\r
-\r
- xmltv_programs += " </programme>\r\n";\r
+ if (xmltv_programs.length() > 0)\r
+ {\r
+ temp_service->setObject(String::stringWithUTF8String(xmltv_programs.c_str()), KEY_PROGRAMS);\r
+ }\r
}\r
}\r
\r
- // unlock\r
- RaymUnlock(_epgs);\r
+ _epgs->writeToFile(_epgs_path, true);\r
\r
- std::string str_xmltv_xml;\r
- str_xmltv_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";\r
- str_xmltv_xml += "<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\r\n";\r
- str_xmltv_xml += "<tv generator-info-name=\"iPTd_R2\" generator-info-url=\"http://localhost/\">\r\n";\r
- str_xmltv_xml += _xmltv_channels;\r
- str_xmltv_xml += xmltv_programs;\r
- str_xmltv_xml += "</tv>\r\n";\r
+ _epgs->setObject(temp_data, KEY_TEMP_DATA);\r
+ temp_data->release();\r
\r
- RaymLock(this);\r
- RELEASE(_xmltv_xml);\r
- _xmltv_xml = String::alloc()->initWithUTF8String(str_xmltv_xml.c_str());\r
- RaymUnlock(this);\r
+ RaymUnlock(_epgs);\r
}\r
\r
void Controller::collectEPGsForTuner(int tuner, time_t limit)\r
return;\r
}\r
\r
-\r
Analyzer *an = Analyzer::alloc()->init();\r
+\r
+ RaymLock(this);\r
_tuners[tuner]->setListener(an);\r
+ RaymUnlock(this);\r
\r
Array *collected = an->collectEPGs(limit);\r
\r
+ RaymLock(this);\r
_tuners[tuner]->setListener(NULL);\r
+ RaymUnlock(this);\r
+\r
an->release();\r
\r
- // lock\r
RaymLock(_epgs);\r
\r
for (uint j = 0; j < collected->count(); ++j)\r
{\r
- Dictionary *epg1 = (Dictionary *)collected->objectAtIndex(j);\r
+ Dictionary *epg = (Dictionary *)collected->objectAtIndex(j);\r
\r
- if (epg1->stringForKey(KEY_EPG_TITLE) == NULL)\r
+ if (epg->stringForKey(KEY_EPG_TITLE) == NULL)\r
{\r
// タイトルが無い場合は不要\r
continue;\r
}\r
\r
// Service ID を Primary Key\r
- String *key = epg1->stringForKey(KEY_EPG_SERVICE_ID);\r
+ String *key = epg->stringForKey(KEY_EPG_SERVICE_ID);\r
if (key != NULL)\r
{\r
- Dictionary *epgs_of_service = _epgs->dictionaryForKey(key);\r
- if (epgs_of_service == NULL)\r
+ Dictionary *services = _epgs->dictionaryForKey(KEY_SERVICES);\r
+ if (services == NULL)\r
{\r
- // 無い場合は作成\r
- epgs_of_service = Dictionary::dictionaryWithCapacity(0);\r
- _epgs->setObject(epgs_of_service, key);\r
+ services = Dictionary::dictionaryWithCapacity(0);\r
+ _epgs->setObject(services, KEY_SERVICES);\r
+ }\r
+ Array *epgs = services->arrayForKey(key);\r
+ if (epgs == NULL)\r
+ {\r
+ epgs = Array::arrayWithCapacity(0);\r
+ services->setObject(epgs, key);\r
+ }\r
+ bool inserted = false;\r
+ for (uint idx = 0; idx < epgs->count(); ++idx)\r
+ {\r
+ Dictionary *epg2 = (Dictionary *)epgs->objectAtIndex(idx);\r
+ if (epg->stringForKey(KEY_EPG_EVENT_ID)->isEqualToString(epg2->stringForKey(KEY_EPG_EVENT_ID)))\r
+ {\r
+ inserted = true;\r
+ break;\r
+ }\r
+ if (compareFunction(epg, epgs->objectAtIndex(idx), NULL) == OrderedAscending)\r
+ {\r
+ epgs->insertObject(epg, idx);\r
+ inserted = true;\r
+ break;\r
+ }\r
}\r
- // Event ID を Secondary Key\r
- key = epg1->stringForKey(KEY_EPG_EVENT_ID);\r
- if (key != NULL)\r
+ if (!inserted)\r
{\r
- epgs_of_service->setObject(epg1, key);\r
+ epgs->addObject(epg);\r
}\r
}\r
}\r
\r
- // ファイルへ書き出し\r
- _epgs->writeToFile(_epgs_path, true);\r
-\r
- // unlock\r
RaymUnlock(_epgs);\r
\r
+ removePastEPGs();\r
+\r
DebugLog2("Controller::collectEPGsForTuner(%d) end.", tuner);\r
}\r
\r
bool Controller::collectEPGs(Tuner::Type type)\r
{\r
- DebugLog0("Controller::collectEPGs(%s) start.", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
-\r
// 使用するチューナを決定\r
int tuner = 0;\r
bool locked = false;\r
// ロック確認\r
if (!locked)\r
{\r
- DebugLog0("Controller::collectEPGs(%s) end(Can't locled).", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
+ DebugLog3("Controller::collectEPGs(%s) end(Can't locled).", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
// ロックできない場合は収集しない\r
return false;\r
}\r
\r
bool canceled = false;\r
- DebugLog0("start collect EPG of \"%s(#%d)\".", _tuners[tuner]->name(), tuner);\r
+ DebugLog0("Collect EPG of \"%s(#%d)\" is started.", _tuners[tuner]->name(), tuner);\r
\r
// 現在のチャンネルを保存\r
int channel = _tuners[tuner]->channel();\r
// チャンネル設定\r
if (_tuners[tuner]->setChannel(ch))\r
{\r
- DebugLog0(" %s: channel: %d", _tuners[tuner]->name(), ch);\r
+ time_t limit = (time_t)_epgs->integerForKey(stationName(type, ch));\r
+ if (limit == 0)\r
+ {\r
+ limit = ((type == Tuner::ISDB_S) ? DEF_COLLECT_EPG_LIMIT_S : DEF_COLLECT_EPG_LIMIT_T);\r
+ _epgs->setInteger((int)limit, stationName(type, ch));\r
+ }\r
\r
- // EPG取集\r
- collectEPGsForTuner(tuner, ((type == Tuner::ISDB_S) ? DEF_COLLECT_EPG_LIMIT_S : DEF_COLLECT_EPG_LIMIT_T));\r
+ collectEPGsForTuner(tuner, limit);\r
\r
- // キャンセル確認\r
RaymLock(this);\r
if (_cancel_epg_collect)\r
{\r
// unlock\r
RaymUnlock(this);\r
\r
- if (canceled)\r
- {\r
- DebugLog0("collect EPG of \"%s\" was canceled.", _tuners[tuner]->name());\r
- }\r
- else\r
- {\r
- DebugLog0("collect EPG of \"%s\" was finished.", _tuners[tuner]->name());\r
-\r
- }\r
-\r
- // 過去のEPGを削除\r
- removePastEPGs();\r
-\r
- DebugLog2("Controller::collectEPGs(%s) end.", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
+ DebugLog0("Collect EPG of \"%s(#%d)\" was %s.", _tuners[tuner]->name(), tuner, canceled ? "canceled" : "finished");\r
\r
return true;\r
}\r
\r
tunerInfo->setInteger(lastChannel, KEY_CHANNEL);\r
\r
- _status->writeToFile(_status_path, false);\r
+ _status->writeToFile(_status_path, true);\r
}\r
\r
// 設定ファイルを更新\r
{\r
tunerInfo->setInteger(channel, KEY_CHANNEL);\r
\r
- _status->writeToFile(_status_path, false);\r
+ _status->writeToFile(_status_path, true);\r
\r
result = true;\r
}\r
\r
// マッピング(UDPPort:tuner,ch)情報取得\r
Dictionary *mapping = NULL;\r
- if ((_streaming_ctrls != NULL) && ((mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL)) != NULL))\r
+ if ((_streaming_ctrls != NULL) && ((mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID)) != NULL))\r
{\r
// マッピング情報取得OK\r
\r
if (stop_need)\r
{\r
// マッピング情報を取得\r
- String *tuner_and_channel = mapping->stringForKey((String *)using_ports->objectAtIndex(i));\r
- if (tuner_and_channel != NULL)\r
+ String *tuner_and_service_id = mapping->stringForKey((String *)using_ports->objectAtIndex(i));\r
+ if (tuner_and_service_id != NULL)\r
{\r
- // ã\83\81ã\83¥ã\83¼ã\83\8aã\81¨ã\83\81ã\83£ã\83³ã\83\8dã\83«に分割\r
- Range r = tuner_and_channel->rangeOfString(",");\r
+ // ã\83\81ã\83¥ã\83¼ã\83\8aã\81¨ã\82µã\83¼ã\83\93ã\82¹IDに分割\r
+ Range r = tuner_and_service_id->rangeOfString("_");\r
if (r.location != NotFound)\r
{\r
- int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();\r
- int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();\r
- DebugLog3("tuner: %d, channel: %d", tuner, channel);\r
+ int tuner = tuner_and_service_id->substringToIndex(r.location)->intValue();\r
+ int service_id = tuner_and_service_id->substringFromIndex(r.location + 1)->intValue();\r
+ DebugLog3("tuner: %d, service_id: %d", tuner, service_id);\r
\r
DebugLog0("auto streaming stop: %s", ((String *)using_ports->objectAtIndex(i))->cString());\r
\r
DebugLog3("port = %s", port);\r
\r
// マッピング情報を取得\r
- String *tuner_and_channel = mapping->stringForKey(port);\r
- if (tuner_and_channel != NULL)\r
+ String *tuner_and_service_id = mapping->stringForKey(port);\r
+ if (tuner_and_service_id != NULL)\r
{\r
// 取得OK: 監視対象ポートが使用されている\r
\r
\r
if (auto_streaming)\r
{\r
- // ã\83\81ã\83¥ã\83¼ã\83\8aã\81¨ã\83\81ã\83£ã\83³ã\83\8dã\83«に分割\r
- Range r = tuner_and_channel->rangeOfString(",");\r
+ // ã\83\81ã\83¥ã\83¼ã\83\8aã\81¨ã\82µã\83¼ã\83\93ã\82¹IDに分割\r
+ Range r = tuner_and_service_id->rangeOfString("_");\r
if (r.location != NotFound)\r
{\r
- int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();\r
- int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();\r
- DebugLog3("tuner: %d, channel: %d", tuner, channel);\r
+ int tuner = tuner_and_service_id->substringToIndex(r.location)->intValue();\r
+ int service_id = tuner_and_service_id->substringFromIndex(r.location + 1)->intValue();\r
+ DebugLog3("tuner: %d, service_id: %d", tuner, service_id);\r
+\r
+ // 暫定\r
+ int channel = -1;\r
+ if (_streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL) != NULL)\r
+ {\r
+ channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL)->integerForKey(tuner_and_service_id);\r
+ }\r
\r
// lock\r
RaymLock(this);\r
String *path = _httpd->rootPath();\r
if (path == NULL)\r
{\r
- DebugLog3("_httpd->rootPath() ng.");\r
+ DebugLog0("_httpd->rootPath() ng.");\r
break;\r
}\r
\r
path = path->stringByAppendingPathComponent("template2.html");\r
if (path == NULL)\r
{\r
- DebugLog3("path->stringByAppendingPathComponent() ng.");\r
+ DebugLog0("path->stringByAppendingPathComponent() ng.");\r
break;\r
}\r
\r
String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);\r
if (html == NULL)\r
{\r
- DebugLog3("String::stringWithContentsOfFile() ng.");\r
+ DebugLog0("String::stringWithContentsOfFile() ng.");\r
break;\r
}\r
\r
html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Programs, NULL));\r
if (html == NULL)\r
{\r
- DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");\r
+ DebugLog0("html->stringByReplacingOccurrencesOfString() ng.");\r
break;\r
}\r
\r
{\r
HTTPResponse *result = NULL;\r
\r
- if (_iptv_m3u8 != NULL)\r
+ char hostname[NI_MAXHOST];\r
+ if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)\r
{\r
- result = responseWithUTF8Text(request, _iptv_m3u8);\r
+ if (_props->stringForKey(KEY_HTTP_HOST)->isEqualToString(hostname) || strcmp("127.0.0.1", hostname) == 0)\r
+ {\r
+ if (_iptv_m3u8_local != NULL)\r
+ {\r
+ result = responseWithUTF8Text(request, _iptv_m3u8_local);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (_iptv_m3u8_remote != NULL)\r
+ {\r
+ result = responseWithUTF8Text(request, _iptv_m3u8_remote);\r
+ }\r
+ }\r
}\r
\r
return result;\r
{\r
HTTPResponse *result = NULL;\r
\r
- if (_xmltv_xml != NULL)\r
+ std::string str_xmltv_xml;\r
+ str_xmltv_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";\r
+ str_xmltv_xml += "<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\r\n";\r
+ str_xmltv_xml += "<tv generator-info-name=\"iPTd_R2\" generator-info-url=\"http://localhost/\">\r\n";\r
+ str_xmltv_xml += _xmltv_channels;\r
+\r
+ Dictionary *temp_data = _epgs->dictionaryForKey(KEY_TEMP_DATA);\r
+ if (temp_data != NULL)\r
{\r
- result = responseWithUTF8Text(request, _xmltv_xml);\r
+ Array *keys = temp_data->allKeys();\r
+ for (uint i = 0; i < keys->count(); ++i)\r
+ {\r
+ Dictionary *temp_service = temp_data->dictionaryForKey((String *)keys->objectAtIndex(i));\r
+ if (temp_service != NULL)\r
+ {\r
+ String *xmltv_programs = temp_service->stringForKey(KEY_PROGRAMS);\r
+ if (xmltv_programs != NULL)\r
+ {\r
+ str_xmltv_xml += xmltv_programs->cString();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ str_xmltv_xml += "</tv>\r\n";\r
+\r
+ String *tmp = String::stringWithUTF8String(str_xmltv_xml.c_str());\r
+ if (tmp != NULL)\r
+ {\r
+ result = responseWithUTF8Text(request, tmp);\r
}\r
\r
return result;\r
/**\r
* @brief HTTP Live Streaming制御\r
*\r
- * http://hogehoge/チューナ番号/チャンネル番号/streaming[-プリセット名].m3u8 がリクエスト(プリセットはオプション)され、\r
- * ã\83\81ã\83¥ã\83¼ã\83\8aç\95ªå\8f·ï¼\8fã\83\81ã\83£ã\83³ã\83\8dã\83«ç\95ªå\8f·/プリセット名(ある場合)が有効値の場合にコールされる\r
+ * http://hogehoge/チューナ番号_サービスID/streaming[-プリセット名].m3u8 がリクエスト(プリセットはオプション)され、\r
+ * ã\83\81ã\83¥ã\83¼ã\83\8aç\95ªå\8f·ï¼\8fã\82µã\83¼ã\83\93ã\82¹ID/プリセット名(ある場合)が有効値の場合にコールされる\r
*\r
* @param [in] request HTTPリクエスト\r
* @param [in] client リクエストしたクライアントのアドレス\r
* @param [in] tuner チューナ番号\r
- * @param [in] channel チャンネル番号\r
+ * @param [in] service_id チャンネル番号\r
* @param [in] preset プリセット(URLで省略された場合 "default" )\r
*/\r
-HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner, int channel, String *preset)\r
+HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner, int service_id, String *preset)\r
{\r
DebugLog2("Controller::responseForHLSControl()");\r
\r
hls_info_tuner->setObject(hls, KEY_HLS_INSTANCE);\r
}\r
\r
+ char tuner_and_service_id[10];\r
+ sprintf_s(tuner_and_service_id, "%03d_%d", tuner, service_id);\r
+\r
// 異チャンネルへのリクエスト、または、プリセット変更の場合\r
- if (((hls_info_tuner->integerForKey(KEY_CHANNEL) != 0) && (hls_info_tuner->integerForKey(KEY_CHANNEL) != channel)) ||\r
+ if (((hls_info_tuner->stringForKey(KEY_CHANNEL) != NULL) && !hls_info_tuner->stringForKey(KEY_CHANNEL)->isEqualToString(tuner_and_service_id)) ||\r
((hls_info_tuner->stringForKey(KEY_PRESET) != NULL) && !hls_info_tuner->stringForKey(KEY_PRESET)->isEqualToString(preset)))\r
{\r
// 停止\r
}\r
\r
// 初回リクエスト or チャンネル/プリセット変更 か?\r
- if ((hls_info_tuner->integerForKey(KEY_CHANNEL) == 0) && (hls_info_tuner->stringForKey(KEY_PRESET) == NULL))\r
+ if ((hls_info_tuner->stringForKey(KEY_CHANNEL) == NULL) && (hls_info_tuner->stringForKey(KEY_PRESET) == NULL))\r
{\r
// UDPポートを検索\r
- Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);\r
+ Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID);\r
if (mapping != NULL)\r
{\r
Array *ports = mapping->allKeys();\r
if (ports != NULL)\r
{\r
- char tuner_and_channel[10];\r
- sprintf_s(tuner_and_channel, "%d,%d", tuner, channel);\r
-\r
for (uint i = 0; i < ports->count(); ++i)\r
{\r
String *port = (String *)ports->objectAtIndex(i);\r
String *tmp = mapping->stringForKey(port);\r
- if (tmp->isEqualToString(tuner_and_channel))\r
+ if (tmp->isEqualToString(tuner_and_service_id))\r
{\r
- DebugLog0("udp mapping %d -> %d,%d", port->intValue(), tuner, channel);\r
+ DebugLog0("udp mapping %d -> %s", port->intValue(), tuner_and_service_id);\r
\r
// ソースを設定\r
hls->setSource(String::stringWithFormat("udp://@0.0.0.0:%d", port->intValue()));\r
hls->setOutputPath(outpath);\r
\r
// インデックス名\r
- hls->setIndexName(String::stringWithFormat("live_%03d_%03d", tuner, channel));\r
+ hls->setIndexName(String::stringWithFormat("live_%s", tuner_and_service_id));\r
\r
// 開始\r
if (hls->start())\r
DebugLog0("hls->start() success");\r
\r
// チャンネルを保存\r
- hls_info_tuner->setInteger(channel, KEY_CHANNEL);\r
+ hls_info_tuner->setString(tuner_and_service_id, KEY_CHANNEL);\r
\r
// プリセットを保存\r
hls_info_tuner->setString(preset, KEY_PRESET);\r
//\r
// HLS制御\r
//\r
- else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming(-[^\\.]+)?.m3u8$") && (cgi == NULL))\r
+ else if (uri->isMatch("^/[0-9]{3}/[0-9]+/streaming(-[^\\.]+)?.m3u8$") && (cgi == NULL))\r
{\r
- // URIã\81\8bã\82\89ã\83\81ã\83£ã\83³ã\83\8dã\83«ç\95ªå\8f·を抽出\r
- // Range実装したい...\r
- int ch = uri->substringFromIndex(5)->substringToIndex(3)->intValue();\r
+ // URIã\81\8bã\82\89ã\82µã\83¼ã\83\93ã\82¹IDを抽出\r
+ Range r = uri->rangeOfString("/streaming");\r
+ int service_id = uri->substringToIndex(r.location)->substringFromIndex(5)->intValue();\r
\r
// presetが指定されている場合、presetを抽出\r
String *preset = NULL;\r
if (uri->isMatch("streaming-"))\r
{\r
- preset = uri->substringFromIndex(19);\r
+ preset = uri->substringFromIndex(r.location + 11);\r
preset = preset->substringToIndex(preset->length() - 5);\r
}\r
else\r
}\r
\r
// チャンネル/presetが有効か確認\r
- if (isChannelEnabled(tuner, ch) &&\r
+ Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);\r
+ if ((mapping != NULL) && (mapping->stringForKey(String::stringWithFormat("%03d_%d", tuner, service_id)) != NULL) &&\r
(_props->dictionaryForKey(KEY_PRESETS) != NULL) &&\r
(_props->dictionaryForKey(KEY_PRESETS)->objectForKey(preset) != NULL))\r
{\r
// \r
- result = responseForHLSControl(request, client, tuner, ch, preset);\r
+ result = responseForHLSControl(request, client, tuner, service_id, preset);\r
}\r
else\r
{\r
result = responseForFailed(request);\r
}\r
}\r
- else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming-[0-9]+.ts$") && (cgi == NULL))\r
+ else if (uri->isMatch("^/[0-9]{3}/[0-9]+/streaming-[0-9]+.ts$") && (cgi == NULL))\r
{\r
- // URIã\81\8bã\82\89ã\83\81ã\83£ã\83³ã\83\8dã\83«ç\95ªå\8f·を抽出\r
- // Range実装したい...\r
- int ch = uri->substringFromIndex(5)->substringToIndex(3)->intValue();\r
+ // URIã\81\8bã\82\89ã\82µã\83¼ã\83\93ã\82¹IDを抽出\r
+ Range r = uri->rangeOfString("/streaming");\r
+ int service_id = uri->substringToIndex(r.location)->substringFromIndex(5)->intValue();\r
\r
// client からホスト名を取得\r
char hostname[NI_MAXHOST];\r
if (hls_info_tuner != NULL)\r
{\r
if (hls_info_tuner->stringForKey(KEY_HOSTNAME)->isEqualToString(hostname) &&\r
- (hls_info_tuner->integerForKey(KEY_CHANNEL) == ch))\r
+ hls_info_tuner->stringForKey(KEY_CHANNEL)->isEqualToString(String::stringWithFormat("%03d_%d", tuner, service_id)))\r
{\r
String *path = ((HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE))->outputPath();\r
if (path != NULL)\r
{\r
- result = _httpd->responseWithPath(path->stringByAppendingPathComponent(uri->substringFromIndex(9)), request);\r
+ result = _httpd->responseWithPath(path->stringByAppendingPathComponent(uri->substringFromIndex(r.location + 1)), request);\r
}\r
}\r
}\r
Array *result = Array::arrayWithCapacity(0);\r
\r
// lock\r
- RaymLock(this);\r
+ RaymLock(_epgs);\r
\r
for (uint i = 0; i < services->count(); ++i)\r
{\r
Dictionary *service = (Dictionary *)services->objectAtIndex(i);\r
- Dictionary *events = _epgs->dictionaryForKey(service->stringForKey(KEY_SERVICE_ID));\r
- if (events != NULL)\r
+ Dictionary *services = _epgs->dictionaryForKey(KEY_SERVICES);\r
+ Array *epgs = services->arrayForKey(service->stringForKey(KEY_SERVICE_ID));\r
+ if (epgs != NULL)\r
{\r
- Array *keys = events->allKeys();\r
- for (uint j = 0; j < keys->count(); ++j)\r
- {\r
- result->addObject(events->objectForKey((String *)keys->objectAtIndex(j)));\r
- }\r
+ result->addObjectsFromArray(epgs);\r
}\r
}\r
\r
// sort\r
result = result->sortedArrayUsingFunction(compareFunction, this);\r
\r
-\r
// unlock\r
- RaymUnlock(this);\r
+ RaymUnlock(_epgs);\r
\r
return result;\r
}\r
}\r
}\r
\r
- // UDPポートマッピング\r
- DebugLog0(" UDP Port Mapping :");\r
- DebugLog0(" tuner, ch -> port");\r
- int udpport = _props->integerForKey(KEY_BEGIN_UDP_PORT);\r
- for (int tuner = 0; tuner < _tunerCount; ++tuner)\r
+ Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);\r
+\r
+ // EPG未収集の場合\r
+ // 最大チューナ番号の各サービスにIPTV有効フラグを立てる\r
+ if (_epgs->count() == 0)\r
{\r
- uint max_channel = (_tuners[tuner]->type() == Tuner::ISDB_S ? Tuner::MAX_CHANNELS_ISDB_S : Tuner::MAX_CHANNELS_ISDB_T);\r
- for (uint ch = 0; ch <= max_channel; ++ch)\r
+ Dictionary *flags = Dictionary::dictionaryWithCapacity(0);\r
+ for (int idx = _tunerCount - 1; idx >= 0; --idx)\r
{\r
- if (isChannelEnabled(tuner, ch))\r
+ Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[idx]->name());\r
+ if (tunerInfo->boolForKey(KEY_ENABLED))\r
{\r
- DebugLog0(" %5d,%3d -> %5d", tuner, ch, udpport);\r
-\r
- Dictionary *udp_to_tuner_channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);\r
- if (udp_to_tuner_channel == NULL)\r
+ int ch_max = (_tuners[idx]->type() == Tuner::Type::ISDB_T) ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S;\r
+ for (int ch = 0; ch < ch_max; ++ch)\r
{\r
- udp_to_tuner_channel = Dictionary::dictionaryWithCapacity(0);\r
- _streaming_ctrls->setObject(udp_to_tuner_channel, KEY_MAPPING_UDP_TO_TUNER_CHANNEL);\r
- }\r
-\r
- Dictionary *tuner_channel_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);\r
- if (tuner_channel_to_udp == NULL)\r
- {\r
- tuner_channel_to_udp = Dictionary::dictionaryWithCapacity(0);\r
- _streaming_ctrls->setObject(tuner_channel_to_udp, KEY_MAPPING_TUNER_CHANNEL_TO_UDP);\r
+ char key[8];\r
+ sprintf_s(key, "%03d", ch);\r
+ Dictionary *channelInfo = tunerInfo->dictionaryForKey(KEY_CHANNELS)->dictionaryForKey(key);\r
+ if ((channelInfo != NULL) && channelInfo->boolForKey(KEY_ENABLED))\r
+ {\r
+ Array *services = channelInfo->arrayForKey(KEY_SERVICES);\r
+ for (uint service_idx = 0; service_idx < services->count(); ++service_idx)\r
+ {\r
+ Dictionary *service = (Dictionary *)services->objectAtIndex(service_idx);\r
+ if (!flags->boolForKey(service->stringForKey(KEY_SERVICE_ID)))\r
+ {\r
+ service->setBool(true, KEY_IPTV_ENABLED);\r
+ flags->setBool(true, service->stringForKey(KEY_SERVICE_ID));\r
+ }\r
+ }\r
+ }\r
}\r
-\r
- char port_str[10];\r
- sprintf_s(port_str, "%d", udpport);\r
- char tuner_and_channel[10];\r
- sprintf_s(tuner_and_channel, "%d,%d", tuner, ch);\r
-\r
- udp_to_tuner_channel->setString(tuner_and_channel, port_str);\r
- tuner_channel_to_udp->setString(port_str, tuner_and_channel);\r
-\r
- ++udpport;\r
}\r
}\r
+ _props->writeToFile(_props_path, true);\r
}\r
\r
- RELEASE(_service_to_channels);\r
- _service_to_channels = Dictionary::alloc()->initWithCapacity(0);\r
+ // IPTV用データの準備/UDPポートマッピング\r
+ Dictionary *temp_data = Dictionary::dictionaryWithCapacity(0);\r
+ _epgs->setObject(temp_data, KEY_TEMP_DATA);\r
\r
_xmltv_channels = "";\r
- std::string str_iptv_m3u8;\r
- str_iptv_m3u8 = "#EXTM3U\r\n";\r
- str_iptv_m3u8 += "\r\n";\r
+ std::string str_iptv_m3u8_local;\r
+ std::string str_iptv_m3u8_remote;\r
\r
- Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);\r
+ str_iptv_m3u8_local = "#EXTM3U\r\n";\r
+ str_iptv_m3u8_local += "\r\n";\r
+ str_iptv_m3u8_remote = "#EXTM3U\r\n";\r
+ str_iptv_m3u8_remote += "\r\n";\r
+\r
+ int udpport = _props->integerForKey(KEY_BEGIN_UDP_PORT);\r
+ char http_port_str[10];\r
+ sprintf_s(http_port_str, "%d", _props->integerForKey(KEY_HTTP_PORT));\r
int idx_isdb_t = 0;\r
int idx_isdb_s = 0;\r
Tuner::Type type = Tuner::Type::ISDB_T;\r
for (uint service_idx = 0; service_idx < services->count(); ++service_idx)\r
{\r
Dictionary *service = (Dictionary *)services->objectAtIndex(service_idx);\r
- char channel_name[32];\r
- sprintf_s(channel_name, "%03d_%s", *idx, service->stringForKey(KEY_SERVICE_ID)->cString());\r
-\r
- Array *ch_list = _service_to_channels->arrayForKey(service->stringForKey(KEY_SERVICE_ID));\r
- if (ch_list == NULL)\r
+ if (service->boolForKey(KEY_IPTV_ENABLED))\r
{\r
- ch_list = Array::arrayWithCapacity(0);\r
- _service_to_channels->setObject(ch_list, service->stringForKey(KEY_SERVICE_ID));\r
+ char channel_name[32];\r
+ sprintf_s(channel_name, "%03d_%s", *idx, service->stringForKey(KEY_SERVICE_ID)->cString());\r
+ char channel_service_id[32];\r
+ sprintf_s(channel_service_id, "%03d/%s", *idx, service->stringForKey(KEY_SERVICE_ID)->cString());\r
+\r
+ Dictionary *temp_service = temp_data->dictionaryForKey(service->stringForKey(KEY_SERVICE_ID));\r
+ if (temp_service == NULL)\r
+ {\r
+ temp_service = Dictionary::dictionaryWithCapacity(0);\r
+ temp_data->setObject(temp_service, service->stringForKey(KEY_SERVICE_ID));\r
+ }\r
+ Array *ch_list = temp_service->arrayForKey(KEY_CHANNELS);\r
+ if (ch_list == NULL)\r
+ {\r
+ ch_list = Array::arrayWithCapacity(0);\r
+ temp_service->setObject(ch_list, KEY_CHANNELS);\r
+ }\r
+ ch_list->addObject(String::stringWithUTF8String(channel_name));\r
+\r
+ Dictionary *udp_to_tuner_service_id = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID);\r
+ if (udp_to_tuner_service_id == NULL)\r
+ {\r
+ udp_to_tuner_service_id = Dictionary::dictionaryWithCapacity(0);\r
+ _streaming_ctrls->setObject(udp_to_tuner_service_id, KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID);\r
+ }\r
+\r
+ Dictionary *tuner_service_id_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);\r
+ if (tuner_service_id_to_udp == NULL)\r
+ {\r
+ tuner_service_id_to_udp = Dictionary::dictionaryWithCapacity(0);\r
+ _streaming_ctrls->setObject(tuner_service_id_to_udp, KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);\r
+ }\r
+\r
+ char port_str[10];\r
+ sprintf_s(port_str, "%d", udpport++);\r
+\r
+ udp_to_tuner_service_id->setString(channel_name, port_str);\r
+ tuner_service_id_to_udp->setString(port_str, channel_name);\r
+\r
+\r
+ _xmltv_channels += " <channel id=\"";\r
+ _xmltv_channels += channel_name;\r
+ _xmltv_channels += "\"";\r
+ // transport_stream_id\r
+ // original_network_id\r
+ _xmltv_channels += " service_id=\"";\r
+ _xmltv_channels += service->stringForKey(KEY_SERVICE_ID)->cString();\r
+ _xmltv_channels += "\">\r\n";\r
+\r
+ _xmltv_channels += " <display-name lang=\"ja_JP\">";\r
+ _xmltv_channels += service->stringForKey(KEY_NAME)->cString();\r
+ _xmltv_channels += "</display-name>\r\n";\r
+\r
+ _xmltv_channels += " </channel>\r\n";\r
+\r
+ str_iptv_m3u8_local += "#EXTINF:-1 tvg-id=\"";\r
+ str_iptv_m3u8_local += channel_name;\r
+ str_iptv_m3u8_local += "\" tvg-logo=\"logo_";\r
+ str_iptv_m3u8_local += channel_name;\r
+ str_iptv_m3u8_local += "\" group-title=\"";\r
+ str_iptv_m3u8_local += _tuners[*idx]->name();\r
+ str_iptv_m3u8_local += "\", ";\r
+ str_iptv_m3u8_local += service->stringForKey(KEY_NAME)->cString();\r
+ str_iptv_m3u8_local += "\r\n";\r
+ str_iptv_m3u8_local += "udp://0.0.0.0:";\r
+ str_iptv_m3u8_local += port_str;\r
+ str_iptv_m3u8_local += "\r\n";\r
+\r
+ str_iptv_m3u8_remote += "#EXTINF:-1 tvg-id=\"";\r
+ str_iptv_m3u8_remote += channel_name;\r
+ str_iptv_m3u8_remote += "\" tvg-logo=\"logo_";\r
+ str_iptv_m3u8_remote += channel_name;\r
+ str_iptv_m3u8_remote += "\" group-title=\"";\r
+ str_iptv_m3u8_remote += _tuners[*idx]->name();\r
+ str_iptv_m3u8_remote += "\", ";\r
+ str_iptv_m3u8_remote += service->stringForKey(KEY_NAME)->cString();\r
+ str_iptv_m3u8_remote += "\r\n";\r
+ str_iptv_m3u8_remote += "http://";\r
+ str_iptv_m3u8_remote += _props->stringForKey(KEY_HTTP_HOST)->cString();\r
+ str_iptv_m3u8_remote += ":";\r
+ str_iptv_m3u8_remote += http_port_str;\r
+ str_iptv_m3u8_remote += "/";\r
+ str_iptv_m3u8_remote += channel_service_id;\r
+ str_iptv_m3u8_remote += "/streaming.m3u8\r\n";\r
}\r
- ch_list->addObject(String::stringWithUTF8String(channel_name));\r
-\r
- _xmltv_channels += " <channel id=\"";\r
- _xmltv_channels += channel_name;\r
- _xmltv_channels += "\"";\r
- // transport_stream_id\r
- // original_network_id\r
- _xmltv_channels += " service_id=\"";\r
- _xmltv_channels += service->stringForKey(KEY_SERVICE_ID)->cString();\r
- _xmltv_channels += "\">\r\n";\r
-\r
- _xmltv_channels += " <display-name lang=\"ja_JP\">";\r
- _xmltv_channels += service->stringForKey(KEY_NAME)->cString();\r
- _xmltv_channels += "</display-name>\r\n";\r
-\r
- _xmltv_channels += " </channel>\r\n";\r
-\r
- str_iptv_m3u8 += "#EXTINF:-1 tvg-id=\"";\r
- str_iptv_m3u8 += channel_name;\r
- str_iptv_m3u8 += "\" tvg-logo=\"logo_";\r
- str_iptv_m3u8 += channel_name;\r
- str_iptv_m3u8 += "\" group-title=\"";\r
- str_iptv_m3u8 += _tuners[*idx]->name();\r
- str_iptv_m3u8 += "\", ";\r
- str_iptv_m3u8 += service->stringForKey(KEY_NAME)->cString();\r
- str_iptv_m3u8 += "\r\n";\r
- str_iptv_m3u8 += "http://0.0.0.0:50080/";\r
- str_iptv_m3u8 += channel_name;\r
- str_iptv_m3u8 += "/streaming.m3u8\r\n";\r
}\r
}\r
}\r
type = (type == Tuner::Type::ISDB_T) ? Tuner::Type::ISDB_S : Tuner::Type::ISDB_T;\r
}\r
\r
- _iptv_m3u8 = String::alloc()->initWithUTF8String(str_iptv_m3u8.c_str());\r
+ RELEASE(_iptv_m3u8_local);\r
+ _iptv_m3u8_local = String::alloc()->initWithUTF8String(str_iptv_m3u8_local.c_str());\r
+ RELEASE(_iptv_m3u8_remote);\r
+ _iptv_m3u8_remote = String::alloc()->initWithUTF8String(str_iptv_m3u8_remote.c_str());\r
\r
+ // 過去の番組データは削除\r
+ removePastEPGs();\r
\r
// 周期タイマ起動\r
_timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC, true);\r
return 0;\r
#endif\r
\r
+#if 0\r
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());\r
if (hProcess != NULL)\r
{\r
}\r
CloseHandle(hProcess);\r
}\r
+#endif\r
\r
#ifdef RAYM_MEMORY_CHECK\r
DebugLog0("");\r
_reservation_seq_id = 0;\r
_cancel_epg_collect = false;\r
\r
- _iptv_m3u8 = NULL;\r
- _xmltv_xml = NULL;\r
- _service_to_channels = NULL;\r
+ _iptv_m3u8_local = NULL;\r
+ _iptv_m3u8_remote = NULL; \r
\r
_tunerCount = 0;\r
for (int i = 0; i < ry0::device::MAX_TUNERS; ++i)\r
break;\r
}\r
\r
- // HTTPd ポート\r
+ // HTTP ポート\r
if (_props->integerForKey(KEY_HTTP_PORT) == 0)\r
{\r
_props->setInteger(DEF_HTTP_PORT, KEY_HTTP_PORT);\r
updated = true;\r
}\r
\r
+ if (_props->stringForKey(KEY_HTTP_HOST) == NULL)\r
+ {\r
+ char hostname[NI_MAXHOST];\r
+ if (gethostname(hostname, sizeof(hostname)) == 0)\r
+ {\r
+ addrinfo ai;\r
+ ai.ai_family = PF_INET;\r
+ ai.ai_flags = AI_CANONNAME;\r
+ addrinfo *p = NULL;\r
+ if (getaddrinfo(hostname, 0, &ai, &p) == 0)\r
+ {\r
+ char hostaddr[40];\r
+ if (getnameinfo(p->ai_addr, (int)p->ai_addrlen, hostaddr, sizeof(hostaddr), 0, 0, NI_NUMERICHOST) == 0)\r
+ {\r
+ _props->setString(hostaddr, KEY_HTTP_HOST);\r
+ updated = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
// 休止までの時間\r
if ((_props->integerForKey(KEY_SUSPEND_TIME) < DEF_SUSPEND_TIME) ||\r
(_props->integerForKey(KEY_SUSPEND_TIME) >= _props->integerForKey(KEY_FORCED_SUSPEND_TIME)))\r
if (updated)\r
{\r
DebugLog0("props updated.");\r
- if (!_props->writeToFile(_props_path, false))\r
+ if (!_props->writeToFile(_props_path, true))\r
{\r
DebugLog0("Can't write property file.");\r
result = -1;\r
else\r
{\r
DebugLog1("epgs file: %s", _epgs_path->cString());\r
-\r
- // 過去の番組データは削除\r
- removePastEPGs();\r
}\r
\r
// 予約データファイルのパス設定\r
{\r
result = Application::start();\r
\r
- DebugLog0("will terminate. 00");\r
-\r
// httpd終了待ち\r
_httpd->stop();\r
}\r
\r
- DebugLog0("will terminate. 01");\r
-\r
RaymLock(this);\r
_cancel_epg_collect = true;\r
RaymUnlock(this);\r
RELEASE(_store_path);\r
RELEASE(_reservations_path);\r
RELEASE(_reservations);\r
- RELEASE(_iptv_m3u8);\r
- RELEASE(_xmltv_xml);\r
- RELEASE(_service_to_channels);\r
+ RELEASE(_iptv_m3u8_local);\r
+ RELEASE(_iptv_m3u8_remote);\r
\r
if (_multi2_dll != NULL)\r
{\r