OSDN Git Service

EPG予約、キーワード予約の不具合修正 master
authorosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Wed, 20 Apr 2016 14:52:42 +0000 (23:52 +0900)
committerosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Wed, 20 Apr 2016 14:52:42 +0000 (23:52 +0900)
15 files changed:
iPTd/iPTd.vcxproj
iPTd/iPTd.vcxproj.filters
iPTd_R2.sdf
src/Raym/Application.cpp
src/Raym/Application.h
src/Raym/Data.cpp
src/Raym/Raym.h
src/Raym/String.cpp
src/keys.h
src/net/HTTPDaemon.cpp
src/net/HTTPDaemon.h
src/net/InternetTextMessageHeader.cpp
src/ry0/iPTd/Controller.cpp
src/ry0/iPTd/Controller.h
src/ry0/iPTd/HTTPLiveStreaming.cpp

index 84611f5..db2b773 100644 (file)
     <ClInclude Include="..\src\net\InternetTextMessage.h" />\r
     <ClInclude Include="..\src\net\InternetTextMessageBody.h" />\r
     <ClInclude Include="..\src\net\InternetTextMessageHeader.h" />\r
+    <ClInclude Include="..\src\net\RTSPRequest.h" />\r
     <ClInclude Include="..\src\Raym\Application.h" />\r
     <ClInclude Include="..\src\Raym\Array.h" />\r
     <ClInclude Include="..\src\Raym\AutoreleasePool.h" />\r
     <ClCompile Include="..\src\net\InternetTextMessage.cpp" />\r
     <ClCompile Include="..\src\net\InternetTextMessageBody.cpp" />\r
     <ClCompile Include="..\src\net\InternetTextMessageHeader.cpp" />\r
+    <ClCompile Include="..\src\net\RTSPRequest.cpp" />\r
     <ClCompile Include="..\src\Raym\Application.cpp" />\r
     <ClCompile Include="..\src\Raym\Array.cpp" />\r
     <ClCompile Include="..\src\Raym\AutoreleasePool.cpp" />\r
index beadd18..454d7ef 100644 (file)
     <ClInclude Include="..\src\mpeg2\ts\Demultiplexer.h">\r
       <Filter>ソース ファイル\mpeg2\ts</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\src\net\RTSPRequest.h">\r
+      <Filter>ソース ファイル\net</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="stdafx.cpp">\r
     <ClCompile Include="..\src\mpeg2\ts\Demultiplexer.cpp">\r
       <Filter>ソース ファイル\mpeg2\ts</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\src\net\RTSPRequest.cpp">\r
+      <Filter>ソース ファイル\net</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ResourceCompile Include="iPTd.rc">\r
index 4161ad0..4fdb0ff 100644 (file)
Binary files a/iPTd_R2.sdf and b/iPTd_R2.sdf differ
index 2b16e0f..e92fcd1 100644 (file)
@@ -11,6 +11,9 @@
 # pragma comment(lib, "comsupp.lib")\r
 # pragma comment(lib, "credui.lib")\r
 \r
+#include <PowrProf.h>\r
+# pragma comment(lib, "PowrProf.lib")\r
+\r
 // #include "Resource.h" --\r
 #define IDS_APP_TITLE           103\r
 \r
@@ -416,6 +419,13 @@ void Application::resetCounter()
     _counter = 0;\r
 }\r
 \r
+void Application::sleep()\r
+{\r
+    _counter = 0;\r
+\r
+    SetSuspendState(FALSE, FALSE, FALSE);\r
+}\r
+\r
 void Application::suspend()\r
 {\r
     _counter = 0;\r
@@ -447,6 +457,18 @@ void Application::suspend()
     SetSystemPowerState(FALSE, FALSE);\r
 }\r
 \r
+void Application::shutdown()\r
+{\r
+    _counter = 0;\r
+\r
+    system("shutdown /s");\r
+\r
+    deleteNotifyIcon();\r
+    DestroyWindow(_wnd);\r
+\r
+    DebugLog0("will terminate");\r
+}\r
+\r
 bool Application::addNotifyIcon()\r
 {\r
     NOTIFYICONDATA nid;\r
index d7391bf..4d3e078 100644 (file)
@@ -46,7 +46,9 @@ public:
     virtual bool canTerminate() = 0;\r
 \r
     void resetCounter();\r
+    void sleep();\r
     void suspend();\r
+    void shutdown();\r
     bool setWakeSchedule(int year, int month, int day, int hour, int min);\r
     void resetWakeSchedule();\r
 #ifdef _WIN32\r
index 32a57f2..4ce5bed 100644 (file)
@@ -135,6 +135,7 @@ Data *Data::initWithContentsOfFile(String *path)
                         int size = _read(fd, &ptr[sum], 256);\r
                         if (size < 0)\r
                         {\r
+                            DebugLog0("Data::initWithContentsOfFile(): _read ng(%d).: %s", errno, path->cString());\r
                             free(ptr);\r
                             release();\r
                             _close(fd);\r
@@ -148,6 +149,7 @@ Data *Data::initWithContentsOfFile(String *path)
                     }\r
                     if (sum != buffer.st_size)\r
                     {\r
+                        DebugLog0("Data::initWithContentsOfFile(): buffer.st_size ng(%d).: %s", errno, path->cString());\r
                         free(ptr);\r
                         release();\r
                         _close(fd);\r
index 3ad180e..1f12b9e 100644 (file)
@@ -19,6 +19,7 @@
 #include <Raym/Stream.h>
 #include <Raym/InputStream.h>
 #include <Raym/FileInputStream.h>
+#include <Raym/URLConnection.h>
 #include <Raym/RunningApplication.h>
 #include <Raym/Application.h>
 
index 2fd9df9..6826a90 100644 (file)
@@ -130,9 +130,22 @@ String *String::stringWithContentsOfFile(const char *path, StringEncoding encodi
             {\r
                 result->autorelease();\r
             }\r
+            else\r
+            {\r
+                DebugLog0("String::stringWithContentsOfFile(): result == NULL");\r
+            }\r
 #endif\r
         }\r
+        else\r
+        {\r
+            DebugLog0("String::stringWithContentsOfFile(): data == NULL");\r
+        }\r
     }\r
+    else\r
+    {\r
+        DebugLog0("String::stringWithContentsOfFile(): path == NULL");\r
+    }\r
+\r
     return result;\r
 }\r
 \r
index 891f2c9..0601fc9 100644 (file)
@@ -21,6 +21,8 @@ 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_HIBERNATION                                          = "Hibernation";\r
+static const char *KEY_SHUTDOWN                                             = "Shutdown";\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
@@ -29,6 +31,7 @@ static const char *KEY_HLS_INFO                                             = "H
 static const char *KEY_HLS_INSTANCE                                         = "HLS Instance";\r
 static const char *KEY_PRESETS                                              = "Presets";\r
 static const char *KEY_PRESET                                               = "Preset";\r
+static const char *KEY_POWER_MANAGER                                        = "Power Manager";\r
 static const char *KEY_DEFAULT                                              = "default";\r
 \r
 static const char *KEY_TUNERS                                               = "Tuners";\r
@@ -100,8 +103,5 @@ static const char *KEY_RESULT                   = "Result";
 #define KEY_I18N_Program_Title                                  "Program Title"\r
 #define KEY_I18N_Description                                    "Description"\r
 \r
-#define URI_PROGRAMS_HTML                                       "programs.html"\r
-#define URI_RESERVATION_HTML                                    "reservation.html"\r
-\r
 // other\r
 static const char * KEY_COUNTER = "Counter";\r
