OSDN Git Service

recording
authorosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Thu, 10 Mar 2016 14:47:28 +0000 (23:47 +0900)
committerosx86_pt1 <rmitachi@ta2.so-net.ne.jp>
Thu, 10 Mar 2016 14:47:28 +0000 (23:47 +0900)
16 files changed:
iPTd_R2.sdf
src/Raym/Application.cpp
src/Raym/Array.cpp
src/Raym/AutoreleasePool.cpp
src/Raym/Dictionary.cpp
src/Raym/Lock.cpp
src/Raym/Object.cpp
src/Raym/Object.h
src/Raym/Raym.h
src/ry0/iPTd/Controller.cpp
src/ry0/iPTd/Controller.h
src/ry0/iPTd/HTTPD.cpp
src/ry0/iPTd/HTTPD.h
src/ry0/iPTd/Reservation.cpp
src/ry0/iPTd/Reservation.h
src/ry0/iPTd/Streaming.cpp

index 739f897..a20447a 100644 (file)
Binary files a/iPTd_R2.sdf and b/iPTd_R2.sdf differ
index 397546c..ee868d3 100644 (file)
@@ -915,9 +915,9 @@ int Application::main(Application *(*allocator)(), LPCWSTR className, HINSTANCE
 {\r
     int result = -1;\r
 \r
-#ifdef OBJC_MEMORY_CHECK\r
+#ifdef RAYM_MEMORY_CHECK\r
     DebugLog0("");\r
-    DebugLog0("Application::main() global_objc_count_ = %d", Raym::global_objc_count_);\r
+    DebugLog0("Application::main() global_raym_count_ = %d", Raym::global_raym_count_);\r
 #endif\r
 \r
     // ARP生成\r
@@ -948,8 +948,8 @@ int Application::main(Application *(*allocator)(), LPCWSTR className, HINSTANCE
     // ARP解放\r
     pool->release();\r
 \r
-#ifdef OBJC_MEMORY_CHECK\r
-    DebugLog0("Application::main() global_objc_count_ = %d", Raym::global_objc_count_);\r
+#ifdef RAYM_MEMORY_CHECK\r
+    DebugLog0("Application::main() global_raym_count_ = %d", Raym::global_raym_count_);\r
 #endif\r
 \r
     return result;\r
index c3c681a..0f3dbb6 100644 (file)
@@ -75,9 +75,9 @@ UInteger Array::count()
     DebugLog2("Array::count()");\r
 \r
     UInteger result = 0;\r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     result = (UInteger)_array.size();\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 \r
     return result;\r
 }\r
@@ -88,10 +88,10 @@ void Array::addObject(Object *object)
 \r
     if (object != NULL)\r
     {\r
-        OBJC_LOCK(this);\r
+        RaymLock(this);\r
         object->retain();\r
         _array.push_back(object);\r
-        OBJC_UNLOCK(this);\r
+        RaymUnlock(this);\r
     }\r
 }\r
 \r
@@ -101,14 +101,14 @@ void Array::addObjectsFromArray(Array *array)
 \r
     if (array != NULL)\r
     {\r
-        OBJC_LOCK(this);\r
+        RaymLock(this);\r
         for (UInteger i = 0; i < array->count(); ++i)\r
         {\r
             Object *object = array->objectAtIndex(i);\r
             object->retain();\r
             _array.push_back(object);\r
         }\r
-        OBJC_UNLOCK(this);\r
+        RaymUnlock(this);\r
     }\r
 }\r
 \r
@@ -117,12 +117,12 @@ Object *Array::objectAtIndex(UInteger index)
     DebugLog2("Array::objectAtIndex(index)");\r
 \r
     Object *result = NULL;\r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     if (index < _array.size())\r
     {\r
         result = _array.at(index);\r
     }\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 \r
     return result;\r
 }\r
@@ -131,7 +131,7 @@ void Array::insertObject(Object *object, UInteger index)
 {\r
     DebugLog2("Array::insertObject(object,index)");\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     if (object != NULL)\r
     {\r
         std::vector<Object *>::iterator it;\r
@@ -147,14 +147,14 @@ void Array::insertObject(Object *object, UInteger index)
             ++idx;\r
         }\r
     }\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 }\r
 \r
 void Array::removeObject(Object *object)\r
 {\r
     DebugLog2("Array::removeObject(object)");\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     std::vector<Object *>::iterator it;\r
     for (it = _array.begin(); it != _array.end(); ++it)\r
     {\r
@@ -165,14 +165,14 @@ void Array::removeObject(Object *object)
             break;\r
         }\r
     }\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 }\r
 \r
 void Array::removeObjectAtIndex(UInteger index)\r
 {\r
     DebugLog2("Array::removeObjectAtIndex(index)");\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     std::vector<Object *>::iterator it;\r
     UInteger idx = 0;\r
     for (it = _array.begin(); it != _array.end(); ++it)\r
@@ -185,21 +185,21 @@ void Array::removeObjectAtIndex(UInteger index)
         }\r
         ++idx;\r
     }\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 }\r
 \r
 void Array::removeAllObjects()\r
 {\r
     DebugLog2("Array::removeAllObjects()");\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     for (unsigned int i = 0; i < _array.size(); ++i)\r
     {\r
         Object *obj = _array.at(i);\r
         obj->release();\r
     }\r
     _array.clear();\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 }\r
 \r
 Array *Array::sortedArrayUsingFunction(Integer (*function)(Object *, Object *, void *), void *context)\r
@@ -208,7 +208,7 @@ Array *Array::sortedArrayUsingFunction(Integer (*function)(Object *, Object *, v
 \r
     Array *result = Array::arrayWithCapacity(0);\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
 \r
     for (unsigned int i = 0; i < _array.size(); ++i)\r
     {\r
@@ -233,7 +233,7 @@ Array *Array::sortedArrayUsingFunction(Integer (*function)(Object *, Object *, v
         }\r
     }\r
 \r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 \r
     return result;\r
 }\r
index 63387c2..b7c0d9e 100644 (file)
@@ -123,9 +123,9 @@ void AutoreleasePool::add(Object *object)
 
     if (object != NULL)
     {
-        OBJC_LOCK(this);
+        RaymLock(this);
         _objects.push_back(object);
-        OBJC_UNLOCK(this);
+        RaymUnlock(this);
     }
 }
 
index 86631b0..140352d 100644 (file)
@@ -510,14 +510,14 @@ void Dictionary::setObject(Object *object, String *forKey)
 \r
     if ((object != NULL) && (forKey != NULL))\r
     {\r
-        OBJC_LOCK(this);\r
+        RaymLock(this);\r
         removeObjectForKey(forKey);\r
         KeyAndValue *kv = KeyAndValue::keyAndValue(forKey, object);\r
         if (kv != NULL)\r
         {\r
             _dict.push_back(kv);\r
         }\r
-        OBJC_UNLOCK(this);\r
+        RaymUnlock(this);\r
     }\r
 }\r
 \r
@@ -528,7 +528,7 @@ Object *Dictionary::objectForKey(String *key)
     Object *result = NULL;\r
     if (key != NULL)\r
     {\r
-        OBJC_LOCK(this);\r
+        RaymLock(this);\r
         std::vector<Object *>::iterator it;\r
         for (it = _dict.begin(); it != _dict.end(); ++it)\r
         {\r
@@ -539,7 +539,7 @@ Object *Dictionary::objectForKey(String *key)
                 break;\r
             }\r
         }\r
-        OBJC_UNLOCK(this);\r
+        RaymUnlock(this);\r
     }\r
     return result;\r
 }\r
@@ -550,7 +550,7 @@ void Dictionary::removeObjectForKey(String *key)
 \r
     if (key != NULL)\r
     {\r
-        OBJC_LOCK(this);\r
+        RaymLock(this);\r
         std::vector<Object *>::iterator it;\r
         for (it = _dict.begin(); it != _dict.end(); ++it)\r
         {\r
@@ -562,7 +562,7 @@ void Dictionary::removeObjectForKey(String *key)
                 break;\r
             }\r
         }\r
-        OBJC_UNLOCK(this);\r
+        RaymUnlock(this);\r
     }\r
 }\r
 \r
@@ -770,7 +770,7 @@ Array *Dictionary::allKeys()
     DebugLog2("Dictionary::allKeys()");\r
 \r
     Array *result = Array::alloc()->initWithCapacity(0)->autorelease();\r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
 \r
     std::vector<Object *>::iterator it;\r
     for (it = _dict.begin(); it != _dict.end(); ++it)\r
@@ -779,7 +779,7 @@ Array *Dictionary::allKeys()
         result->addObject(kv->key());\r
     }\r
 \r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 \r
     return result;\r
 }\r
@@ -789,9 +789,9 @@ UInteger Dictionary::count()
     DebugLog2("Dictionary::count()");\r
 \r
     UInteger result = 0;\r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
     result = _dict.size();\r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
     return result;\r
 }\r
 \r
