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