index 64c40f0..78e6534 100644 (file)
@@ -12,6 +12,9 @@ using namespace Raym;
 namespace NET\r
 {\r
 \r
+DEFINE_STATIC_MUTEX(mutex_);\r
+static HTTPResponse *unnecessary_ = NULL;\r
+\r
 HTTPDaemon::HTTPDaemon()\r
 {\r
     DebugLog2("HTTPDaemon::HTTPDaemon()");\r
@@ -220,6 +223,20 @@ HTTPResponse *HTTPDaemon::responseWithPath(String *path, HTTPRequest *request)
     return result;\r
 }\r
 \r
+HTTPResponse *HTTPDaemon::responseOfUnnecessary()\r
+{\r
+    mutex_.lock();\r
+    if (unnecessary_ == NULL)\r
+    {\r
+        unnecessary_ = HTTPResponse::alloc();\r
+        ((Object *)unnecessary_)->init();\r
+        ((Object *)unnecessary_)->autorelease(true);\r
+    }\r
+    mutex_.unlock();\r
+\r
+    return unnecessary_;\r
+}\r
+\r
 String *HTTPDaemon::reasonForStatus(int status)\r
 {\r
     DebugLog2("HTTPDaemon::reasonForStatus()");\r
@@ -289,7 +306,8 @@ unsigned __stdcall HTTPDaemon_session(void *arg)
 \r
 void HTTPDaemon::session(SOCKET sock, struct sockaddr_in *client)\r
 {\r
-DebugLog0("session start.");\r
+    DebugLog0("session start. sock = %d", sock);\r
+\r
     DebugLog2("HTTPDaemon::session()");\r
 \r
     Number *num_sock = Number::alloc()->initWithInt((int)sock);\r
@@ -305,16 +323,23 @@ DebugLog0("session start.");
 \r
         HTTPResponse *response = NULL;\r
         DebugLog3("before request()");\r
-        HTTPRequest *request = HTTPRequest::requestWithSocket(sock);\r
+        HTTPRequest *request;\r
+        if (_delegate != NULL)\r
+        {\r
+            request = _delegate->readRequest(sock);\r
+        }\r
+        else\r
+        {\r
+            request = HTTPRequest::requestWithSocket(sock);\r
+        }\r
         DebugLog3("after request()");\r
         if (request != NULL)\r
         {\r
             if (_delegate != NULL)\r
             {\r
-                response = _delegate->request(request, client);\r
+                response = _delegate->request(request, sock, client);\r
             }\r
 \r
-//            if ((response == NULL) && request->method()->isEqualToString(String::stringWithUTF8String("GET")))\r
             if ((response == NULL) && (request->method()->isEqualToString("GET") || request->method()->isEqualToString("HEAD")))\r
             {\r
                 if (_rootPath != NULL)\r
@@ -377,13 +402,13 @@ DebugLog0("session start.");
                 int status;\r
                 if (request == NULL)\r
                 {\r
-                DebugLog3("request == NULL");\r
+                    DebugLog3("request == NULL");\r
                 }\r
                 else if (request->method() == NULL)\r
                 {\r
-                DebugLog3("method == NULL");\r
+                    DebugLog3("method == NULL");\r
                 }\r
-                if (request->method()->isEqualToString("GET"))\r
+                if (request->method()->isEqualToString("GET") || request->method()->isEqualToString("HEAD"))\r
                 {\r
                     status = HTTP_STATUS_INTERNAL_SERVER_ERROR;\r
                 }\r
@@ -398,86 +423,89 @@ DebugLog0("session start.");
                 response = responseWithReason(reasonForStatus(status), status, ver);\r
             }\r
 \r
-            // status line\r
-            char statusLine[256];\r
-            sprintf_s(statusLine, sizeof(statusLine), "%s %03d %s\r\n", response->version()->cString(), response->status(), response->reason()->cString());\r
-            send(sock, statusLine, (int)strlen(statusLine), 0);\r
-\r
-            InternetTextMessage *message = response->message();\r
-            if (message != NULL)\r
+            if (response != responseOfUnnecessary())\r
             {\r
-                // response header\r
-                InternetTextMessageHeader *header = message->header();\r
-                if (header != NULL)\r
+                // status line\r
+                char statusLine[256];\r
+                sprintf_s(statusLine, sizeof(statusLine), "%s %03d %s\r\n", response->version()->cString(), response->status(), response->reason()->cString());\r
+                send(sock, statusLine, (int)strlen(statusLine), 0);\r
+\r
+                InternetTextMessage *message = response->message();\r
+                if (message != NULL)\r
                 {\r
-                    Array *fieldNames = header->fieldNames();\r
-                    for (uint i = 0; i < fieldNames->count(); ++i)\r
+                    // response header\r
+                    InternetTextMessageHeader *header = message->header();\r
+                    if (header != NULL)\r
                     {\r
-                        String *name = (String *)fieldNames->objectAtIndex(i);\r
-                        char field[16384];\r
-                        sprintf_s(field, sizeof(field), "%s: %s\r\n", name->cString(), header->fieldBodyForName(name)->cString());\r
+                        Array *fieldNames = header->fieldNames();\r
+                        for (uint i = 0; i < fieldNames->count(); ++i)\r
+                        {\r
+                            String *name = (String *)fieldNames->objectAtIndex(i);\r
+                            char field[16384];\r
+                            sprintf_s(field, sizeof(field), "%s: %s\r\n", name->cString(), header->fieldBodyForName(name)->cString());\r
 \r
-                        DebugLog2("send response header");\r
-                        send(sock, field, (int)strlen(field), 0);\r
+                            DebugLog2("send response header");\r
+                            send(sock, field, (int)strlen(field), 0);\r
+                        }\r
                     }\r
-                }\r
 \r
-                send(sock, "\r\n", 2, 0);\r
+                    send(sock, "\r\n", 2, 0);\r
 \r
-                if (!request->method()->isEqualToString("HEAD"))\r
-                {\r
-                    // response entity\r
-                    InternetTextMessageBody *body = message->body();\r
-                    if (body != NULL)\r
+                    if (!request->method()->isEqualToString("HEAD"))\r
                     {\r
-                        const char *ptr = NULL;\r
-                        UInteger length;\r
-                        Data *data = body->data();\r
-                        if (data != NULL)\r
+                        // response entity\r
+                        InternetTextMessageBody *body = message->body();\r
+                        if (body != NULL)\r
                         {\r
-                            ptr = (const char *)data->bytes();\r
-                            length = data->length();\r
-                        }\r
-                        else if (body->body() != NULL)\r
-                        {\r
-                            String *str = body->body();\r
-                            ptr = str->cString();\r
-                            length = str->length();\r
-                        }\r
-                        if (ptr != NULL)\r
-                        {\r
-                            UInteger offset = 0;\r
-                            while (offset < length)\r
+                            const char *ptr = NULL;\r
+                            UInteger length;\r
+                            Data *data = body->data();\r
+                            if (data != NULL)\r
+                            {\r
+                                ptr = (const char *)data->bytes();\r
+                                length = data->length();\r
+                            }\r
+                            else if (body->body() != NULL)\r
                             {\r
-                                int len = ((length - offset) > 16384) ? 16384 : (int)(length - offset);\r
-                                DebugLog2("send response entity");\r
-                                send(sock, &ptr[offset], len, 0);\r
-                                offset += len;\r
+                                String *str = body->body();\r
+                                ptr = str->cString();\r
+                                length = str->length();\r
+                            }\r
+                            if (ptr != NULL)\r
+                            {\r
+                                UInteger offset = 0;\r
+                                while (offset < length)\r
+                                {\r
+                                    int len = ((length - offset) > 16384) ? 16384 : (int)(length - offset);\r
+                                    DebugLog2("send response entity");\r
+                                    send(sock, &ptr[offset], len, 0);\r
+                                    offset += len;\r
+                                }\r
                             }\r
                         }\r
                     }\r
                 }\r
-            }\r
 \r
-            if ((response->status() / 100) != 2)\r
-            {\r
-                DebugLog2("done. response is not OK.");\r
-                done = true;\r
-            }\r
-            else if (request != NULL)\r
-            {\r
-                if (message != NULL)\r
+                if ((response->status() / 100) != 2)\r
                 {\r
-                    InternetTextMessageHeader *header = message->header();\r
-                    if (header != NULL)\r
+                    DebugLog2("done. response is not OK.");\r
+                    done = true;\r
+                }\r
+                else if (request != NULL)\r
+                {\r
+                    if (message != NULL)\r
                     {\r
-                        String *fieldBody = header->fieldBodyForName(String::stringWithUTF8String("Connection"));\r
-                        if (fieldBody != NULL)\r
+                        InternetTextMessageHeader *header = message->header();\r
+                        if (header != NULL)\r
                         {\r
-                            if (strstr(fieldBody->cString(), "close") != NULL)\r
+                            String *fieldBody = header->fieldBodyForName(String::stringWithUTF8String("Connection"));\r
+                            if (fieldBody != NULL)\r
                             {\r
-                                DebugLog2("done. request connection is close.");\r
-                                done = true;\r
+                                if (strstr(fieldBody->cString(), "close") != NULL)\r
+                                {\r
+                                    DebugLog2("done. request connection is close.");\r
+                                    done = true;\r
+                                }\r
                             }\r
                         }\r
                     }\r
@@ -497,7 +525,7 @@ DebugLog0("session start.");
         }\r
     }\r
 \r
-DebugLog0("session end.");\r
+    DebugLog0("session end. sock = %d", sock);\r
 \r
     EnterCriticalSection(&_cs);\r
     _sockets->removeObject(num_sock);\r
@@ -591,7 +619,7 @@ void HTTPDaemon::run()
                 SOCKET newsock;\r
                 if ((newsock = accept(httpd, (struct sockaddr *)&acc_addr, &sock_len)) != INVALID_SOCKET)\r
                 {\r
-DebugLog0("accepted.");\r
+                    DebugLog0("accepted. newsock = %d", newsock);\r
                     HTTPDaemonSessionArgs *args = new HTTPDaemonSessionArgs();\r
                     args->_daemon = this;\r
                     args->_sock = newsock;\r
index 7794a88..2724fb0 100644 (file)
@@ -21,7 +21,8 @@ namespace NET
 class HTTPDaemonDelegate\r
 {\r
 public:\r
-    virtual HTTPResponse *request(HTTPRequest *request, struct sockaddr_in *client) = 0;\r
+    virtual HTTPRequest *readRequest(SOCKET sock) = 0;\r
+    virtual HTTPResponse *request(HTTPRequest *request, SOCKET sock, struct sockaddr_in *client) = 0;\r
 \r
 };\r
 \r
@@ -58,6 +59,7 @@ public:
 \r
     HTTPResponse *responseWithReason(Raym::String *reason, int status, Raym::String *version);\r
     HTTPResponse *responseWithPath(Raym::String *path, HTTPRequest *request);\r
+    static HTTPResponse *responseOfUnnecessary();\r
     static Raym::String *reasonForStatus(int status);\r
 \r
     // for internal use\r
index 43a219e..630deab 100644 (file)
@@ -2,6 +2,7 @@
 // InternetTextMessageHeader.h\r
 //\r
 \r
+#define DBG_LEVEL 3\r
 #include <Raym/Log.h>\r
 #include "net/InternetTextMessageHeader.h"\r
 \r
@@ -66,6 +67,7 @@ InternetTextMessageHeader *InternetTextMessageHeader::initWithData(Data *data)
                         ++value;\r
                     }\r
 \r
+                    DebugLog3("%s: %s", field, value);\r
                     String *body = String::stringWithUTF8String(value);\r
                     String *name = String::stringWithUTF8String(field);\r
                     setFieldBodyWithName(body, name);\r
index f53288f..6cf09a5 100644 (file)
 #include <ws2tcpip.h>\r
 #include <Iphlpapi.h>\r
 \r
+#include "b25/aribstr.h"\r
+#include "b25/arib_std_b25.h"\r
+#include "b25/b_cas_card.h"\r
+\r
+#include "net/RTSPRequest.h"\r
+\r
 #include "ry0/iPTd/Controller.h"\r
 #include "ry0/iPTd/HTTPLiveStreaming.h"\r
 #include "ry0/iPTd/Analyzer.h"\r
 \r
-#include "b25/aribstr.h"\r
-#include "b25/arib_std_b25.h"\r
-#include "b25/b_cas_card.h"\r
 \r
 using namespace Raym;\r
 using namespace NET;\r
@@ -64,7 +67,7 @@ static const time_t DEF_COLLECT_EPG_LIMIT_T  = 20;
 \r
 static const time_t OFFSET_OF_START_TIME        = -2;       // 録画開始時刻の補正(秒単位)\r
 static const time_t OFFSET_OF_END_TIME          = -3;       // 録画停止時刻の補正(秒単位)\r
-static const time_t OFFSET_OF_WAKEUP            = -240;     // 起動スケジュールの補正(秒単位)  注:休止するまでの時間(DEF_SUSPEND_TIME)よりも短くすること\r
+static const time_t OFFSET_OF_WAKEUP            = -300;     // 起動スケジュールの補正(秒単位)  注:休止するまでの時間(DEF_SUSPEND_TIME)よりも短くすること\r
 static const time_t OFFSET_OF_SUPPRESSION_TIME  = -600;     // 録画開始前に休止の抑制を開始する時間(秒単位)\r
 \r
 \r
@@ -448,7 +451,8 @@ bool Controller::collectEPGs(Tuner::Type type)
                 collectEPGsForTuner(tuner, limit);\r
 \r
                 RaymLock(this);\r
-                if (_cancel_epg_collect)\r
+                if (((type == Tuner::ISDB_S) && _cancel_epg_collect_s) ||\r
+                    ((type == Tuner::ISDB_T) && _cancel_epg_collect_t))\r
                 {\r
                     ch = Tuner::MAX_CHANNELS_ISDB_T + 1;\r
                     canceled = true;\r
@@ -475,12 +479,21 @@ bool Controller::collectEPGs(Tuner::Type type)
     // チューナをアンロック\r
     _tuners[tuner]->unlock();\r
 \r
+    if (type == Tuner::ISDB_S)\r
+    {\r
+        _cancel_epg_collect_s = false;\r
+    }\r
+    else\r
+    {\r
+        _cancel_epg_collect_t = false;\r
+    }\r
+\r
     // unlock\r
     RaymUnlock(this);\r
 \r
     DebugLog0("Collect EPG of \"%s(#%d)\" was %s.", _tuners[tuner]->name(), tuner, canceled ? "canceled" : "finished");\r
 \r
-    return true;\r
+    return !canceled;\r
 }\r
 \r
 #ifndef _WIN32\r
@@ -494,24 +507,38 @@ bool Controller::collectEPGs(Tuner::Type type)
 //\r
 bool Controller::reserve(int service_id, int event_id)\r
 {\r
-    DebugLog2("Controller::reserve(service_id, event_id)");\r
+    DebugLog0("Controller::reserve(service_id, event_id)");\r
+    DebugLog0("event_id: %d, service_id: %d", event_id, service_id);\r
 \r
     bool result = false;\r
 \r
     // lock\r
     RaymLock(this);\r
 \r
-    if (_epgs != NULL)\r
+    if ((_epgs != NULL) && (_epgs->dictionaryForKey(KEY_SERVICES) != NULL))\r
     {\r
-        Dictionary *events = _epgs->dictionaryForKey(String::stringWithFormat("%d", service_id));\r
+        Array *events = _epgs->dictionaryForKey(KEY_SERVICES)->arrayForKey(String::stringWithFormat("%d", service_id));\r
         if (events != NULL)\r
         {\r
-            Dictionary *epg = events->dictionaryForKey(String::stringWithFormat("%d", event_id));\r
-            if (epg != NULL)\r
+            DebugLog0("count: %d, event_id: %d, service_id: %d", events->count(), event_id, service_id);\r
+            for (uint i = 0; i < events->count(); ++i)\r
             {\r
-                result = reserve(epg);\r
+                Dictionary *epg = (Dictionary *)events->objectAtIndex(i);\r
+                DebugLog0("epg event_id: %s", epg->stringForKey(KEY_EPG_EVENT_ID)->cString());\r
+                if (epg->stringForKey(KEY_EPG_EVENT_ID)->isEqualToString(String::stringWithFormat("%d", event_id)))\r
+                {\r
+                    result = reserve(epg);\r
+                }\r
             }\r
         }\r
+        else\r
+        {\r
+            DebugLog0("events is NULL");\r
+        }\r
+    }\r
+    else\r
+    {\r
+        DebugLog0("_epgs is NULL");\r
     }\r
 \r
     // unlock\r
@@ -526,7 +553,7 @@ bool Controller::reserve(int service_id, int event_id)
 //\r
 bool Controller::reserve(Dictionary *in_epg)\r
 {\r
-    DebugLog2("Controller::reserve(epg)");\r
+    DebugLog0("Controller::reserve(epg)");\r
 \r
     bool result = false;\r
 \r
@@ -641,7 +668,7 @@ bool Controller::reserve(Dictionary *in_epg)
 //\r
 bool Controller::reserve(int tuner, Dictionary *in_epg)\r
 {\r
-    DebugLog2("Controller::reserve(tuner, epg)");\r
+    DebugLog0("Controller::reserve(tuner, epg)");\r
 \r
     bool result = false;\r
 \r
@@ -1093,12 +1120,13 @@ void Controller::updateKeywordsReservation()
 \r
     // キーワードで検索\r
     Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);\r
-    if (keywords_info != NULL)\r
+\r
+    if ((keywords_info != NULL) && (_epgs != NULL) && (_epgs->dictionaryForKey(KEY_SERVICES) != NULL))\r
     {\r
-        // キーワード有り\r
+        // キーワード、EPG有り\r
 \r
         // _epgs からキー(サービスID)を取得\r
-        Array *service_id_keys = _epgs->allKeys();\r
+        Array *service_id_keys = _epgs->dictionaryForKey(KEY_SERVICES)->allKeys();\r
 \r
         // サービスIDでループ\r
         for (uint service_id_keys_idx = 0; service_id_keys_idx < service_id_keys->count(); ++service_id_keys_idx)\r
@@ -1115,16 +1143,13 @@ void Controller::updateKeywordsReservation()
             }\r
 \r
             // 指定サービスIDのEPGを取得\r
-            Dictionary *events = _epgs->dictionaryForKey((String *)service_id_keys->objectAtIndex(service_id_keys_idx));\r
-\r
-            // キー(イベントID)を取得\r
-            Array *event_id_keys = events->allKeys();\r
+            Array *events = _epgs->dictionaryForKey(KEY_SERVICES)->arrayForKey(service_id);\r
 \r
             // イベントIDでループ\r
-            for (uint event_id_keys_idx = 0; event_id_keys_idx < event_id_keys->count(); ++event_id_keys_idx)\r
+            for (uint events_idx = 0; events_idx < events->count(); ++events_idx)\r
             {\r
                 // 指定イベントIDのEPGを取得\r
-                Dictionary *epg = events->dictionaryForKey((String *)event_id_keys->objectAtIndex(event_id_keys_idx));\r
+                Dictionary *epg = (Dictionary *)events->objectAtIndex(events_idx);\r
 \r
                 // 取得したEPGがキーワードの条件にマッチするか\r
 \r
@@ -1287,14 +1312,39 @@ void Controller::updateSchedule()
 \r
     //\r
     TM resume_tm;\r
-    resume_time += OFFSET_OF_WAKEUP;    // 起動時刻を 5分前に設定(OFFSET_OF_WAKEUPで調整)\r
+    resume_time += OFFSET_OF_WAKEUP;    // 起動時刻を調整\r
     if (localtime_s(&resume_tm, &resume_time) == 0)\r
     {\r
-        resetWakeSchedule();\r
-        if (setWakeSchedule(resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min))\r
+        if (_props->boolForKey(KEY_SHUTDOWN) && (_props->stringForKey(KEY_POWER_MANAGER) != NULL))\r
+        {\r
+            char http_req[256];\r
+            sprintf_s(http_req, "http://%s/iptv.pl?wakeup=%04d/%02d/%02d_%02d:%02d:00",\r
+                      _props->stringForKey(KEY_POWER_MANAGER)->cString(),\r
+                      resume_tm.tm_year + 1900, resume_tm.tm_mon + 1,\r
+                      resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);\r
+            URL *url = URL::URLWithString(http_req);\r
+            URLRequest *req = URLRequest::requestWithURL(url);\r
+            URLResponse *resp = NULL;\r
+            Error *error = NULL;\r
+            Data *data = URLConnection::sendSynchronousRequest(req, &resp, &error);\r
+            if (data != NULL)\r
+            {\r
+                String *html = String::stringWithUTF8String((const char *)data->bytes());\r
+                if ((html != NULL) && (html->rangeOfString("<body>OK</body>").location != NotFound))\r
+                {\r
+                    DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",\r
+                              resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);\r
+                }\r
+            }\r
+        }\r
+        else\r
         {\r
-            DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",\r
-                      resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);\r
+            resetWakeSchedule();\r
+            if (setWakeSchedule(resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min))\r
+            {\r
+                DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",\r
+                          resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);\r
+            }\r
         }\r
     }\r
 \r
@@ -1743,8 +1793,8 @@ void Controller::periodic_2(void)
                                     // lock\r
                                     RaymLock(this);\r
 \r
-                                    // 非ストリーミング中 かつ 非レコーディング中 または チャンネルが同じ 場合\r
-                                    if (!_tuners[tuner]->isStreaming() && (!_tuners[tuner]->isRecording() || _tuners[tuner]->channel() == channel))\r
+                                    // ロックされてない場合\r
+                                    if (!_tuners[tuner]->isLocked())\r
                                     {\r
                                         // ストリーミング開始可能\r
 \r
@@ -2067,7 +2117,7 @@ HTTPResponse *Controller::responseWithUTF8Text(HTTPRequest *request, String *tex
     return result;\r
 }\r
 \r
-HTTPResponse *Controller::responseByResultAndReferer(HTTPRequest *request, bool result, const char *referer)\r
+HTTPResponse *Controller::responseByResult(HTTPRequest *request, bool result)\r
 {\r
     HTTPResponse *retval = NULL;\r
 \r
@@ -2086,19 +2136,17 @@ HTTPResponse *Controller::responseByResultAndReferer(HTTPRequest *request, bool
                 String *field_host    = header->fieldBodyForName("Host");\r
                 if (field_host != NULL)\r
                 {\r
-                    std::string tmp = "http://";\r
+                    std::string tmp = "^http://";\r
                     tmp += field_host->cString();\r
-                    tmp += "/";\r
-                    tmp += referer;\r
-                    iui = field_referer->isEqualToString(tmp.c_str());\r
-                    DebugLog2("tmp: %s", tmp.c_str());\r
-                    DebugLog2("ref: %s", field_referer->cString());\r
+                    tmp += "/(programs_(t|s)_\\d+|reservation)\\.html$";\r
+                    iui = field_referer->isMatch(tmp.c_str());\r
+                    DebugLog0("tmp: %s", tmp.c_str());\r
+                    DebugLog0("ref: %s", field_referer->cString());\r
                 }\r
             }\r
         }\r
     }\r
-//    if ((ref != NULL) && match(ref->cString(), referer))\r
-//    if ((ref != NULL) && ref->isEqualToString(referer))\r
+\r
     if (iui)\r
     {\r
         String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");\r
@@ -2239,6 +2287,190 @@ HTTPResponse *Controller::responseForPrograms(HTTPRequest *request, SOCKADDR_IN
         String *path = _httpd->rootPath();\r
         if (path == NULL)\r
         {\r
+            DebugLog3("_httpd->rootPath() ng.");\r
+            break;\r
+        }\r
+\r
+        path = path->stringByAppendingPathComponent("template2.html");\r
+        if (path == NULL)\r
+        {\r
+            DebugLog0("path->stringByAppendingPathComponent() ng.");\r
+            break;\r
+        }\r
+\r
+        String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);\r
+        if (html == NULL)\r
+        {\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
+            DebugLog0("html->stringByReplacingOccurrencesOfString() ng.");\r
+            break;\r
+        }\r
+\r
+        std::string contents;\r
+\r
+        String *uri = request->URI();\r
+        if (uri->isMatch("^/programs\\.html$"))\r
+        {\r
+            contents += "<ul id=\"home\" title=\"";\r
+            contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();\r
+            contents += "\" selected=\"true\">";\r
+\r
+            // 地デジ\r
+            contents += "<li>";\r
+            contents += "<a target=\"_self\" href=\"/programs_t.html\">";\r
+            contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();\r
+            contents += "</a></li>";\r
+            // BS/CS\r
+            contents += "<li>";\r
+            contents += "<a target=\"_self\" href=\"/programs_s.html\">";\r
+            contents += "BS/CS";\r
+            contents += "</a></li>";\r
+\r
+            contents += "</ul>";\r
+        }\r
+        else if (uri->isMatch("^/programs_t\\.html$"))\r
+        {\r
+            contents += "<ul id=\"home\" title=\"";\r
+            contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();\r
+            contents += "\" selected=\"true\">";\r
+\r
+            // 地デジ(局名)\r
+            Array *stations = stationInfos(Tuner::ISDB_T);\r
+            for (uint i = 0; i < stations->count(); ++i)\r
+            {\r
+                Dictionary *station = (Dictionary *)stations->objectAtIndex(i);\r
+                if ((station != NULL) &&\r
+                    (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&\r
+                    (station->stringForKey(KEY_NAME) != NULL))\r
+                {\r
+                    contents += "<li>";\r
+                    contents += "<a target=\"_self\" href=\"/programs_t_";\r
+                    contents += station->stringForKey(KEY_CHANNEL_ID)->cString();\r
+                    contents += ".html\">";\r
+                    contents += station->stringForKey(KEY_NAME)->cString();\r
+                    contents += "</a></li>";\r
+                }\r
+            }\r
+\r
+            contents += "</ul>";\r
+        }\r
+        else if (uri->isMatch("^/programs_s\\.html$"))\r
+        {\r
+            contents += "<ul id=\"home\" title=\"";\r
+            contents += "BS/CS";\r
+            contents += "\" selected=\"true\">";\r
+\r
+            Array *stations = stationInfos(Tuner::ISDB_S);\r
+            for (uint i = 0; i < stations->count(); ++i)\r
+            {\r
+                Dictionary *station = (Dictionary *)stations->objectAtIndex(i);\r
+                if ((station != NULL) &&\r
+                    (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&\r
+                    (station->stringForKey(KEY_NAME) != NULL))\r
+                {\r
+                    contents += "<li>";\r
+                    contents += "<a target=\"_self\" href=\"/programs_s_";\r
+                    contents += station->stringForKey(KEY_CHANNEL_ID)->cString();\r
+                    contents += ".html\">";\r
+                    contents += station->stringForKey(KEY_NAME)->cString();\r
+                    contents += "</a></li>";\r
+                }\r
+            }\r
+\r
+            contents += "</ul>";\r
+        }\r
+        else if (uri->isMatch("^/programs_(t|s)_.+\\.html$"))\r
+        {\r
+            Array *stations = NULL;\r
+            String *ch_id = NULL;\r
+            if (uri->isMatch("programs_t_"))\r
+            {\r
+                stations = stationInfos(Tuner::ISDB_T);\r
+                ch_id = uri->stringByReplacingOccurrencesOfString("/programs_t_", "");\r
+                ch_id = ch_id->stringByReplacingOccurrencesOfString(".html", "");\r
+            }\r
+            else\r
+            {\r
+                stations = stationInfos(Tuner::ISDB_S);\r
+                ch_id = uri->stringByReplacingOccurrencesOfString("/programs_s_", "");\r
+                ch_id = ch_id->stringByReplacingOccurrencesOfString(".html", "");\r
+            }\r
+\r
+            for (uint i = 0; i < stations->count(); ++i)\r
+            {\r
+                Dictionary *station = (Dictionary *)stations->objectAtIndex(i);\r
+                if ((station != NULL) &&\r
+                    (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&\r
+                    station->stringForKey(KEY_CHANNEL_ID)->isEqualToString(ch_id))\r
+                {\r
+                    std::string epgs;\r
+\r
+                    contents += "<ul id=\"home\" title=\"";\r
+                    contents += station->stringForKey(KEY_NAME)->cString();\r
+                    contents += "\" selected=\"true\">";\r
+\r
+                    Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));\r
+                    for (uint i = 0; i < programs->count(); ++i)\r
+                    {\r
+                        Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);\r
+                        if ((epg != NULL) &&\r
+                            (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&\r
+                            (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&\r
+                            (epg->stringForKey(KEY_EPG_DATE) != NULL) &&\r
+                            (epg->stringForKey(KEY_EPG_START) != NULL) &&\r
+                            (epg->stringForKey(KEY_EPG_END) != NULL))\r
+                        {\r
+                            contents += "<li>";\r
+                            contents += "<a href=\"#epg_";\r
+                            contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();\r
+                            contents += "_";\r
+                            contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();\r
+                            contents += "\">";\r
+                            contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();\r
+                            contents += "&nbsp;";\r
+                            contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();\r
+                            contents += "-";\r
+                            contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();\r
+                            contents += "</a></li>";\r
+\r
+                            epgs += epg_regist_form(epg);\r
+                        }\r
+                    }\r
+\r
+                    contents += "</ul>";\r
+\r
+                    contents += epgs;\r
+\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+\r
+        html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());\r
+        if (html != NULL)\r
+        {\r
+            result = responseWithHTML(request, html);\r
+        }\r
+\r
+        break;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+#if 0\r
+    HTTPResponse *result = NULL;\r
+    while ((request != NULL) && (client != NULL))\r
+    {\r
+        String *path = _httpd->rootPath();\r
+        if (path == NULL)\r
+        {\r
             DebugLog0("_httpd->rootPath() ng.");\r
             break;\r
         }\r
@@ -2429,6 +2661,7 @@ HTTPResponse *Controller::responseForPrograms(HTTPRequest *request, SOCKADDR_IN
     }    \r
     return result;\r
 }\r
+#endif\r
 \r
 HTTPResponse *Controller::responseForReservation(HTTPRequest *request, SOCKADDR_IN *client)\r
 {\r
@@ -3406,7 +3639,7 @@ HTTPResponse *Controller::responseForRegistCGI(HTTPRequest *request, SOCKADDR_IN
                     {\r
                         DebugLog2("valid request");\r
 \r
-                        result = responseByResultAndReferer(request, reserve(service_id->intValue(), event_id->intValue()), URI_PROGRAMS_HTML);\r
+                        result = responseByResult(request, reserve(service_id->intValue(), event_id->intValue()));\r
                     }\r
                 }\r
 \r
@@ -3484,7 +3717,7 @@ HTTPResponse *Controller::responseForRegistCGI(HTTPRequest *request, SOCKADDR_IN
                         // Status\r
                         epg->setString("ready", KEY_EPG_STATUS);\r
 \r
-                        result = responseByResultAndReferer(request, reserve(epg), URI_RESERVATION_HTML);\r
+                        result = responseByResult(request, reserve(epg));\r
                     }\r
                 }\r
             }\r
@@ -3518,7 +3751,7 @@ HTTPResponse *Controller::responseForCancelCGI(HTTPRequest *request, SOCKADDR_IN
                     String *value = param->stringForKey("resv_id");\r
                     if ((value != NULL) && value->isMatch("^\\d{6}$"))\r
                     {\r
-                        result = responseByResultAndReferer(request, cancel(-1, value->intValue()), URI_RESERVATION_HTML);\r
+                        result = responseByResult(request, cancel(-1, value->intValue()));\r
                     }\r
                 }\r
             }\r
@@ -3742,7 +3975,9 @@ HTTPResponse *Controller::responseForReloadURI(NET::HTTPRequest *request, SOCKAD
         contents += "<meta http-equiv=\"refresh\" content=\"0;URL=";\r
 #else\r
         contents += "<meta http-equiv=\"refresh\" content=\"";\r
-        contents += sec;\r
+        char tmp[16];\r
+        sprintf_s(tmp, "%d", sec);\r
+        contents += tmp;\r
         contents += ";URL=";\r
 #endif\r
         contents += uri;\r
@@ -3868,6 +4103,20 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
              // ホスト名を設定\r
             hls_info_tuner->setString(hostname, KEY_HOSTNAME);\r
 \r
+            RaymLock(this);\r
+            if (!_tuners[tuner]->isRecording() && !_tuners[tuner]->isStreaming() && _tuners[tuner]->isLocked())\r
+            {\r
+                if (_tuners[tuner]->type() == Tuner::ISDB_S)\r
+                {\r
+                    _cancel_epg_collect_s = true;\r
+                }\r
+                else\r
+                {\r
+                    _cancel_epg_collect_t = true;\r
+                }\r
+            }\r
+            RaymUnlock(this);\r
+\r
             // HLS制御インスタンス取得\r
             HTTPLiveStreaming *hls = (HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE);\r
             if (hls == NULL)\r
@@ -3948,7 +4197,7 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
             String *index_path = hls->indexPath();\r
             FileManager *fm = FileManager::defaultManager();\r
             int count = 0;\r
-            while (count++ < 30)\r
+            while (count++ < 5)\r
             {\r
                 bool isDirectory = false;\r
                 if (fm->fileExistsAtPath(index_path, &isDirectory))\r
@@ -3976,15 +4225,13 @@ HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_I
 \r
             RaymLock(this);\r
 \r
+            hls_info_tuner->setInteger(0, KEY_COUNTER);\r
+\r
             if (result == NULL)\r
             {\r
                 DebugLog0("file no exists");\r
                 result = responseForReloadURI(request, client, request->URI()->cString(), 10);\r
             }\r
-            else\r
-            {\r
-                hls_info_tuner->setInteger(0, KEY_COUNTER);\r
-            }\r
         }\r
         else\r
         {\r
@@ -4184,7 +4431,7 @@ DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
                     if (epg != NULL)\r
                     {\r
                         // 録画開始&結果生成\r
-                        result = responseByResultAndReferer(request, reserve(tuner, epg), URI_RESERVATION_HTML);\r
+                        result = responseByResult(request, reserve(tuner, epg));\r
                     }\r
                 }\r
             }\r
@@ -4439,7 +4686,173 @@ DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
     return result;\r
 }\r
 \r
-HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)\r
+HTTPResponse *Controller::requestRTSP(RTSPRequest *request, SOCKET sock, SOCKADDR_IN *client)\r
+{\r
+    HTTPResponse *result = NULL;\r
+\r
+    static int streaming_port = 0;\r
+\r
+    String *uri = request->URI();\r
+    if (uri->isMatch("^rtsp://[^/]+(:\\d+)/[0-9]{3}/[0-9]+/streaming.sdp/?$"))\r
+    {\r
+        if (request->method()->isEqualToString("OPTIONS"))\r
+        {\r
+            result = HTTPResponse::alloc()->init();\r
+            result->setVersion(request->version());\r
+            result->setStatus(HTTP_STATUS_OK);\r
+            result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));\r
+\r
+            InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();\r
+            header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), String::stringWithUTF8String("CSeq"));\r
+            header->setFieldBodyWithName(String::stringWithUTF8String("DESCRIBE, SETUP, TEARDOWN, PLAY"), String::stringWithUTF8String("Public"));\r
+\r
+            InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);\r
+            RELEASE(header);\r
+\r
+            result->setMessage(message);\r
+            result->autorelease();\r
+            RELEASE(message);\r
+        }\r
+        else if (request->method()->isEqualToString("DESCRIBE"))\r
+        {\r
+            String *accept = request->message()->header()->fieldBodyForName("Accept");\r
+            if ((accept != NULL) && accept->isMatch("application/sdp"))\r
+            {\r
+                result = HTTPResponse::alloc()->init();\r
+                result->setVersion(request->version());\r
+                result->setStatus(HTTP_STATUS_OK);\r
+                result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));\r
+\r
+                InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();\r
+                header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), "CSeq");\r
+                header->setFieldBodyWithName("23 Jan 2007 15:35:06 JST", "Date");\r
+                header->setFieldBodyWithName("application/sdp", "Content-Type");\r
+\r
+                std::string str_body;\r
+                str_body =  "v=0\r\n";                                    // プロトコルのバージョン\r
+                str_body += "o=hoge 1234 5678 IN IP4 172.19.29.9\r\n";   // 発信元およびセッション識別子\r
+                str_body += "s=test\r\n";                                // セッション名\r
+                str_body += "c=IN IP4 172.19.29.9\r\n";                                // \r
+                str_body += "t=0 0\r\n";\r
+                str_body += "a=control:*\r\n";\r
+                str_body += "a=range:npt=0-\r\n";\r
+                str_body += "m=video 0 RAW/RAW/UDP 33\r\n";\r
+\r
+                // Content-Length\r
+                header->setFieldBodyWithName(String::stringWithFormat("%I64u", str_body.length()), "Content-Length");\r
+\r
+                InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(str_body.c_str()));\r
+\r
+                InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);\r
+                RELEASE(header);\r
+                RELEASE(body);\r
+\r
+                result->setMessage(message);\r
+                result->autorelease();\r
+                RELEASE(message);\r
+            }\r
+        }\r
+        else if (request->method()->isEqualToString("SETUP"))\r
+        {\r
+            String *transport = request->message()->header()->fieldBodyForName("Transport");\r
+            if ((transport != NULL) && transport->isMatch("UDP.*;unicast;client_port=\\d+"))\r
+            {\r
+                Range r = transport->rangeOfString("_port=");\r
+                String *port = transport->substringFromIndex(r.location + 6);\r
+                r = port->rangeOfString("-");\r
+                port = port->substringToIndex(r.location);\r
+                DebugLog0("port: %s", port->cString());\r
+                streaming_port = port->intValue();\r
+\r
+                result = HTTPResponse::alloc()->init();\r
+                result->setVersion(request->version());\r
+                result->setStatus(HTTP_STATUS_OK);\r
+                result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));\r
+\r
+                InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();\r
+                header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), "CSeq");\r
+                header->setFieldBodyWithName("12345678", "Session");\r
+                String *tr = transport->stringByAppendingString(";server_port=50020-50021");\r
+                header->setFieldBodyWithName(tr, "Transport");\r
+\r
+                InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);\r
+                RELEASE(header);\r
+\r
+                result->setMessage(message);\r
+                result->autorelease();\r
+                RELEASE(message);\r
+            }\r
+        }\r
+        else if (request->method()->isEqualToString("PLAY"))\r
+        {\r
+            String *range = request->message()->header()->fieldBodyForName("Range");\r
+            if (range != NULL)\r
+            {\r
+                result = HTTPResponse::alloc()->init();\r
+                result->setVersion(request->version());\r
+                result->setStatus(HTTP_STATUS_OK);\r
+                result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));\r
+\r
+                InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();\r
+                header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), "CSeq");\r
+                header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("Session"), "Session");\r
+                header->setFieldBodyWithName(range, "Range");\r
+\r
+                InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);\r
+                RELEASE(header);\r
+\r
+                result->setMessage(message);\r
+                result->autorelease();\r
+                RELEASE(message);\r
+\r
+                SOCKADDR_IN dst_addr;\r
+\r
+                dst_addr.sin_family = AF_INET;\r
+                dst_addr.sin_addr.s_addr = htonl(0xac131d01);\r
+                dst_addr.sin_port = htons(streaming_port);\r
+\r
+                if (_tuners[1]->startStreaming(&dst_addr))\r
+                {\r
+                    DebugLog0("streaming start ok");\r
+                }\r
+            }\r
+        }\r
+        else if (request->method()->isEqualToString("TEARDOWN"))\r
+        {\r
+            result = HTTPResponse::alloc()->init();\r
+            result->setVersion(request->version());\r
+            result->setStatus(HTTP_STATUS_OK);\r
+            result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));\r
+\r
+            InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();\r
+            header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), String::stringWithUTF8String("CSeq"));\r
+\r
+            InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);\r
+            RELEASE(header);\r
+\r
+            result->setMessage(message);\r
+            result->autorelease();\r
+            RELEASE(message);\r
+        }\r
+    }\r
+    else\r
+    {\r
+        DebugLog0("no match");\r
+    }\r
+\r
+    if (result == NULL)\r
+    {\r
+        result = HTTPResponse::alloc()->init();\r
+        result->setVersion(request->version());\r
+        result->setStatus(HTTP_STATUS_NOT_FOUND);\r
+        result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_NOT_FOUND));\r
+        result->autorelease();\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+HTTPResponse *Controller::request(HTTPRequest *request, SOCKET sock, SOCKADDR_IN *client)\r
 {\r
     DebugLog2("%s\n", __FUNCTION__);\r
 \r
@@ -4453,6 +4866,11 @@ HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)
         return NULL;\r
     }\r
 \r