@@ -904,7 +904,7 @@ bool Dictionary::writeToFile(String *path, bool atomically)
 {\r
     DebugLog2("Dictionary::writeToFile(path,atomically)");\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
 \r
     const char *outfile = path->cString();\r
     int fd = -1;\r
@@ -939,7 +939,7 @@ bool Dictionary::writeToFile(String *path, bool atomically)
     close(fd);\r
 #endif\r
 \r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 \r
     return true;\r
 }\r
@@ -1034,7 +1034,7 @@ std::string Dictionary::toString()
 {\r
     DebugLog2("Dictionary::toString()");\r
 \r
-    OBJC_LOCK(this);\r
+    RaymLock(this);\r
 \r
     std::string result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";\r
     result += "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";\r
@@ -1042,7 +1042,7 @@ std::string Dictionary::toString()
     result += toString(0);\r
     result += "</plist>\n";\r
 \r
-    OBJC_UNLOCK(this);\r
+    RaymUnlock(this);\r
 \r
     return result;\r
 }\r
index d51d7bb..0bf363b 100644 (file)
@@ -49,12 +49,12 @@ Lock *Lock::autorelease()
 
 void Lock::lock()
 {
-    OBJC_LOCK(this);
+    RaymLock(this);
 }
 
 void Lock::unlock()
 {
-    OBJC_UNLOCK(this);
+    RaymUnlock(this);
 }
 
 const char *Lock::className()
