OSDN Git Service

EPG関連修正
authorosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Sat, 9 Apr 2016 15:47:17 +0000 (00:47 +0900)
committerosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Sat, 9 Apr 2016 15:47:17 +0000 (00:47 +0900)
kodiで視聴テスト

iPTd_R2.sdf
src/Raym/Dictionary.cpp
src/Raym/Dictionary.h
src/keys.h
src/net/HTTPDaemon.cpp
src/ry0/iPTd/Analyzer.cpp
src/ry0/iPTd/Controller.cpp
src/ry0/iPTd/Controller.h

index 390b9fb..4161ad0 100644 (file)
Binary files a/iPTd_R2.sdf and b/iPTd_R2.sdf differ
index 140352d..8cd36a6 100644 (file)
@@ -643,6 +643,15 @@ String *Dictionary::stringForKey(const char *key)
     return result;\r
 }\r
 \r
+void Dictionary::setInteger(int value, String *key)\r
+{\r
+    DebugLog2("Dictionary::setInteger(value,key)");\r
+\r
+    Number *v = Number::alloc()->initWithInt(value);\r
+    setObject(v, key);\r
+    v->release();\r
+}\r
+\r
 void Dictionary::setInteger(int value, const char *key)\r
 {\r
     DebugLog2("Dictionary::setInteger(value,key)");\r
@@ -730,6 +739,15 @@ Array *Dictionary::arrayForKey(const char *key)
     return ret;\r
 }\r
 \r