+    if (request->version()->isEqualToString("RTSP/1.0"))\r
+    {\r
+        return requestRTSP((RTSPRequest *)request, sock, client);\r
+    }\r
+\r
     HTTPResponse *response = NULL;\r
 \r
     if (request->method()->isEqualToString("GET") ||\r
@@ -4460,7 +4878,7 @@ HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)
     {\r
         // URI\r
         String *uri = request->URI();\r
-        DebugLog0("request: %s\n", uri->cString());\r
+        DebugLog0("request(%d): %s\n", sock, uri->cString());\r
 \r
         //\r
         //\r
@@ -4560,8 +4978,7 @@ HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)
         //\r
         // program\r
         //\r
-//        else if (match(uri.c_str(), "^/programs.html$"))\r
-        else if (uri->isMatch("^/" URI_PROGRAMS_HTML "$"))\r
+        else if (uri->isMatch("^/programs.*\\.html$"))\r
         {\r
             response = responseForPrograms(request, client);\r
         }\r
@@ -4637,6 +5054,11 @@ HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)
     return response;\r
 }\r
 \r
+HTTPRequest * Controller::readRequest(SOCKET sock)\r
+{\r
+    return RTSPRequest::requestWithSocket(sock);\r
+}\r
+\r
 #ifndef _WIN32\r
 #pragma mark '\r
 #pragma mark ------- プロパティ取得 -------\r