index d4e5010..7579f6b 100644 (file)
 namespace Raym
 {
 
-#ifdef OBJC_MEMORY_CHECK
-int global_objc_count_ = 0;
-int global_objc_init_count_ = 0;
-int global_objc_retain_count_ = 0;
-int global_objc_autorelease_count_ = 0;
-int global_objc_release_count_ = 0;
+#ifdef RAYM_MEMORY_CHECK
+int global_raym_count_ = 0;
+int global_raym_init_count_ = 0;
+int global_raym_retain_count_ = 0;
+int global_raym_autorelease_count_ = 0;
+int global_raym_release_count_ = 0;
 DEFINE_STATIC_MUTEX(global_lock_);
 #endif
 
@@ -24,26 +24,26 @@ Object::Object()
 {
     DebugLog2("Object::Object()");
 
-    OBJC_LOCK_CREATE;
+    RAYM_LOCK_CREATE;
 
     _retainCount = 1;
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-    ++global_objc_count_;
-//    DebugLog0("C:0x%08x:%d", this, global_objc_count_);
+    ++global_raym_count_;
+//    DebugLog0("C:0x%08x:%d", this, global_raym_count_);
     global_lock_.unlock();
 #endif
 }
 
 Object::~Object()
 {
-    OBJC_LOCK_DESTROY;
+    RAYM_LOCK_DESTROY;
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-//    DebugLog0("D:0x%08x:%d", this, global_objc_count_);
-    --global_objc_count_;
+//    DebugLog0("D:0x%08x:%d", this, global_raym_count_);
+    --global_raym_count_;
     global_lock_.unlock();
 #endif
 
@@ -61,9 +61,9 @@ Object *Object::init()
 {
     DebugLog2("Object::init()");
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-    ++global_objc_init_count_;
+    ++global_raym_init_count_;
     global_lock_.unlock();
 #endif
 
@@ -74,13 +74,13 @@ Object *Object::retain()
 {
     DebugLog2("Object::retain()");
 
-    OBJC_LOCK(this);
+    RaymLock(this);
     ++_retainCount;
-    OBJC_UNLOCK(this);
+    RaymUnlock(this);
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-    ++global_objc_retain_count_;
+    ++global_raym_retain_count_;
     global_lock_.unlock();
 #endif
 
@@ -91,9 +91,9 @@ Object *Object::autorelease()
 {
     DebugLog2("Object::autorelease()");
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-    ++global_objc_autorelease_count_;
+    ++global_raym_autorelease_count_;
     global_lock_.unlock();
 #endif
 
@@ -105,9 +105,9 @@ Object *Object::autorelease(bool rootPool)
 {
     DebugLog2("Object::autorelease()");
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-    ++global_objc_autorelease_count_;
+    ++global_raym_autorelease_count_;
     global_lock_.unlock();
 #endif
 
@@ -119,19 +119,19 @@ void Object::release()
 {
     DebugLog2("Object::release()");
 
-#ifdef OBJC_MEMORY_CHECK
+#ifdef RAYM_MEMORY_CHECK
     global_lock_.lock();
-    ++global_objc_release_count_;
+    ++global_raym_release_count_;
     global_lock_.unlock();
 #endif
 
-    OBJC_LOCK(this);
+    RaymLock(this);
     if (_retainCount > 0)
     {
         --_retainCount;
         if (_retainCount == 0)
         {
-            OBJC_UNLOCK(this);
+            RaymUnlock(this);
             delete this;
             return;
         }
@@ -141,7 +141,7 @@ void Object::release()
         DebugLog0("object is already released. (0x%016lx)", this);
         abort();
     }
-    OBJC_UNLOCK(this);
+    RaymUnlock(this);
 }
 
 String *Object::description()
index c06db9c..0c39a12 100644 (file)
@@ -4,7 +4,7 @@
 \r
 #pragma once\r
 \r
-#define OBJC_MEMORY_CHECK\r
+#define RAYM_MEMORY_CHECK\r
 \r
 #ifdef _WIN32\r
 #include <windows.h>\r
 \r
 #ifdef _WIN32\r
 \r
-#define OBJC_LOCK_CREATE    InitializeCriticalSection(&_cs)\r
-#define OBJC_LOCK_DESTROY   DeleteCriticalSection(&_cs)\r
-/*\r
-#define OBJC_LOCK(OBJ) \\r
-    DebugLog4("ECS_B:[0x%08X:0x%08X] %s() at %d\n", (unsigned int)(OBJ), GetCurrentThreadId(), __FUNCTION__, __LINE__); \\r
-    EnterCriticalSection(&(OBJ)->_cs); \\r
-    DebugLog4("ECS_A:[0x%08X:0x%08X] %s() at %d\n", (unsigned int)(OBJ), GetCurrentThreadId(), __FUNCTION__, __LINE__);\r
-\r
-#define OBJC_UNLOCK(OBJ) \\r
-    DebugLog4("LCS_B:[0x%08X:0x%08X] %s() at %d\n", (unsigned int)(OBJ), GetCurrentThreadId(), __FUNCTION__, __LINE__); \\r
-    LeaveCriticalSection(&(OBJ)->_cs); \\r
-    DebugLog4("LCS_A:[0x%08X:0x%08X] %s() at %d\n", (unsigned int)(OBJ), GetCurrentThreadId(), __FUNCTION__, __LINE__);\r
-*/\r
+#define RAYM_LOCK_CREATE    InitializeCriticalSection(&_cs)\r
+#define RAYM_LOCK_DESTROY   DeleteCriticalSection(&_cs)\r
 \r
 #define DEFINE_STATIC_MUTEX(variable)       \\r
 class STATIC_MUTEX_variable                 \\r
@@ -80,27 +69,27 @@ static STATIC_MUTEX_variable variable;
 \r
 #else\r
 \r
-#define OBJC_LOCK_CREATE    {                                   \\r
+#define RAYM_LOCK_CREATE    {                                   \\r
     pthread_mutexattr_t attr;                                   \\r
     pthread_mutexattr_init(&attr);                              \\r
     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);  \\r
     pthread_mutex_init(&_lock, &attr);                          \\r
 }\r
-#define OBJC_LOCK_DESTROY   pthread_mutex_destroy(&_lock)\r
-#define OBJC_LOCK           pthread_mutex_lock(&_lock)\r
-#define OBJC_UNLOCK         pthread_mutex_unlock(&_lock)\r
+#define RAYM_LOCK_DESTROY   pthread_mutex_destroy(&_lock)\r
+#define RAYM_LOCK           pthread_mutex_lock(&_lock)\r
+#define RAYM_UNLOCK         pthread_mutex_unlock(&_lock)\r
 \r
 #endif\r
 \r
 namespace Raym\r
 {\r
 \r
-#ifdef OBJC_MEMORY_CHECK\r
-extern int global_objc_count_;\r
-extern int global_objc_init_count_;\r
-extern int global_objc_retain_count_;\r
-extern int global_objc_autorelease_count_;\r
-extern int global_objc_release_count_;\r
+#ifdef RAYM_MEMORY_CHECK\r
+extern int global_raym_count_;\r
+extern int global_raym_init_count_;\r
+extern int global_raym_retain_count_;\r
+extern int global_raym_autorelease_count_;\r
+extern int global_raym_release_count_;\r
 #endif\r
 \r
 typedef unsigned int    uint;\r
@@ -137,11 +126,11 @@ public:
 //    virtual const char *className() = 0;\r
     virtual const char *className();\r
 \r
-    friend void OBJC_LOCK(Object *);\r
-    friend void OBJC_UNLOCK(Object *);\r
+    friend void RaymLock(Object *);\r
+    friend void RaymUnlock(Object *);\r
 };\r
 \r
-inline void OBJC_LOCK(Object *obj)\r
+inline void RaymLock(Object *obj)\r
 {\r
 #ifdef _WIN32\r
     EnterCriticalSection(&(obj->_cs));\r
@@ -149,7 +138,7 @@ inline void OBJC_LOCK(Object *obj)
 #endif\r
 }\r
 \r
-inline void OBJC_UNLOCK(Object *obj)\r
+inline void RaymUnlock(Object *obj)\r
 {\r
 #ifdef _WIN32\r
     LeaveCriticalSection(&(obj->_cs));\r
@@ -157,5 +146,7 @@ inline void OBJC_UNLOCK(Object *obj)
 #endif\r
 }\r
 \r
+#define RaymCriticalSection(OBJ, BLOCK) RaymLock(OBJ); BLOCK; RaymUnlock(OBJ);\r
+\r
 } // Raym\r
 \r
index 34968e1..14feb2a 100644 (file)
@@ -5,7 +5,6 @@
 #pragma once
 
 #include <Raym/Object.h>
-#include <Raym/Object.h>
 #include <Raym/AutoreleasePool.h>
 #include <Raym/String.h>
 #include <Raym/Dictionary.h>
@@ -21,7 +20,6 @@
 #include <Raym/InputStream.h>
 #include <Raym/FileInputStream.h>
 #include <Raym/RunningApplication.h>
-
 #include <Raym/Application.h>
 
 namespace Raym
index 4b1f21e..08b5d03 100644 (file)
@@ -22,8 +22,6 @@ namespace ry0
 namespace iPTd\r
 {\r
 \r
-static const char * PLIST_PREFIX = "com.gmail.tim.and.pom";\r
-\r
 // プロパティデフォルト値\r
 static const char * DEF_NAME                = "iPTd_R2";\r
 static const char * DEF_HOSTNAME            = "localhost";\r
@@ -47,11 +45,7 @@ static const TimeInterval DEF_COLLECT_EPG_RETRY    = 60.0;
 static const TimeInterval DEF_COLLECT_EPG_LIMIT_S  = 10.5;\r
 static const TimeInterval DEF_COLLECT_EPG_LIMIT_T  = 20.5;\r
 \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_SUPPRESSION_TIME  = -600;     // 録画開始前に休止の抑制を開始する時間(秒単位)\r
-\r
+const char *Controller::_plist_prefix = "com.gmail.tim.and.pom";\r
 \r
 #ifndef _WIN32\r
 #pragma mark '\r
@@ -987,7 +981,6 @@ int Controller::start()
     _status             = NULL;\r
     _epgs_path          = NULL;\r
     _epgs               = NULL;\r
-    _store_path         = NULL;\r
 \r
     _timer_restart      = NULL;\r
     _timer_periodic     = NULL;\r
@@ -1038,7 +1031,7 @@ int Controller::start()
         DebugLog2("_system_path: %s\n", _system_path->cString());\r
 \r
         // プロパティファイルのパス設定\r
-        _props_path = String::alloc()->initWithFormat("%s%s.iptd.plist", _system_path->cString(), PLIST_PREFIX);\r
+        _props_path = String::alloc()->initWithFormat("%s%s.iptd.plist", _system_path->cString(), _plist_prefix);\r
         if (_props_path == NULL)\r
         {\r
             DebugLog0("error: set property file path.\n");\r
@@ -1059,7 +1052,7 @@ int Controller::start()
         }\r
 \r
         // ステータスファイルのパス設定\r
-        _status_path = String::alloc()->initWithFormat("%s%s.iptd.status.plist", _system_path->cString(), PLIST_PREFIX);\r
+        _status_path = String::alloc()->initWithFormat("%s%s.iptd.status.plist", _system_path->cString(), _plist_prefix);\r
         if (_status_path == NULL)\r
         {\r
             DebugLog0("error: set status file path.\n");\r
@@ -1203,16 +1196,57 @@ int Controller::start()
             updated = true;\r
         }\r
 \r
+        // 録画データ格納先の確認\r
+        if (_props->stringForKey(KEY_STORE_PATH) ==  NULL)\r
+        {\r
+            // プロパティに未設定の場合\r
+            //   <Public Directory>/Videos を設定\r
+            const char *public_dir = GetPublicDirectory();\r
+            if (public_dir == NULL)\r
+            {\r
+                DebugLog0("error: GetPublicDirectory().");\r
+                result = -1;\r
+                break;\r
+            }\r
+            _props->setString(String::alloc()->initWithFormat("%s\\Videos", public_dir), KEY_STORE_PATH);\r
+\r
+            // 更新フラグ\r
+            updated = true;\r
+        }\r
+\r
+        // 実際にディレクトリが存在しているか確認\r
+        FileManager *fm = FileManager::defaultManager();\r
+        bool isDir = false;\r
+        if (!fm->fileExistsAtPath(_props->stringForKey(KEY_STORE_PATH), &isDir))\r
+        {\r
+            isDir = false;\r
+        }\r
+        if (!isDir)\r
+        {\r
+            DebugLog0("error: \"%s\" is not exists.", _props->stringForKey(KEY_STORE_PATH)->cString());\r
+            result = -1;\r
+            break;\r
+        }\r
+\r
         //\r
-        _reservation = Reservation::alloc()->initWithController(this, String::stringWithFormat("%s%s.iptd.reservations.plist", _system_path->cString(), PLIST_PREFIX));\r
+        _reservation = Reservation::alloc()->initWithController(this);\r
+        if (_reservation == NULL)\r
+        {\r
+            result = -1;\r
+            break;\r
+        }\r
 \r
         //\r
         _streaming = Streaming::alloc()->initWithController(this);\r
+        if (_streaming == NULL)\r
+        {\r
+            result = -1;\r
+            break;\r
+        }\r
 \r
         // httpdのルートパス\r
         String *rootPath = _system_path->stringByAppendingPathComponent("html");\r
-        FileManager *fm = FileManager::defaultManager();\r
-        bool isDir = false;\r
+        isDir = false;\r
         if (!fm->fileExistsAtPath(rootPath, &isDir))\r
         {\r
             isDir = false;\r
@@ -1227,7 +1261,12 @@ int Controller::start()
         }\r
 \r
         //\r
-        _httpd = HTTPDaemon::alloc()->initWithController(this, _props->integerForKey(KEY_HTTP_PORT), rootPath);\r
+        _httpd = HTTPD::alloc()->initWithController(this, _props->integerForKey(KEY_HTTP_PORT), rootPath);\r
+        if (_httpd == NULL)\r
+        {\r
+            result = -1;\r
+            break;\r
+        }\r
 \r
 \r
         // プロパティファイルを保存\r
@@ -1337,7 +1376,6 @@ int Controller::start()
     RELEASE(_status);\r
     RELEASE(_epgs_path);\r
     RELEASE(_epgs);\r
-    RELEASE(_store_path);\r
 \r
     RELEASE(_reservation);\r
     RELEASE(_streaming);\r
index 2f8a5c5..afa6df4 100644 (file)
@@ -31,9 +31,12 @@ typedef struct _stat STAT;
 class Controller : public Raym::Application,\r
                    public Raym::TimerDelegate\r
 {\r
-private:\r
-//    CRITICAL_SECTION    _cs;\r
+protected:\r
+    Controller();\r
+    ~Controller();\r
 \r
+public:\r
+    static const char * _plist_prefix;\r
     Raym::String *      _system_path;           // システムパス(実行ファイルが配置されているディレクトリ)\r
     Raym::String *      _props_path;            // プロパティファイルのパス\r
     Raym::Dictionary *  _props;                 // プロパティ\r
@@ -41,7 +44,6 @@ private:
     Raym::Dictionary *  _status;                // ステータス\r
     Raym::String *      _epgs_path;             // 番組データファイルのパス\r
     Raym::Dictionary *  _epgs;                  // 番組データ\r
-    Raym::String *      _store_path;            // 録画データ格納先\r
     int                 _idle_count;            // アイドルカウンタ\r
 \r
     // 非同期処理用タイマ\r
@@ -53,22 +55,17 @@ private:
 \r
     Reservation *       _reservation;           // 予約録画制御\r
     Streaming *         _streaming;             // ストリーミング制御\r
-    HTTPDaemon *        _httpd;                 // HTTP制御\r
+    HTTPD *             _httpd;                 // HTTP制御\r
 \r
     bool                            _initialized;           // 初期化済み\r
     HMODULE                         _multi2_dll;\r
     bool                            _cancel_epg_collect;    // EPG収集キャンセル\r
 \r
 \r
-public:\r
     int                             _tunerCount;\r
     ry0::device::Tuner *            _tuners[ry0::device::MAX_TUNERS];\r
 \r
-protected:\r
-    Controller();\r
-    ~Controller();\r
 \r
-public:\r
     static Controller *alloc();\r
     int restart();\r
 \r
index 70ba295..99b4bce 100644 (file)
 #include "ry0/iPTd/Controller.h"\r
 \r
 using namespace Raym;\r
+using namespace NET;\r
 \r
 namespace ry0\r
 {\r
 namespace iPTd\r
 {\r
 \r
-HTTPDaemon::HTTPDaemon()\r
+HTTPD::HTTPD()\r
 {\r
     _controller = NULL;\r
     _httpd      = NULL;\r
@@ -27,7 +28,7 @@ HTTPDaemon::HTTPDaemon()
     _path       = NULL;\r
 }\r
 \r
-HTTPDaemon::~HTTPDaemon()\r
+HTTPD::~HTTPD()\r
 {\r
     RELEASE(_httpd);\r
     RELEASE(_path);\r
@@ -35,12 +36,12 @@ HTTPDaemon::~HTTPDaemon()
     _controller = NULL;\r
 }\r
 \r
-HTTPDaemon *HTTPDaemon::alloc()\r
+HTTPD *HTTPD::alloc()\r
 {\r
-    return new HTTPDaemon();\r
+    return new HTTPD();\r
 }\r
 \r
-HTTPDaemon *HTTPDaemon::initWithController(Controller *controller, int port, String *path)\r
+HTTPD *HTTPD::initWithController(Controller *controller, int port, String *path)\r
 {\r
     _controller = controller;\r
     _port = port;\r
@@ -49,23 +50,23 @@ HTTPDaemon *HTTPDaemon::initWithController(Controller *controller, int port, Str
     return this;\r
 }\r
 \r
-bool HTTPDaemon::start()\r
+bool HTTPD::start()\r
 {\r
     if (_httpd == NULL)\r
     {\r
-        _httpd = NET::HTTPDaemon::alloc()->initWithPort(_port, 10);\r
+        _httpd = HTTPDaemon::alloc()->initWithPort(_port, 10);\r
         _httpd->setRootPath(_path);\r
         _httpd->setDelegate(this);\r
     }\r
     return _httpd->start();\r
 }\r
 \r
-void HTTPDaemon::stop()\r
+void HTTPD::stop()\r
 {\r
     _httpd->stop();\r
 }\r
 \r
-NET::HTTPResponse *HTTPDaemon::request(NET::HTTPRequest *request, struct sockaddr_in *client)\r
+HTTPResponse *HTTPD::request(HTTPRequest *request, SOCKADDR_IN *client)\r
 {\r
     DebugLog2("%s\n", __FUNCTION__);\r
 \r
@@ -79,7 +80,7 @@ NET::HTTPResponse *HTTPDaemon::request(NET::HTTPRequest *request, struct sockadd
 //        return NULL;\r
     }\r
 \r
-    NET::HTTPResponse *response = NULL;\r
+    HTTPResponse *response = NULL;\r
 \r
     if (request->method()->isEqualToString("GET") ||\r
         request->method()->isEqualToString("HEAD"))\r
@@ -87,11 +88,517 @@ NET::HTTPResponse *HTTPDaemon::request(NET::HTTPRequest *request, struct sockadd
         // URI\r
         String *uri = request->URI();\r
         DebugLog0("request: %s\n", uri->cString());\r
+        if (uri->isMatch("^/config.xml$"))\r
+        {\r
+            RaymCriticalSection(_controller,\r
+            {\r
+                response = responseWithDictionary(request, _controller->_props);\r
+            });\r
+        }\r
+        else if (uri->isMatch("^/status.xml$"))\r
+        {\r
+            RaymCriticalSection(_controller,\r
+            {\r
+                response = responseWithDictionary(request, _controller->_status);\r
+            });\r
+        }\r
+        //\r
+        // tuner control\r
+        //\r
+        else if (uri->isMatch("^/[0-9]{3}/"))\r
+        {\r
+            // String::substringWithRange() の実装は後回しなので。。\r
+            std::string s = uri->cString();\r
+            int tuner = atoi(s.substr(1, 3).c_str());\r
+            if ((0 <= tuner) && (tuner < _controller->_tunerCount))\r
+            {\r
+                response = requestTunerControl(request, client, tuner);\r
+            }\r
+        }\r
     }\r
 \r
-\r
     return response;\r
 }\r
 \r
+HTTPResponse *HTTPD::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner)\r
+{\r
+    DebugLog0("%s\n", __FUNCTION__);\r
+\r
+    HTTPResponse *result = NULL;\r
+\r
+    // lock\r
+    RaymLock(_controller);\r
+\r
+    // URI取得\r
+    String *uri = request->URI();\r
+    while (uri != NULL)\r
+    {\r
+        // CGIリクエストとして解析\r
+        Dictionary *cgi = request->parseAsCGI();\r
+        if (cgi != NULL)\r
+        {\r
+            uri = cgi->stringForKey(HTTPRequest::KEY_CGI);\r
+            if (uri == NULL)\r
+            {\r
+                break;\r
+            }\r
+        }\r
+\r
+        //\r
+        // チャンネル設定\r
+        //   /ttt/channel=nnn\r
+        //\r
+        if (uri->isMatch("^/[0-9]{3}/channel=[0-9]{1,3}$") && (cgi == NULL))\r
+        {\r
+            String *ch = uri->substringFromIndex(13);\r
+            if (ch == NULL)\r
+            {\r
+                break;\r
+            }\r
+            int channel = ch->intValue();\r
+            DebugLog2("set channel:%d(%s)\n", channel, ch->cString());\r
+            if (_controller->setChannel(tuner, channel))\r
+            {\r
+                // success\r
+                DebugLog2("success.\n");\r
+                result = responseForSuccess(request);\r
+            }\r
+            else\r
+            {\r
+                // failed\r
+                DebugLog2("failed.\n");\r
+                result = responseForFailed(request);\r
+            }\r
+        }\r
+\r
+        //\r
+        // 録画開始(最大23:59まで)\r
+        //   /ttt/recording=on?hour=hh&min=mm[&channel=nnn]\r
+        //\r
+        else if (uri->isMatch("^/[0-9]{3}/recording=on$") && (cgi != NULL))\r
+        {\r
+            // パラメータがあるか\r
+            Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);\r
+            if (params == NULL)\r
+            {\r
+                break;\r
+            }\r
+\r
+            // パラメータ数は2〜3か\r
+            if ((params->count() != 2) && (params->count() != 3))\r
+            {\r
+                break;\r
+            }\r
+\r
+            // パラメータのチェック\r
+            String *p_hour    = NULL;\r
+            String *p_min     = NULL;\r
+            String *p_channel = NULL;\r
+\r
+            struct {\r
+                const char *name;\r
+                String **variable;\r
+                const char *regex;\r
+            }\r
+            cgi[] =\r
+            {\r
+                {"hour",    &p_hour,    "^[0-2][0-9]$"},\r
+                {"min",     &p_min,     "^[0-5][0-9]$"},\r
+                {"channel", &p_channel, "^[0-9]{3}$"},\r
+                {NULL, NULL, NULL}\r
+            };\r
+\r
+            for (uint i = 0; cgi[i].name != NULL; ++i)\r
+            {\r
+                *(cgi[i].variable) = NULL;\r
+                for (uint j = 0; j < params->count(); ++j)\r
+                {\r
+                    Dictionary *param = (Dictionary *)params->objectAtIndex(j);\r
+                    String *value = param->stringForKey(cgi[i].name);\r
+                    if ((value != NULL) && value->isMatch(cgi[i].regex))\r
+                    {\r
+                        *(cgi[i].variable) = value;\r
+                    }\r
+                }\r
+            }\r
+\r
+            // パラメータは有効か\r
+            if ((p_hour == NULL) || (p_min == NULL))\r
+            {\r
+                break;\r
+            }\r
+\r
+            // チャンネル設定\r
+            int channel = 0;\r
+            if (p_channel != NULL)\r
+            {\r
+                channel = p_channel->intValue();\r
+            }\r
+            else\r
+            {\r
+                channel = _controller->_tuners[tuner]->channel();\r
+            }\r
+\r
+            if (channel >= 0)\r
+            {\r
+                // recording on\r
+                int hour = p_hour->intValue();\r
+                int min = p_min->intValue();\r
+                if (hour < 24)\r
+                {\r
+                    // EPG生成\r
+                    Dictionary *epg = Dictionary::dictionaryWithCapacity(0);\r
+                    while (true)\r
+                    {\r
+                        time_t now;\r
+                        time(&now);\r
+                        now += 1; // margin\r
+                        TM tm;\r
+                        if (localtime_s(&tm, &now) != 0)\r
+                        {\r
+                            epg = NULL;\r
+                            break;\r
+                        }\r
+                        TM end;\r
+                        end = tm;\r
+                        end.tm_hour += hour;\r
+                        end.tm_min += min;\r
+                        end.tm_sec += 1; // margin\r
+                        if (mktime(&end) == -1)\r
+                        {\r
+                            epg = NULL;\r
+                            break;\r
+                        }\r
+\r
+                        char tmp[16];\r
+\r
+                        // Date\r
+                        sprintf_s(tmp, sizeof(tmp), "%04d/%02d/%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);\r
+                        epg->setString(tmp, KEY_EPG_DATE);\r
+\r
+                        // Start\r
+                        sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);\r
+                        epg->setString(tmp, KEY_EPG_START);\r
+\r
+                        // End\r
+                        sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", end.tm_hour, end.tm_min, end.tm_sec);\r
+                        epg->setString(tmp, KEY_EPG_END);\r
+\r
+                        // Channel\r
+                        sprintf_s(tmp, sizeof(tmp), "%d", channel);\r
+                        epg->setString(tmp, KEY_EPG_CHANNEL);\r
+\r
+                        // 繰り返し\r
+                        epg->setString("off", KEY_EPG_REPEAT); \r
+\r
+                        // Status\r
+                        epg->setString("ready", KEY_EPG_STATUS);\r
+\r
+                        break;\r
+                    }\r
+                \r
+                    if (epg != NULL)\r
+                    {\r
+                        // 録画開始&結果生成\r
+                        if (_controller->_reservation->reserve(tuner, epg))\r
+                        {\r
+                            result = responseForSuccess(request);\r
+                        }\r
+                        else\r
+                        {\r
+                            result = responseForFailed(request);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        //\r
+        // 録画停止\r
+        //   /ttt/recording=off\r
+        //\r
+        else if (uri->isMatch("^/[0-9]{3}/recording=off$") && (cgi == NULL))\r
+        {\r
+            // recording off\r
+            DebugLog2("recording off: %s\n", uri->cString());\r
+            if (_controller->_reservation->cancel(tuner, -1))\r
+            {\r
+                // success\r
+                DebugLog2("success.\n");\r
+                result = responseForSuccess(request);\r
+            }\r
+            else\r
+            {\r
+                // failed\r
+                DebugLog2("failed.\n");\r
+                result = responseForFailed(request);\r
+            }\r
+        }\r
+\r
+        //\r
+        // ストリーミング開始\r
+        //   /ttt/streaming=on?udp=nnnnn(&host=aaaaaa)\r
+        //\r
+        else if (uri->isMatch("^/[0-9]{3}/streaming=on$") && (cgi != NULL))\r
+        {\r
+            // パラメータがあるか\r
+            Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);\r
+            if (params == NULL)\r
+            {\r
+                break;\r
+            }\r
+\r
+            // パラメータ数は1〜2か\r
+            if ((params->count() != 1) && (params->count() != 2))\r
+            {\r
+                break;\r
+            }\r
+\r
+            // パラメータのチェック\r
+            String *p_udp  = NULL;\r
+            String *p_host = NULL;\r
+\r
+            struct {\r
+                const char *name;\r
+                String **variable;\r
+                const char *regex;\r
+            }\r
+            cgi[] =\r
+            {\r
+                {"udp",  &p_udp,  "^[0-9]{1,5}$"},\r
+                {"host", &p_host, "^.+$"},\r
+                {NULL, NULL, NULL}\r
+            };\r
+\r
+            for (uint i = 0; cgi[i].name != NULL; ++i)\r
+            {\r
+                *(cgi[i].variable) = NULL;\r
+                for (uint j = 0; j < params->count(); ++j)\r
+                {\r
+                    Dictionary *param = (Dictionary *)params->objectAtIndex(j);\r
+                    String *value = param->stringForKey(cgi[i].name);\r
+                    if ((value != NULL) && value->isMatch(cgi[i].regex))\r
+                    {\r
+                        *(cgi[i].variable) = value;\r
+                    }\r
+                }\r
+            }\r
+\r
+            // パラメータチェック\r
+            if (p_udp == NULL)\r
+            {\r
+                break;\r
+            }\r
+\r
+            SOCKADDR_IN dst_addr;\r
+            \r
+            if (p_host != NULL)\r
+            {\r
+    #if 0\r
+                std::string host = udpstr.substr(idx + 5);\r
+                udpstr = udpstr.substr(0, idx - 1);\r
+                DebugLog2("udp: %s\n", udpstr.c_str());\r
+                DebugLog2("host: %s\n", host.c_str());\r
+                struct hostent *ent = gethostbyname(host.c_str());\r
+    #endif\r
+            }\r
+            else\r
+            {\r
+                memcpy(&dst_addr, client, sizeof(SOCKADDR_IN));\r
+            }\r
+            dst_addr.sin_port = htons(p_udp->intValue());\r
+            \r
+            if (_controller->_tuners[tuner]->startStreaming(&dst_addr))\r
+            {\r
+                // success\r
+                DebugLog2("success.\n");\r
+                result = responseForSuccess(request);\r
+            }\r
+            else\r
+            {\r
+                // failed\r
+                DebugLog2("failed.\n");\r
+                result = responseForFailed(request);\r
+            }\r
+        }\r
+\r
+        //\r
+        // ストリーミング停止\r
+        //   /ttt/streaming=off(?host=aaaa)\r
+        //\r
+        else if (uri->isMatch("^/[0-9]{3}/streaming=off$"))\r
+        {\r
+            // パラメータ\r
+            String *p_host = NULL;\r
+\r
+            // パラメータがあるか\r
+            if (cgi != NULL)\r
+            {\r
+                Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);\r
+                if (params == NULL)\r
+                {\r
+                    break;\r
+                }\r
+\r
+                // パラメータ数は0〜1か\r
+                if ((params->count() != 0) && (params->count() != 1))\r
+                {\r
+                    break;\r
+                }\r
+\r
+                struct {\r
+                    const char *name;\r
+                    String **variable;\r
+                    const char *regex;\r
+                }\r
+                cgi[] =\r
+                {\r
+                    {"host", &p_host, "^.+$"},\r
+                    {NULL, NULL, NULL}\r
+                };\r
+\r
+                for (uint i = 0; cgi[i].name != NULL; ++i)\r
+                {\r
+                    *(cgi[i].variable) = NULL;\r
+                    for (uint j = 0; j < params->count(); ++j)\r
+                    {\r
+                        Dictionary *param = (Dictionary *)params->objectAtIndex(j);\r
+                        String *value = param->stringForKey(cgi[i].name);\r
+                        if ((value != NULL) && value->isMatch(cgi[i].regex))\r
+                        {\r
+                            *(cgi[i].variable) = value;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+\r
+            SOCKADDR_IN dst_addr;\r
+            if (p_host != NULL)\r
+            {\r
+            }\r
+            else\r
+            {\r
+            }\r
+\r
+            _controller->_tuners[tuner]->stopStreaming();\r
+            \r
+            // success\r
+            DebugLog2("success.\n");\r
+            result = responseForSuccess(request);\r
+        }\r
+\r
+        //\r
+        // HLS制御\r
+        //\r
+        else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming(-[^\\.]+)?.m3u8$") && (cgi == NULL))\r
+        {\r
+            DebugLog0("uri: %s", uri->cString());\r
+/*\r
+            // URIからチャンネル番号を抽出\r
+            //   Range実装したい...\r
+            int ch = uri->substringFromIndex(5)->substringToIndex(3)->intValue();\r
+            DebugLog0("ch: %d", ch);\r
+\r
+            // presetが指定されている場合、presetを抽出\r
+            String *preset = NULL;\r
+            if (uri->isMatch("streaming-"))\r
+            {\r
+                preset = uri->substringFromIndex(19);\r
+                preset = preset->substringToIndex(preset->length() - 5);\r
+                DebugLog0("opt: preset: %s", preset->cString());\r
+            }\r
+            else\r
+            {\r
+                // なければ "default"\r
+                preset = NSString::stringWithUTF8String(KEY_DEFAULT);\r
+            }\r
+\r
+            // チャンネル/presetが有効か確認\r
+            if (isChannelEnabled(tuner, ch) &&\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
+            }\r
+            else\r
+            {\r
+                result = responseForFailed(request);\r
+            }\r
+            DebugLog0("hls req. done");\r
+*/\r
+        }\r
+        else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming-[0-9]+.ts$") && (cgi == NULL))\r
+        {\r
+            // 分割されたTS\r
+            DebugLog0("uri: %s", uri->cString());\r
+        }\r
+\r
+        break;\r
+    }\r
+\r
+    // unlock\r
+    RaymUnlock(_controller);\r
+\r
+    return result;\r
+}\r
+\r
+// positive response by XML\r
+HTTPResponse *HTTPD::responseForSuccess(HTTPRequest *request)\r
+{\r
+    Dictionary *dict = Dictionary::dictionaryWithCapacity(0);\r
+    dict->setString("Success", KEY_RESULT);\r
+    return responseWithDictionary(request, dict);\r
+}\r
+\r
+// negative response by XML\r
+HTTPResponse *HTTPD::responseForFailed(HTTPRequest *request)\r
+{\r
+    Dictionary *dict = Dictionary::dictionaryWithCapacity(0);\r
+    dict->setString("Failed", KEY_RESULT);\r
+    return responseWithDictionary(request, dict);\r
+}\r
+\r
+HTTPResponse *HTTPD::responseWithDictionary(HTTPRequest *request, Dictionary *dictionary)\r
+{\r
+    HTTPResponse *result = NULL;\r
+    if ((request != NULL) && (dictionary != NULL))\r
+    {\r
+        std::string xml = dictionary->toString();\r
+\r
+        // header\r
+        InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();\r
+        // Date\r
+        // Server\r
+        // Content-Encoding\r
+        // Last-Modified\r
+        // Content-Type\r
+        header->setFieldBodyWithName("application/xml", "Content-Type");\r
+        // Connection\r
+        // Tranfer-Encoding\r
+        // Content-Length\r
+        header->setFieldBodyWithName(String::stringWithFormat("%I64u", xml.length()), "Content-Length");\r
+\r
+        // body\r
+        InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(xml.c_str()));\r
+\r
+        // message\r
+        InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);\r
+        RELEASE(header);\r
+        RELEASE(body);\r
+        if (message != NULL)\r
+        {\r
+            result = HTTPResponse::alloc()->init();\r
+            result->autorelease();\r
+            result->setVersion(request->version());\r
+            result->setReason(NET::HTTPDaemon::reasonForStatus(200));\r
+            result->setStatus(200);\r
+            result->setMessage(message);\r
+            RELEASE(message);\r
+        }\r
+    }\r
+    return result;\r
+}\r
+\r
 } // iPTd\r
 } // ry0\r
index f0c6060..8403df0 100644 (file)
@@ -15,8 +15,8 @@ namespace iPTd
 \r
 class Controller;\r
 \r
-class HTTPDaemon : public Raym::Object,\r
-                   public NET::HTTPDaemonDelegate\r
+class HTTPD : public Raym::Object,\r
+              public NET::HTTPDaemonDelegate\r
 {\r
 private:\r
     Controller *        _controller;\r
@@ -25,17 +25,23 @@ private:
     Raym::String *      _path;\r
 \r
 protected:\r
-    HTTPDaemon();\r
-    ~HTTPDaemon();\r
+    HTTPD();\r
+    ~HTTPD();\r
 \r
 public:\r
-    static HTTPDaemon *alloc();\r
-    HTTPDaemon *initWithController(Controller *controller, int port, Raym::String *path);\r
+    static HTTPD *alloc();\r
+    HTTPD *initWithController(Controller *controller, int port, Raym::String *path);\r
 \r
     bool start();\r
     void stop();\r
 \r
     NET::HTTPResponse *request(NET::HTTPRequest *request, struct sockaddr_in *client);\r
+    NET::HTTPResponse *requestTunerControl(NET::HTTPRequest *request, struct sockaddr_in *client, int tuner);\r
+\r
+\r
+    static NET::HTTPResponse *responseForSuccess(NET::HTTPRequest *request);\r
+    static NET::HTTPResponse *responseForFailed(NET::HTTPRequest *request);\r
+    static NET::HTTPResponse *responseWithDictionary(NET::HTTPRequest *request, Raym::Dictionary *dictionary);\r
 };\r
 \r
 \r
index a9f8189..dc00064 100644 (file)
@@ -4,6 +4,10 @@
  */\r
 \r
 #include <time.h>\r
+#include <fcntl.h>\r
+#include <io.h>\r
+#include <direct.h>\r
+\r
 \r
 #define DBG_LEVEL 3\r
 #include "Raym/Log.h"\r
@@ -19,12 +23,15 @@ namespace ry0
 namespace iPTd\r
 {\r
 \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_SUPPRESSION_TIME  = -600;     // 録画開始前に休止の抑制を開始する時間(秒単位)\r
 \r
 Reservation::Reservation()\r
 {\r
     _controller         = NULL;\r
-    _path               = NULL;\r
+    _reservations_path  = NULL;\r
     _reservations       = NULL;\r
     _reservation_seq_id = -1;\r
 }\r
@@ -32,7 +39,7 @@ Reservation::Reservation()
 Reservation::~Reservation()\r
 {\r
     _controller = NULL;\r
-    RELEASE(_path);\r
+    RELEASE(_reservations_path);\r
     RELEASE(_reservations);\r
 }\r
 \r
@@ -41,26 +48,47 @@ Reservation *Reservation::alloc()
     return new Reservation();\r
 }\r
 \r
-Reservation *Reservation::initWithController(Controller *controller, String *path)\r
+Reservation *Reservation::initWithController(Controller *controller)\r
 {\r
     _controller = controller;\r
-    _path = path->retain();\r
 \r
-    _reservations = Dictionary::alloc()->initWithContentsOfFile(_path);\r
+    _reservations_path = String::alloc()->initWithFormat("%s%s.iptd.reservations.plist", _controller->_system_path->cString(), Controller::_plist_prefix);\r
+    if (_reservations_path == NULL)\r
+    {\r
+        release();\r
+        return NULL;\r
+    }\r
+\r
+    _reservations = Dictionary::alloc()->initWithContentsOfFile(_reservations_path);\r
     if (_reservations == NULL)\r
     {\r
-        DebugLog1("because \"%s\" is not exists, created.", _path->cString());\r
+        DebugLog1("because \"%s\" is not exists, created.", _reservations_path->cString());\r
         _reservations = Dictionary::alloc()->initWithCapacity(0);\r
+        if (_reservations == NULL)\r
+        {\r
+            release();\r
+            return NULL;\r
+        }\r
         _reservation_seq_id = 1;\r
     }\r
     else\r
     {\r
-        DebugLog1("reservations file: \"%s\"", _path->cString());\r
+        DebugLog1("reservations file: \"%s\"", _reservations_path->cString());\r
 \r
         // 予約情報シーケンスID\r
         _reservation_seq_id = _reservations->integerForKey(KEY_EPG_LAST_RESV_ID);\r
     }\r
 \r
+    // 周期タイマ起動\r
+    _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, NULL, true);\r
+    if (_timer_periodic == NULL)\r
+    {\r
+        release();\r
+        return NULL;\r
+    }\r
+\r
+    _timer_periodic->fire();\r
+\r
     return this;\r
 }\r
 \r
@@ -97,5 +125,524 @@ bool Reservation::canTerminate()
     return true;\r
 }\r
 \r
+//\r
+// 録画予約:チューナ/EPG指定\r
+//\r
+bool Reservation::reserve(int tuner, Dictionary *in_epg)\r
+{\r
+    DebugLog2("Reservation::reserve(tuner, epg)");\r
+\r
+    bool result = false;\r
+\r
+    // lock\r
+    RaymLock(_controller);\r
+\r
+    while ((0 <= tuner) && (tuner < _controller->_tunerCount) && (in_epg != NULL))\r
+    {\r
+        Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg);\r
+        if (epg == NULL)\r
+        {\r
+            DebugLog3("Dictionary::dictionaryWithDictionary() ng.");\r
+            break;\r
+        }\r
+\r
+        Array *array = _reservations->arrayForKey(_controller->_tuners[tuner]->name());\r
+        if (array == NULL)\r
+        {\r
+            array = Array::arrayWithCapacity(0);\r
+            _reservations->setObject(array, _controller->_tuners[tuner]->name());\r
+        }\r
+\r
+        time_t epg_start;\r
+        time_t epg_end;\r
+        Controller::getTimeWithEPG(epg, &epg_start, &epg_end);\r
+        DebugLog2("epg start: %ld, end: %ld\n", epg_start, epg_end);\r
+\r
+        time_t pre_start = 0;\r
+        time_t pre_end = 0;\r
+        pre_end = time(NULL);\r
+        DebugLog2("pre_end: %ld", pre_end);\r
+\r
+        for (uint i = 0; i < array->count(); ++i)\r
+        {\r
+            Dictionary *cur = (Dictionary *)array->objectAtIndex(i);\r
+            time_t cur_start;\r
+            time_t cur_end;\r
+            Controller::getTimeWithEPG(cur, &cur_start, &cur_end);\r
+            DebugLog2("cur start: %ld, end: %ld\n", cur_start, cur_end);\r
+            if ((pre_end <= epg_start) && (epg_end <= cur_start))\r
+            {\r
+                DebugLog2("insert: %d\n", i);\r
+                array->insertObject(epg, i);\r
+                result = true;\r
+                break;\r
+            }\r
+            pre_start = cur_start;\r
+            pre_end = cur_end;\r
+        }\r
+\r
+        if (!result)\r
+        {\r
+            if (pre_end <= epg_start)\r
+            {\r
+                DebugLog2("add\n");\r
+                array->addObject(epg);\r
+                result = true;\r
+            }\r
+            else\r
+            {\r
+                DebugLog2("no add\n");\r
+            }\r
+        }\r
+        if (result)\r
+        {\r
+            epg->setInteger(_reservation_seq_id, KEY_EPG_RESV_ID);\r
+            _reservation_seq_id = (_reservation_seq_id + 1) % 1000000;\r
+            _reservations->setInteger(_reservation_seq_id, KEY_EPG_LAST_RESV_ID);\r
+\r
+            //\r
+            _reservations->writeToFile(_reservations_path, true);\r
+        }\r
+\r
+        break;\r
+    }\r
+\r
+    // unlock\r
+    RaymUnlock(_controller);\r
+\r
+    return result;\r
+}\r
+\r
+//\r
+// tuner: 0 - (_tunerCount - 1)  cancel current\r
+// tuner: -1  cancel reserve_id\r
+//\r
+bool Reservation::cancel(int tuner, int reserve_id)\r
+{\r
+    bool result = false;\r
+\r
+    // lock\r
+    RaymLock(_controller);\r
+\r
+    //\r
+    if ((0 <= tuner) && (tuner < _controller->_tunerCount))\r
+    {\r
+        Array *array = _reservations->arrayForKey(_controller->_tuners[tuner]->name());\r
+        if (array != NULL)\r
+        {\r
+            if (array->count() > 0)\r
+            {\r
+                Dictionary *epg = (Dictionary *)array->objectAtIndex(0);\r
+                String *status = epg->stringForKey(KEY_EPG_STATUS);\r
+                if (status != NULL)\r
+                {\r
+                    if (status->isEqualToString("running"))\r
+                    {\r
+                        epg->setString("stop", KEY_EPG_STATUS);\r
+                        result = true;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    //\r
+    else if ((tuner < 0) && (0 <= reserve_id) && (reserve_id < 1000000))\r
+    {\r
+        for (int i = 0; i < _controller->_tunerCount; ++i)\r
+        {\r
+            Array *array = _reservations->arrayForKey(_controller->_tuners[i]->name());\r
+            if (array != NULL)\r
+            {\r
+                for (uint j = 0; j < array->count(); ++j)\r
+                {\r
+                    Dictionary *epg = (Dictionary *)array->objectAtIndex(j);\r
+                    if (reserve_id == epg->integerForKey(KEY_EPG_RESV_ID))\r
+                    {\r
+                        String *status = epg->stringForKey(KEY_EPG_STATUS);\r
+                        if ((status != NULL) && status->isEqualToString("running"))\r
+                        {\r
+                            epg->setString("stop", KEY_EPG_STATUS);\r
+                        }\r
+                        else\r
+                        {\r
+                            array->removeObjectAtIndex(j);\r
+                        }\r
+                        result = true;\r
+                        break;\r
+                    }\r
+                }\r
+            }\r
+            if (result)\r
+            {\r
+                break;\r
+            }\r
+        }\r
+    }\r
+\r
+    if (result)\r
+    {\r
+        _reservations->writeToFile(_reservations_path, true);\r
+    }\r
+\r
+    // unlock\r
+    RaymUnlock(_controller);\r
+\r
+    return result;\r
+}\r
+\r
+std::string Reservation::createVideoPath(int tuner)\r
+{\r
+    DebugLog2("Reservation::createVideoPath()");\r
+\r
+    std::string result = "";\r
+\r
+    while (true)\r
+    {\r
+        time_t now;\r
+        time(&now);\r
+        TM tm;\r
+        if (localtime_s(&tm, &now) != 0)\r
+        {\r
+            break;\r
+        }\r
+\r
+        result = _controller->_props->stringForKey(KEY_STORE_PATH)->cString();\r
+        DebugLog2("result: %s\n", result.c_str());\r
+\r
+        char tmp[128];\r
+        if (sprintf_s(tmp, sizeof(tmp), "\\%04d", tm.tm_year + 1900) < 0)\r
+        {\r
+            DebugLog0("sprintf_s() error: year\n");\r
+            result = "";\r
+            break;\r
+        }\r
+        result += tmp;\r
+        DebugLog2("result: %s\n", result.c_str());\r
+\r
+        STAT stat;\r
+        if (_stat(result.c_str(), &stat) != 0)\r
+        {\r
+            if (_mkdir(result.c_str()) != 0)\r
+            {\r
+                DebugLog0("_mkdir() error: year\n");\r
+                result = "";\r
+                break;\r
+            }\r
+            _stat(result.c_str(), &stat);\r
+        }\r
+        if ((stat.st_mode & _S_IFDIR) != _S_IFDIR)\r
+        {\r
+            DebugLog0("%s is not directory.\n", result.c_str());\r
+            result = "";\r
+            break;\r
+        }\r
+\r
+        if (sprintf_s(tmp, sizeof(tmp), "\\%02d", tm.tm_mon + 1) < 0)\r
+        {\r
+            DebugLog0("sprintf_s() error: month\n");\r
+            result = "";\r
+            break;\r
+        }\r
+        result += tmp;\r
+        DebugLog2("result: %s\n", result.c_str());\r
+\r
+        if (_stat(result.c_str(), &stat) != 0)\r
+        {\r
+            if (_mkdir(result.c_str()) != 0)\r
+            {\r
+                DebugLog0("_mkdir() error: month\n");\r
+                result = "";\r
+                break;\r
+            }\r
+            _stat(result.c_str(), &stat);\r
+        }\r
+        if ((stat.st_mode & _S_IFDIR) != _S_IFDIR)\r
+        {\r
+            DebugLog0("%s is not directory.", result.c_str());\r
+            result = "";\r
+            break;\r
+        }\r
+\r
+        if (sprintf_s(tmp, sizeof(tmp),\r
+                      "\\%04d%02d%02d_%02d%02d%02d_%03d_%s.ts",\r
+                      tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,\r
+                      _controller->_tuners[tuner]->channel(), _controller->_tuners[tuner]->name()) < 0)\r
+        {\r
+            DebugLog0("sprintf_s() error: filename");\r
+            result = "";\r
+            break;\r
+        }\r
+        result += tmp;\r
+        DebugLog2("result: %s\n", result.c_str());\r
+\r
+        break;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+void Reservation::timerExpired(Timer *timer, void *userInfo)\r
+{\r
+    bool need_update = false;\r
+\r
+#ifdef RAYM_MEMORY_CHECK\r
+    DebugLog0("global_objc_count_ = %d", Raym::global_raym_count_);\r
+#endif\r
+\r
+    // lock\r
+    RaymLock(_controller);\r
+\r
+    // 現在時刻取得\r
+    time_t now = time(NULL);\r
+\r
+    DebugLog2("periodic: %d", now);\r
+\r
+    //\r
+    for (int tuner = 0; tuner < _controller->_tunerCount; ++tuner)\r
+    {\r
+        Array *array = _reservations->arrayForKey(_controller->_tuners[tuner]->name());\r
+        if ((array == NULL) || (array->count() == 0))\r
+        {\r
+            // next tuner\r
+            continue;\r
+        }\r
+\r
+        //\r
+        Dictionary *epg = (Dictionary *)array->objectAtIndex(0);\r
+        time_t start;\r
+        time_t end;\r
+        Controller::getTimeWithEPG(epg, &start, &end);\r
+        \r
+        //\r
+        // 録画停止要否チェック\r
+        //\r
+        bool stop_need = false;\r
+        while (true)\r
+        {\r
+            String *status = epg->stringForKey(KEY_EPG_STATUS);\r
+            if (status != NULL)\r
+            {\r
+                if (status->isEqualToString("stop"))\r
+                {\r
+                    stop_need = true;\r
+                    break;\r
+                }\r
+                if (!status->isEqualToString("running"))\r
+                {\r
+                    break;\r
+                }\r
+            }\r
+            if (end + OFFSET_OF_END_TIME <= now)\r
+            {\r
+                stop_need = true;\r
+            }\r
+            break;\r
+        }\r
+        if (stop_need)\r
+        {\r
+            DebugLog2("I try stop\n");\r
+            int fd = _controller->_tuners[tuner]->stopRecording();\r
+            if (fd < 0)\r
+            {\r
+                DebugLog1("stopRecording() error.\n");\r
+            }\r
+            else\r
+            {\r
+                DebugLog2("stopRecording() ok\n");\r
+                DebugLog0("stop recording of \"%s\"", _controller->_tuners[tuner]->name());\r
+                _close(fd);\r
+            }\r
+            array->removeObject(epg);\r
+            \r
+            if (array->count() > 0)\r
+            {\r
+                epg = (Dictionary *)array->objectAtIndex(0);\r
+            }\r
+            else\r
+            {\r
+                epg = NULL;\r
+            }\r
+            need_update = true;\r
+        }\r
+\r
+        if (epg == NULL)\r
+        {\r
+            // next tuner\r
+            continue;\r
+        }\r
+\r
+        //\r
+        // 録画開始要否チェック\r
+        //\r
+        bool start_need = false;\r
+        start = end = 0;\r
+        Controller::getTimeWithEPG(epg, &start, &end);\r
+        if ((start != 0) && (end != 0))\r
+        {\r
+            String *status = epg->stringForKey(KEY_EPG_STATUS);\r
+            if ((status == NULL) || !(status->isEqualToString("running")))\r
+            {\r
+                if (end + OFFSET_OF_END_TIME <= now)\r
+                {\r
+                    // 既に終了時間が経過しているので削除する\r
+                    array->removeObject(epg);\r
+                }\r
+                else if (start + OFFSET_OF_START_TIME <= now)\r
+                {\r
+                    start_need = true;\r
+                }\r
+            }\r
+        }\r
+\r
+        if (start_need)\r
+        {\r
+            DebugLog2("I need start.\n");\r
+            String *ch = epg->stringForKey(KEY_EPG_CHANNEL);\r
+            if (ch != NULL)\r
+            {\r
+                int channel = atoi(ch->cString());\r
+                DebugLog2("channel: %d\n", channel);\r
+                std::string videopath = createVideoPath(tuner);\r
+                if (videopath != "")\r
+                {\r
+                    DebugLog2("videopath: %s\n", videopath.c_str());\r
+                    int fd = -1;\r
+                    if (_sopen_s(&fd, videopath.c_str(),\r
+                                 (_O_CREAT | _O_EXCL | _O_WRONLY | _O_BINARY | _O_TRUNC), _SH_DENYRW, (_S_IREAD | _S_IWRITE)) == 0)\r
+                    {\r
+                        DebugLog2("open ok.\n");\r
+                        bool startResult = true;\r
+                        if (_controller->_tuners[tuner]->channel() != channel)\r
+                        {\r
+                            if (!_controller->setChannel(tuner, channel))\r
+                            {\r
+                                DebugLog3("setChannel() ng.");\r
+                                startResult = false;\r
+                            }\r
+                        }\r
+\r
+                        if (startResult)\r
+                        {\r
+                            if (_controller->_tuners[tuner]->startRecording(fd))\r
+                            {\r
+                                DebugLog2("startRecording() ok.");\r
+                                DebugLog0("start recording of \"%s\" to %s.", _controller->_tuners[tuner]->name(), videopath.c_str());\r
+                            }\r
+                            else\r
+                            {\r
+                                DebugLog3("Tuner::startRecording() failed.");\r
+                                startResult = false;\r
+                            }\r
+                        }\r
+\r
+                        if (startResult)\r
+                        {\r
+                            epg->setString("running", KEY_EPG_STATUS);\r
+                        }\r
+                        else\r
+                        {\r
+                            _close(fd);\r
+                        }\r
+                    }\r
+                    else\r
+                    {\r
+                        DebugLog0("open ng. 0x%08x\n", errno);\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    DebugLog0("Can't create videopath.\n");\r
+                }\r
+            }\r
+            else\r
+            {\r
+                DebugLog0("error.\n");\r
+            }\r
+        }\r
+    }\r
+\r
+    if (need_update)\r
+    {\r
+        //\r
+        _reservations->writeToFile(_reservations_path, true);\r
+    }\r
+\r
+#if 0\r
+    // EPG収集時刻を取得\r
+    NSString *collect_str = _props->stringForKey(KEY_COLLECT_EPG_TIME);\r
+    if (collect_str != NULL)\r
+    {\r
+        // 秒に変換\r
+        time_t collect_time = 0;\r
+        getTimeWithString(collect_str, &collect_time);\r
+\r
+        // 現在時刻と比較\r
+        if ((collect_time <= now) && (now < collect_time + 1))\r
+        {\r
+            // タイマが起動中か確認\r
+            if ((_timer_epg_s == NULL) || !_timer_epg_s->valid())\r
+            {\r
+                // EPG収集用タイマ起動(ISDB-S)\r
+                RELEASE(_timer_epg_s);\r
+                _timer_epg_s = NSTimer::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
+            }\r
+\r
+            // タイマが起動中か確認\r
+            if ((_timer_epg_t == NULL) || !_timer_epg_t->valid())\r
+            {\r
+                // EPG収集用タイマ起動(ISDB-T)\r
+                RELEASE(_timer_epg_t);\r
+                _timer_epg_t = NSTimer::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
+            }\r
+        }\r
+    }\r
+#endif\r
+\r
+    // unlock\r
+    RaymUnlock(_controller);\r
+\r
+    //\r
+    // 1/100秒単位が 0 に近くなるように次回T.O.を微調整\r
+    // ただし、windowsは精度が低いので期待しないことw\r
+    //\r
+\r
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)\r
+    static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;\r
+#else\r
+    static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;\r
+#endif\r
+    // 現在時刻を取得\r
+    FILETIME ft;\r
+    GetSystemTimeAsFileTime(&ft);\r
+\r
+    // EPOCH秒への変換\r
+    __time64_t now_sec;\r
+    __time64_t now_usec;\r
+    now_sec = ft.dwHighDateTime;\r
+    now_sec <<= 32;\r
+    now_sec |= ft.dwLowDateTime;\r
+    now_sec /= 10;  /*convert into microseconds*/\r
+    now_sec -= DELTA_EPOCH_IN_MICROSECS;\r
+    now_usec = (now_sec % 1000000UL);\r
+    now_sec = now_sec / 1000000UL;\r
+\r
+    TimeInterval interval = (TimeInterval)now_usec;\r
+    interval = interval / 1000000;\r
+    _timer_periodic->setTimeInterval(1.005 - interval);\r
+\r
+#ifdef RAYM_MEMORY_CHECK\r
+    DebugLog0("global_objc_count_ = %d", Raym::global_raym_count_);\r
+#endif\r
+}\r
+\r
 } // iPTd\r
 } // ry0\r
index f6331e1..96b51dc 100644 (file)
@@ -14,13 +14,16 @@ namespace iPTd
 \r
 class Controller;\r
 \r
-class Reservation : public Raym::Object\r
+class Reservation : public Raym::Object,\r
+                    public Raym::TimerDelegate\r
+\r
 {\r
 private:\r
     Controller *        _controller;\r
-    Raym::String *      _path;\r
+    Raym::String *      _reservations_path;\r
     Raym::Dictionary *  _reservations;          // 予約情報\r
     int                 _reservation_seq_id;    // 予約情報シーケンスID\r
+    Raym::Timer *       _timer_periodic;\r
 \r
 \r
 protected:\r
@@ -29,9 +32,24 @@ protected:
 \r
 public:\r
     static Reservation *alloc();\r
-    Reservation *initWithController(Controller *controller, Raym::String *path);\r
+    Reservation *initWithController(Controller *controller);\r
+\r
+//    void collectEPGsForTuner(int tuner, Foundation::NSTimeInterval limit);\r
+//    bool collectEPGs(ry0::device::Tuner::Type type);\r
+//    void removePastEPGs();\r
+    bool reserve(int service_id, int event_id);\r
+    bool reserve(Raym::Dictionary *epg);\r
+    bool reserve(int tuner, Raym::Dictionary *epg);\r
+    bool cancel(int tuner, int reserve_id);\r
+//    void updateKeywordsReservation();\r
+//    void updateSchedule();\r
 \r
     bool canTerminate();\r
+\r
+    std::string createVideoPath(int tuner);\r
+\r
+    // タイマ満了IF (from Timer)\r
+    void timerExpired(Raym::Timer *timer, void *userInfo);\r
 };\r
 \r
 \r
index ea53a97..5039930 100644 (file)
@@ -56,9 +56,20 @@ Streaming *Streaming::initWithController(Controller *controller)
 \r
     // 制御情報\r
     _ctrls = Dictionary::alloc()->initWithCapacity(0);\r
+    if (_ctrls == NULL)\r
+    {\r
+        release();\r
+        return NULL;\r
+    }\r
 \r
     // 周期タイマ起動\r
     _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, NULL, true);\r
+    if (_timer_periodic == NULL)\r
+    {\r
+        release();\r
+        return NULL;\r
+    }\r
+\r
     _timer_periodic->fire();\r
 \r
     return this;\r