+void Dictionary::setBool(bool value, String *key)\r
+{\r
+    DebugLog2("Dictionary::setBool(value,key)");\r
+\r
+    Number *obj = Number::alloc()->initWithBool(value);\r
+    setObject(obj, key);\r
+    obj->release();\r
+}\r
+\r
 void Dictionary::setBool(bool value, const char *key)\r
 {\r
     DebugLog2("Dictionary::setBool(value,key)");\r
index 5171995..9fa98dc 100644 (file)
@@ -72,6 +72,7 @@ public:
     void setString(const char *string, const char *forKey);
     String *stringForKey(String *key);
     String *stringForKey(const char *key);
+    void setInteger(int value, String *key);
     void setInteger(int value, const char *key);
     int integerForKey(String *key);
     int integerForKey(const char *key);
@@ -79,6 +80,7 @@ public:
     Dictionary *dictionaryForKey(const char *key);
     Array *arrayForKey(String *key);
     Array *arrayForKey(const char *key);
+    void setBool(bool value, String *key);
     void setBool(bool value, const char *key);
     bool boolForKey(String *key);
     bool boolForKey(const char *key);
index c12b949..891f2c9 100644 (file)
@@ -1,9 +1,9 @@
-//\r
-// keys.h\r
-//\r
+/**\r
+ * @file keys.h\r
+ *\r
+ */\r
 \r
-#ifndef __RY0_KEYS_H__\r
-#define __RY0_KEYS_H__\r
+#pragma once\r
 \r
 // general\r
 static const char *KEY_NAME                                                 = "Name";\r
@@ -12,6 +12,7 @@ static const char *KEY_CHANNEL                                              = "C
 // system\r
 static const char *KEY_VERSION                                              = "Version";\r
 static const char *KEY_HOSTNAME                                             = "Hostname";\r
+static const char *KEY_HTTP_HOST                                            = "HTTP Host";\r
 static const char *KEY_HTTP_PORT                                            = "HTTP Port";\r
 static const char *KEY_STORE_PATH                                           = "Store Path";\r
 static const char *KEY_SUSPEND_TIME                                         = "Suspend Time";\r
@@ -20,8 +21,9 @@ static const char *KEY_FORCED_SUSPEND_TIME                                  = "F
 static const char *KEY_COLLECT_EPG_TIME                                     = "Time to Collect EPG";\r
 static const char *KEY_BEGIN_UDP_PORT                                       = "Begin of UDP Port";\r
 static const char *KEY_CACHE_PATH                                           = "Cache Path";\r
-static const char *KEY_MAPPING_UDP_TO_TUNER_CHANNEL                         = "Mapping for UDP Port to Tuner and Channel";\r
-static const char *KEY_MAPPING_TUNER_CHANNEL_TO_UDP                         = "Mapping for Tuner and Channel to UDP Port";\r
+static const char *KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID                      = "Mapping for UDP Port to Tuner and Service ID";\r
+static const char *KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP                      = "Mapping for Tuner and Service ID to UDP Port";\r
+static const char *KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL                  = "Mapping for Tuner and Service ID to Channel";\r
 static const char *KEY_UDP_IN_USE                                           = "UDP in use";\r
 static const char *KEY_HLS_INFO                                             = "HLS Information";\r
 static const char *KEY_HLS_INSTANCE                                         = "HLS Instance";\r
@@ -29,7 +31,6 @@ static const char *KEY_PRESETS                                              = "P
 static const char *KEY_PRESET                                               = "Preset";\r
 static const char *KEY_DEFAULT                                              = "default";\r
 \r
-// tuner info\r
 static const char *KEY_TUNERS                                               = "Tuners";\r
 static const char *KEY_INITIALIZED                                          = "Initialized";\r
 static const char *KEY_ENABLED                  = "Enabled";\r
@@ -43,8 +44,10 @@ static const char *KEY_LNB_POWER                = "LNB Power";
 static const char *KEY_CN                       = "C_N";\r
 static const char *KEY_AGC                      = "AGC";\r
 static const char *KEY_MAX_AGC                  = "Max AGC";\r
+static const char *KEY_TEMP_DATA                                            = "Temp Data";\r
+static const char *KEY_IPTV_ENABLED                                         = "IPTV Enabled";\r
+static const char *KEY_PROGRAMS                                             = "Programs";\r
 \r
-// API\r
 static const char *KEY_RESULT                   = "Result";\r
 \r
 // EPG\r
@@ -102,5 +105,3 @@ static const char *KEY_RESULT                   = "Result";
 \r
 // other\r
 static const char * KEY_COUNTER = "Counter";\r
-\r
-#endif // __RY0_KEYS_H__\r
index d3aaa2e..64c40f0 100644 (file)
@@ -289,6 +289,7 @@ unsigned __stdcall HTTPDaemon_session(void *arg)
 \r
 void HTTPDaemon::session(SOCKET sock, struct sockaddr_in *client)\r
 {\r
+DebugLog0("session start.");\r
     DebugLog2("HTTPDaemon::session()");\r
 \r
     Number *num_sock = Number::alloc()->initWithInt((int)sock);\r
@@ -390,6 +391,10 @@ void HTTPDaemon::session(SOCKET sock, struct sockaddr_in *client)
                 {\r
                     status = HTTP_STATUS_NO_CONTENT;\r
                 }\r
+                else\r
+                {\r
+                    status = HTTP_STATUS_INTERNAL_SERVER_ERROR;\r
+                }\r
                 response = responseWithReason(reasonForStatus(status), status, ver);\r
             }\r
 \r
@@ -492,6 +497,8 @@ void HTTPDaemon::session(SOCKET sock, struct sockaddr_in *client)
         }\r
     }\r
 \r
+DebugLog0("session end.");\r
+\r
     EnterCriticalSection(&_cs);\r
     _sockets->removeObject(num_sock);\r
     LeaveCriticalSection(&_cs);\r