@@ -4931,22 +5353,23 @@ void Controller::timerExpired(Timer *timer, void *userInfo)
         {\r
             // 初期化成功\r
             DebugLog2("tuner initialize success.");\r
-#if 1\r
+\r
+            _cancel_epg_collect_s = false;\r
+            _cancel_epg_collect_t = false;\r
+\r
             // EPG収集用タイマ起動(ISDB-S)\r
             _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);\r
             if (_timer_epg_s != NULL)\r
             {\r
                 _timer_epg_s->fire();\r
             }\r
-#endif\r
-#if 1\r
+\r
             // EPG収集用タイマ起動(ISDB-T)\r
             _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);\r
             if (_timer_epg_t != NULL)\r
             {\r
                 _timer_epg_t->fire();\r
             }\r
-#endif\r
         }\r
         else\r
         {\r
@@ -5094,7 +5517,8 @@ void Controller::systemWillSuspend()
     DebugLog2("Controller::systemWillSuspend() start");\r
 \r
     RaymLock(this);\r
-    _cancel_epg_collect = true;\r
+    _cancel_epg_collect_s = true;\r
+    _cancel_epg_collect_t = true;\r
     RaymUnlock(this);\r
 \r
     // タイマ停止\r
@@ -5145,8 +5569,6 @@ void Controller::systemWillSuspend()
         }\r
     }\r
 \r
-    _cancel_epg_collect = false;\r
-\r
     DebugLog0("system will suspend...");\r
 \r
     // unlock\r
@@ -5244,6 +5666,9 @@ void Controller::detectIdle()
             // unlock\r
             RaymUnlock(this);\r
 \r
+            bool shutdown = _props->boolForKey(KEY_SHUTDOWN);\r
+            bool hibernation = _props->boolForKey(KEY_HIBERNATION);\r
+\r
             // サスペンド前にARPを解放しておく\r
             pool->release();\r
 \r
@@ -5251,8 +5676,19 @@ void Controller::detectIdle()
             // ブロードキャストされないため、自分でコールしておく\r
             systemWillSuspend();\r
 \r
-            // サスペンド\r
-            suspend();\r
+            //\r
+            if (shutdown)\r
+            {\r
+                Application::shutdown();\r
+            }\r
+            else if (hibernation)\r
+            {\r
+                Application::suspend();\r
+            }\r
+            else\r
+            {\r
+                Application::sleep();\r
+            }\r
 \r
             // 再度 ARPを用意\r
             pool = AutoreleasePool::alloc()->init();\r
@@ -5451,11 +5887,19 @@ int Controller::restart()
                                         _streaming_ctrls->setObject(tuner_service_id_to_udp, KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);\r
                                     }\r
 \r