@@ -584,6 +591,7 @@ void HTTPDaemon::run()
                 SOCKET newsock;\r
                 if ((newsock = accept(httpd, (struct sockaddr *)&acc_addr, &sock_len)) != INVALID_SOCKET)\r
                 {\r
+DebugLog0("accepted.");\r
                     HTTPDaemonSessionArgs *args = new HTTPDaemonSessionArgs();\r
                     args->_daemon = this;\r
                     args->_sock = newsock;\r
index 9d4c59b..03a2d5b 100644 (file)
@@ -74,6 +74,7 @@ Dictionary *Analyzer::stationInfo()
                 service->setString(tmp, KEY_SERVICE_ID);\r
                 sprintf_s(tmp, "%d", _sdt->_services[i]._desc->service_type);\r
                 service->setString(tmp, KEY_SERVICE_TYPE);\r
+                service->setBool(false, KEY_IPTV_ENABLED);\r
                 if (_sdt->_services[i]._desc->service_name_length > 0)\r
                 {\r
                     String *name = String::stringWithCString(_sdt->_services[i]._desc->service_name, ShiftJISStringEncoding);\r
index 79356c9..f53288f 100644 (file)
@@ -59,8 +59,8 @@ static const long long CMD_COLLECT_EPG_ISDB_T   = 0x0006;  // 番組情報取得
 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
@@ -217,93 +217,88 @@ void Controller::removePastEPGs()
 {\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
@@ -324,61 +319,80 @@ void Controller::collectEPGsForTuner(int tuner, time_t limit)
         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
@@ -403,13 +417,13 @@ bool Controller::collectEPGs(Tuner::Type type)
     // ロック確認\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
@@ -424,12 +438,15 @@ bool Controller::collectEPGs(Tuner::Type type)
             // チャンネル設定\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
@@ -461,20 +478,7 @@ bool Controller::collectEPGs(Tuner::Type type)
     // 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
@@ -1489,7 +1493,7 @@ void Controller::scanChannel(int tuner)
 \r
         tunerInfo->setInteger(lastChannel, KEY_CHANNEL);\r
 \r
-        _status->writeToFile(_status_path, false);\r
+        _status->writeToFile(_status_path, true);\r
     }\r
 \r
     // 設定ファイルを更新\r
@@ -1560,7 +1564,7 @@ bool Controller::setChannel(int tuner, int channel)
                 {\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
@@ -1594,7 +1598,7 @@ void Controller::periodic_2(void)
 \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
@@ -1646,16 +1650,16 @@ void Controller::periodic_2(void)
                                 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
@@ -1678,8 +1682,8 @@ void Controller::periodic_2(void)
                         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
@@ -1721,13 +1725,20 @@ void Controller::periodic_2(void)
 \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
@@ -2228,28 +2239,28 @@ HTTPResponse *Controller::responseForPrograms(HTTPRequest *request, SOCKADDR_IN
         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
@@ -3752,9 +3763,23 @@ HTTPResponse *Controller::responseForPlaylist(HTTPRequest *request, SOCKADDR_IN
 {\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
@@ -3764,9 +3789,36 @@ HTTPResponse *Controller::responseForXmltv(HTTPRequest *request, SOCKADDR_IN *cl
 {\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
@@ -3775,16 +3827,16 @@ HTTPResponse *Controller::responseForXmltv(HTTPRequest *request, SOCKADDR_IN *cl
 /**\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
@@ -3825,8 +3877,11 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
                 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
@@ -3838,25 +3893,22 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
             }\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
@@ -3870,7 +3922,7 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
                                 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
@@ -3878,7 +3930,7 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
                                     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
@@ -4315,17 +4367,17 @@ DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
         //\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
@@ -4335,23 +4387,24 @@ DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
             }\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
@@ -4364,12 +4417,12 @@ DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
                     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
@@ -4777,28 +4830,24 @@ Array *Controller::programsForServices(Array *services)
     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
@@ -5289,55 +5338,59 @@ int Controller::restart()
         }\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
@@ -5363,44 +5416,93 @@ int Controller::restart()
                             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
@@ -5413,8 +5515,13 @@ int Controller::restart()
         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
@@ -5508,6 +5615,7 @@ int Controller::start()
     return 0;\r
 #endif\r
 \r
+#if 0\r
     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());\r
     if (hProcess != NULL)\r
     {\r
@@ -5517,6 +5625,7 @@ int Controller::start()
         }\r
         CloseHandle(hProcess);\r
     }\r
+#endif\r
 \r
 #ifdef RAYM_MEMORY_CHECK\r
     DebugLog0("");\r
@@ -5550,9 +5659,8 @@ int Controller::start()
     _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
@@ -5701,13 +5809,34 @@ int Controller::start()
             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
@@ -5840,7 +5969,7 @@ int Controller::start()
         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
@@ -5883,9 +6012,6 @@ int Controller::start()
         else\r
         {\r
             DebugLog1("epgs file: %s", _epgs_path->cString());\r
-\r
-            // 過去の番組データは削除\r
-            removePastEPGs();\r
         }\r
 \r
         // 予約データファイルのパス設定\r
@@ -5952,14 +6078,10 @@ int Controller::start()
     {\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
@@ -6017,9 +6139,8 @@ int Controller::start()
     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
index 1336387..b2a5a33 100644 (file)
@@ -13,7 +13,7 @@
 #include "net/HTTPDaemon.h"\r
 \r
 #define VERSION "0.03"\r
-#define REVISION 30\r
+#define REVISION 34\r
 \r
 namespace ry0\r
 {\r
@@ -37,8 +37,30 @@ private:
     Raym::String *          _status_path;           // ステータスファイルのパス\r
     Raym::Dictionary *      _status;                // ステータス\r
     Raym::String *          _epgs_path;             // 番組データファイルのパス\r
-    Raym::Dictionary *      _epgs;                  // 番組データ\r
+\r
+    /**\r
+     * EPGデータ\r
+     *\r
+     * Root                 - Dictionary\r
+     *   KEY_SERVICES       - Dictionary\r
+     *     <service_id>     - Array                 // ソート済み\r
+     *       [Item 0]       - Dictionary            // EPGデータ\r
+     *         :\r
+     *       [Item X]\r
+     *   <station_name>     - Number                // 局毎のEPG収集時間[秒]\r
+     *\r
+     *   KEY_TEMP_DATA      - Dictionary            // ここから下は保存前に削除し、保存後に再構築する\r
+     *     <service_id>     - Dictionary\r
+     *       KEY_CHANNELS   - Array\r
+     *         [Item 0]     - String\r
+     *           :\r
+     *         [Item X]\r
+     *       KEY_PROGRAMS   - String\r
+     */\r
+    Raym::Dictionary *      _epgs;\r
+\r
     Raym::String *          _store_path;            // 録画データ格納先\r
+\r
     Raym::Dictionary *      _reservations;          // 予約情報\r
     Raym::String *          _reservations_path;     // 予約情報ファイルのパス\r
     int                     _reservation_seq_id;    // 予約情報シーケンスID\r
@@ -59,10 +81,9 @@ private:
     Raym::Timer *           _timer_epg_s;           // EPG(ISDB-S)収集用\r
     Raym::Timer *           _timer_epg_t;           // EPG(ISDB-T)収集用\r
 \r
-    Raym::String *          _iptv_m3u8;\r
-    Raym::String *          _xmltv_xml;\r
+    Raym::String *          _iptv_m3u8_local;\r
+    Raym::String *          _iptv_m3u8_remote;\r
     std::string             _xmltv_channels;\r
-    Raym::Dictionary *      _service_to_channels;\r
 \r
     void scanChannel(int tuner);\r
     void periodic();\r
@@ -137,7 +158,7 @@ public:
     NET::HTTPResponse *responseForReloadURI(NET::HTTPRequest *request, SOCKADDR_IN *client, const char *uri, int sec = 0);\r
     NET::HTTPResponse *responseForPlaylist(NET::HTTPRequest *request, SOCKADDR_IN *client);\r
     NET::HTTPResponse *responseForXmltv(NET::HTTPRequest *request, SOCKADDR_IN *client);\r
-    NET::HTTPResponse *responseForHLSControl(NET::HTTPRequest *request, SOCKADDR_IN *client, int tuner, int channel, Raym::String *preset);\r
+    NET::HTTPResponse *responseForHLSControl(NET::HTTPRequest *request, SOCKADDR_IN *client, int tuner, int service_id, Raym::String *preset);\r
     NET::HTTPResponse *requestTunerControl(NET::HTTPRequest *request, SOCKADDR_IN *client, int tuner);\r
     NET::HTTPResponse *request(NET::HTTPRequest *request, SOCKADDR_IN *client);\r
 \r