+                                    Dictionary *tuner_service_id_to_channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL);\r
+                                    if (tuner_service_id_to_channel == NULL)\r
+                                    {\r
+                                        tuner_service_id_to_channel = Dictionary::dictionaryWithCapacity(0);\r
+                                        _streaming_ctrls->setObject(tuner_service_id_to_channel, KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL);\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
+                                    tuner_service_id_to_channel->setInteger(ch, channel_name);\r
 \r
 \r
                                     _xmltv_channels += "  <channel id=\"";\r
@@ -5495,6 +5939,7 @@ int Controller::restart()
                                     str_iptv_m3u8_remote += "\", ";\r
                                     str_iptv_m3u8_remote += service->stringForKey(KEY_NAME)->cString();\r
                                     str_iptv_m3u8_remote += "\r\n";\r
+#if 0\r
                                     str_iptv_m3u8_remote += "http://";\r
                                     str_iptv_m3u8_remote += _props->stringForKey(KEY_HTTP_HOST)->cString();\r
                                     str_iptv_m3u8_remote += ":";\r
@@ -5502,6 +5947,16 @@ int Controller::restart()
                                     str_iptv_m3u8_remote += "/";\r
                                     str_iptv_m3u8_remote += channel_service_id;\r
                                     str_iptv_m3u8_remote += "/streaming.m3u8\r\n";\r
+#else\r
+//                                    str_iptv_m3u8_remote += "rtsp://";\r
+                                    str_iptv_m3u8_remote += "sip://";\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.sdp\r\n";\r
+#endif\r
                                 }\r
                             }\r
                         }\r
@@ -5540,6 +5995,8 @@ int Controller::restart()
     // unlock\r
     RaymUnlock(this);\r
 \r
+    DebugLog0("initialize done.");\r
+\r
     return (_tunerCount > 0);\r
 }\r
 \r
@@ -5615,7 +6072,7 @@ int Controller::start()
     return 0;\r
 #endif\r
 \r
-#if 0\r
+#if 1\r
     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());\r
     if (hProcess != NULL)\r
     {\r
@@ -5657,7 +6114,8 @@ int Controller::start()
     _idle_count         = 0;\r
     _initialized        = false;\r
     _reservation_seq_id = 0;\r
-    _cancel_epg_collect = false;\r
+    _cancel_epg_collect_s = false;\r
+    _cancel_epg_collect_t = false;\r
 \r
     _iptv_m3u8_local    = NULL;\r
     _iptv_m3u8_remote   = NULL; \r
@@ -5965,6 +6423,15 @@ int Controller::start()
             break;\r
         }\r
 \r
+        if (_props->boolForKey(KEY_SHUTDOWN))\r
+        {\r
+            if (_props->stringForKey(KEY_POWER_MANAGER) == NULL)\r
+            {\r
+                _props->setBool(false, KEY_SHUTDOWN);\r
+                updated = true;\r
+            }\r
+        }\r
+\r
         // プロパティファイルを保存\r
         if (updated)\r
         {\r
@@ -5983,6 +6450,10 @@ int Controller::start()
         DebugLog0("  HTTP Port           : %d", _props->integerForKey(KEY_HTTP_PORT));\r
         DebugLog0("  Suspend Time        : %d min", _props->integerForKey(KEY_SUSPEND_TIME));\r
         DebugLog0("  Forced Suspend Time : %d min", _props->integerForKey(KEY_FORCED_SUSPEND_TIME));\r
+        if (_props->boolForKey(KEY_SHUTDOWN))\r
+        {\r
+            DebugLog0("  Power Manager       : %s", _props->stringForKey(KEY_POWER_MANAGER)->cString());\r
+        }\r
         Array *apps = _props->arrayForKey(KEY_DO_NOT_IN_SUSPEND);\r
         if (apps != NULL)\r
         {\r
@@ -6083,7 +6554,8 @@ int Controller::start()
     }\r
 \r
     RaymLock(this);\r
-    _cancel_epg_collect = true;\r
+    _cancel_epg_collect_s = true;\r
+    _cancel_epg_collect_t = true;\r
     RaymUnlock(this);\r
 \r
     // タイマ停止\r
index b2a5a33..e8310b0 100644 (file)
 #include "ry0/device/TunerFactory.h"\r
 \r
 #include "net/HTTPDaemon.h"\r
+#include "net/RTSPRequest.h"\r
 \r
-#define VERSION "0.03"\r
-#define REVISION 34\r
+#define VERSION "0.05"\r
+#define REVISION 37\r
 \r
 namespace ry0\r
 {\r
@@ -44,7 +45,7 @@ private:
      * Root                 - Dictionary\r
      *   KEY_SERVICES       - Dictionary\r
      *     <service_id>     - Array                 // ソート済み\r
-     *       [Item 0]       - Dictionary            // EPGデータ\r
+     *       [Item 0]       - Dictionary            // EPGデータ (時間で昇順にソート)\r
      *         :\r
      *       [Item X]\r
      *   <station_name>     - Number                // 局毎のEPG収集時間[秒]\r
@@ -68,7 +69,8 @@ private:
 \r
     bool                    _initialized;           // 初期化済み\r
     HMODULE                 _multi2_dll;\r
-    bool                    _cancel_epg_collect;    // EPG収集キャンセル\r
+    bool                    _cancel_epg_collect_s;  // EPG収集キャンセル(ISDB-S)\r
+    bool                    _cancel_epg_collect_t;  // EPG収集キャンセル(ISDB-T)\r
 \r
     NET::HTTPDaemon *       _httpd;\r
 \r
@@ -146,7 +148,7 @@ public:
     // HTTP制御関連\r
     NET::HTTPResponse *responseWithHTML(NET::HTTPRequest *request, Raym::String *html);\r
     NET::HTTPResponse *responseWithUTF8Text(NET::HTTPRequest *request, Raym::String *text);\r
-    NET::HTTPResponse *responseByResultAndReferer(NET::HTTPRequest *request, bool result, const char *referer);\r
+    NET::HTTPResponse *responseByResult(NET::HTTPRequest *request, bool result);\r
     NET::HTTPResponse *responseForMain(NET::HTTPRequest *request, SOCKADDR_IN *client);\r
     NET::HTTPResponse *responseForPrograms(NET::HTTPRequest *request, SOCKADDR_IN *client);\r
     NET::HTTPResponse *responseForReservation(NET::HTTPRequest *request, SOCKADDR_IN *client);\r
@@ -160,7 +162,9 @@ public:
     NET::HTTPResponse *responseForXmltv(NET::HTTPRequest *request, SOCKADDR_IN *client);\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
+    NET::HTTPResponse *requestRTSP(NET::RTSPRequest *request, SOCKET sock, SOCKADDR_IN *client);\r
+    NET::HTTPResponse *request(NET::HTTPRequest *request, SOCKET sock, SOCKADDR_IN *client);\r
+    NET::HTTPRequest *readRequest(SOCKET sock);\r
 \r
     // Windows用IF (from TrayApp)\r
     int  start();    // エントリポイント\r
index 907cf8d..c8f527a 100644 (file)
@@ -178,8 +178,10 @@ bool HTTPLiveStreaming::start()
     args->addObject(String::stringWithUTF8String("30000/1001"));
     args->addObject(String::stringWithUTF8String("-aspect"));
     args->addObject(String::stringWithUTF8String("16:9"));
-    args->addObject(String::stringWithUTF8String("-s"));
-    args->addObject(String::stringWithUTF8String("1280x720"));
+//    args->addObject(String::stringWithUTF8String("-s"));
+//    args->addObject(String::stringWithUTF8String("1280x720"));
+    args->addObject(String::stringWithUTF8String("-g"));
+    args->addObject(String::stringWithUTF8String("150"));
     args->addObject(String::stringWithUTF8String("-bufsize"));
     args->addObject(String::stringWithUTF8String("20000k"));
     args->addObject(String::stringWithUTF8String("-maxrate"));