OSDN Git Service

0.01版
[iptd/iPTd.git] / src / ry0 / iPTd / Reservation.cpp
diff --git a/src/ry0/iPTd/Reservation.cpp b/src/ry0/iPTd/Reservation.cpp
deleted file mode 100644 (file)
index 5d47374..0000000
+++ /dev/null
@@ -1,1235 +0,0 @@
-/**\r
- * @file Reservation.cpp\r
- *\r
- */\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
-\r
-#include "keys.h"\r
-#include "mpeg2/ts/Analyzer.h"\r
-#include "ry0/iPTd/Reservation.h"\r
-#include "ry0/iPTd/Controller.h"\r
-\r
-using namespace Raym;\r
-using namespace ry0::device;\r
-\r
-namespace ry0\r
-{\r
-namespace iPTd\r
-{\r
-\r
-static const long long CMD_PERIODIC                 = 0x0001;   // 周期処理\r
-static const long long CMD_COLLECT_EPG_ISDB_S       = 0x0002;   // 番組情報取得(ISDB-S)\r
-static const long long CMD_COLLECT_EPG_ISDB_T       = 0x0003;   // 番組情報取得(ISDB-T)\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
-static const TimeInterval DEF_COLLECT_EPG_DELAY     = 1.0;\r
-static const TimeInterval DEF_COLLECT_EPG_RETRY     = 60.0;\r
-static const TimeInterval DEF_COLLECT_EPG_LIMIT_S   = 10.5;\r
-static const TimeInterval DEF_COLLECT_EPG_LIMIT_T   = 20.5;\r
-\r
-Reservation::Reservation()\r
-{\r
-    _controller         = NULL;\r
-    _tuners             = NULL;\r
-    _reservations_path  = NULL;\r
-    _reservations       = NULL;\r
-    _reservation_seq_id = -1;\r
-    _epgs_path          = NULL;\r
-    _epgs               = NULL;\r
-    _timer_periodic     = NULL;\r
-    _timer_epg_s        = NULL;\r
-    _timer_epg_t        = NULL;\r
-    _cancel_epg_collect = false;\r
-}\r
-\r
-Reservation::~Reservation()\r
-{\r
-    RELEASE(_reservations_path);\r
-    RELEASE(_reservations);\r
-    RELEASE(_epgs_path);\r
-    RELEASE(_epgs);\r
-    RELEASE(_timer_periodic);\r
-    RELEASE(_timer_epg_s);\r
-    RELEASE(_timer_epg_t);\r
-}\r
-\r
-Reservation *Reservation::alloc()\r
-{\r
-    return new Reservation();\r
-}\r
-\r
-Reservation *Reservation::initWithController(Controller *controller)\r
-{\r
-    _controller  = controller;\r
-    _tuners      = controller->_tuners;\r
-\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("reservations file: %s (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", _reservations_path->cString());\r
-\r
-        _reservation_seq_id = _reservations->integerForKey(KEY_EPG_LAST_RESV_ID);\r
-    }\r
-\r
-    _epgs_path = String::alloc()->initWithFormat("%s%s.iptd.epgs.plist", _controller->_system_path->cString(), Controller::_plist_prefix);\r
-    if (_epgs_path == NULL)\r
-    {\r
-        release();\r
-        return NULL;\r
-    }\r
-\r
-    _epgs = Dictionary::alloc()->initWithContentsOfFile(_epgs_path);\r
-    if (_epgs == NULL)\r
-    {\r
-        DebugLog1("epgs file: %s (created)", _epgs_path->cString());\r
-        _epgs = Dictionary::alloc()->initWithCapacity(0);\r
-        if (_epgs == NULL)\r
-        {\r
-            release();\r
-            return NULL;\r
-        }\r
-    }\r
-    else\r
-    {\r
-        DebugLog1("epgs file: %s", _epgs_path->cString());\r
-\r
-        // 過去の番組データは削除\r
-        removePastEPGs();\r
-    }\r
-\r
-    return this;\r
-}\r
-\r
-bool Reservation::canSuspend()\r
-{\r
-    bool result = true;\r
-\r
-    RaymLock(_controller);\r
-    if (((_timer_epg_s != NULL) && _timer_epg_s->valid()) ||\r
-        ((_timer_epg_t != NULL) && _timer_epg_t->valid()))\r
-    {\r
-        result = false;\r
-    }\r
-    RaymUnlock(_controller);\r
-\r
-    if (result)\r
-    {\r
-        result = canTerminate();\r
-    }\r
-\r
-    return result;\r
-}\r
-\r
-bool Reservation::canTerminate()\r
-{\r
-    bool result = true;\r
-\r
-    RaymLock(_controller);\r
-\r
-    time_t now = time(NULL);\r
-\r
-    for (int tuner = 0; tuner < _controller->_tuner_count; ++tuner)\r
-    {\r
-        Array *array = _reservations->arrayForKey(_tuners[tuner]->name());\r
-        if ((array == NULL) || (array->count() == 0))\r
-        {\r
-            continue;\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
-        if (start + OFFSET_OF_SUPPRESSION_TIME <= now)\r
-        {\r
-            result = false;\r
-            break;\r
-        }\r
-    }\r
-\r
-    RaymUnlock(_controller);\r
-\r
-    return result;\r
-}\r
-\r
-void Reservation::systemWillSuspend()\r
-{\r
-    RaymLock(_controller);\r
-    _cancel_epg_collect = true;\r
-    RaymUnlock(_controller);\r
-\r
-    if ((_timer_epg_s != NULL) && _timer_epg_s->valid())\r
-    {\r
-        _timer_epg_s->invalidate();\r
-    }\r
-    if ((_timer_epg_t != NULL) && _timer_epg_t->valid())\r
-    {\r
-        _timer_epg_t->invalidate();\r
-    }\r
-    if ((_timer_periodic != NULL) && _timer_periodic->valid())\r
-    {\r
-        _timer_periodic->invalidate();\r
-    }\r
-\r
-    RaymLock(_controller);\r
-    _cancel_epg_collect = false;\r
-    RaymUnlock(_controller);\r
-}\r
-\r
-void Reservation::systemResumed()\r
-{\r
-    DebugLog2("%s", __FUNCTION__);\r
-\r
-    RaymLock(_controller);\r
-\r
-    _cancel_epg_collect = false;\r
-\r
-    if (_timer_periodic == NULL)\r
-    {\r
-        _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC, true);\r
-        if (_timer_periodic != NULL)\r
-        {\r
-            _timer_periodic->fire();\r
-        }\r
-    }\r
-\r
-    if (_timer_epg_s == NULL)\r
-    {\r
-        _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);\r
-        if (_timer_epg_s != NULL)\r
-        {\r
-            _timer_epg_s->fire();\r
-        }\r
-    }\r
-\r
-    if (_timer_epg_t == NULL)\r
-    {\r
-        _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);\r
-        if (_timer_epg_t != NULL)\r
-        {\r
-            _timer_epg_t->fire();\r
-        }\r
-    }\r
-\r
-    RaymUnlock(_controller);\r
-}\r
-\r
-//\r
-// 録画予約:サービスID/イベントID指定\r
-//   EPGデータから指定のサービスID/イベントIDのEPGを取り出し、EPG指定の録画予約をコール\r
-//\r
-bool Reservation::reserve(int service_id, int event_id)\r
-{\r
-    DebugLog2("Reservation::reserve(service_id, event_id)");\r
-\r
-    bool result = false;\r
-\r
-    RaymLock(_controller);\r
-\r
-    if (_epgs != NULL)\r
-    {\r
-        Dictionary *events = _epgs->dictionaryForKey(String::stringWithFormat("%d", service_id));\r
-        if (events != NULL)\r
-        {\r
-            Dictionary *epg = events->dictionaryForKey(String::stringWithFormat("%d", event_id));\r
-            if (epg != NULL)\r
-            {\r
-                result = reserve(epg);\r
-            }\r
-        }\r
-    }\r
-\r
-    RaymUnlock(_controller);\r
-\r
-    return result;\r
-}\r
-\r
-//\r
-// 録画予約:EPG指定\r
-//   EPGからサービスIDを取り出し、チューナ情報を検索して一致するサービスIDがあったらチューナ/EPG指定の録画予約を試行\r
-//\r
-bool Reservation::reserve(Dictionary *in_epg)\r
-{\r
-    DebugLog2("Reservation::reserve(epg)");\r
-\r
-    bool result = false;\r
-\r
-    RaymLock(_controller);\r
-\r
-    while (in_epg != NULL)\r
-    {\r
-        // EPGを複製\r
-        Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg);\r
-        if (epg == NULL)\r
-        {\r
-            DebugLog3("Dictionary::dictionaryWithDictionary() ng.");\r
-            break;\r
-        }\r
-\r
-        // サービスID取得\r
-        String *service_id = epg->stringForKey(KEY_EPG_SERVICE_ID);\r
-        if (service_id == NULL)\r
-        {\r
-            DebugLog3("epg->stringForKey(KEY_EPG_SERVICE_ID) ng.");\r
-            break;\r
-        }\r
-        DebugLog3("service_id: %s\n", service_id->cString());\r
-\r
-        // 全チューナ情報取得\r
-        Dictionary *tunerInfos = _controller->_props->dictionaryForKey(KEY_TUNERS);\r
-        if (tunerInfos == NULL)\r
-        {\r
-            DebugLog3("_props->dictionaryForKey(KEY_TUNERS) ng.");\r
-            break;\r
-        }\r
-\r
-        // チューナを検索\r
-        for (int i = 0; (!result) && (i < _controller->_tuner_count); ++i)\r
-        {\r
-            // チューナ情報取得\r
-            Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name());\r
-            if (tunerInfo == NULL)\r
-            {\r
-                DebugLog3("tunerInfos->dictionaryForKey(_tuners[%d]->name()) ng.", i);\r
-                continue;\r
-            }\r
-\r
-            // 全チャンネル情報取得\r
-            Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);\r
-            if (channels == NULL)\r
-            {\r
-                DebugLog3("tunerInfo->dictionaryForKey(KEY_CHANNELS) ng.");\r
-                continue;\r
-            }\r
-\r
-            // キー取得\r
-            Array *chkeys = channels->allKeys();\r
-            for (uint ch = 0; ch < chkeys->count(); ++ch)\r
-            {\r
-                // チャンネル情報取得\r
-                Dictionary *channel = channels->dictionaryForKey((String *)chkeys->objectAtIndex(ch));\r
-                if (channel == NULL)\r
-                {\r
-                    DebugLog3("channels->dictionaryForKey() ng.");\r
-                    continue;\r
-                }\r
-\r
-                // 全サービス情報取得\r
-                Array *services = (Array *)channel->objectForKey(KEY_SERVICES);\r
-                if (services == NULL)\r
-                {\r
-                    DebugLog3("channel->objectForKey() ng.");\r
-                    continue;\r
-                }\r
-\r
-                for (uint s = 0; s < services->count(); ++s)\r
-                {\r
-                    // サービス情報取得\r
-                    Dictionary *service = (Dictionary *)services->objectAtIndex(s);\r
-                    if (service == NULL)\r
-                    {\r
-                        DebugLog3("service->objectAtIndex() ng.");\r
-                        continue;\r
-                    }\r
-\r
-                    // サービスIDを比較\r
-                    String *sid = service->stringForKey(KEY_SERVICE_ID);\r
-                    if ((sid != NULL) && sid->isEqualToString(service_id))\r
-                    {\r
-                        // チャンネルを設定\r
-                        epg->setString((String *)chkeys->objectAtIndex(ch), KEY_EPG_CHANNEL);\r
-\r
-                        // 録画予約\r
-                        result = reserve(i, epg);\r
-\r
-                        // チャンネルループのカウンタを更新(=ループを終了させる)\r
-                        ch = chkeys->count();\r
-                        break;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        break;\r
-    }\r
-\r
-    RaymUnlock(_controller);\r
-\r
-    return result;\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->_tuner_count) && (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(_tuners[tuner]->name());\r
-        if (array == NULL)\r
-        {\r
-            array = Array::arrayWithCapacity(0);\r
-            _reservations->setObject(array, _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->_tuner_count))\r
-    {\r
-        Array *array = _reservations->arrayForKey(_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->_tuner_count; ++i)\r
-        {\r
-            Array *array = _reservations->arrayForKey(_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
-void Reservation::updateSchedule()\r
-{\r
-    DebugLog2("Reservation::updateSchedule()");\r
-\r
-    RaymLock(_controller);\r
-\r
-    // レジューム時刻\r
-    time_t resume_time = 0;\r
-\r
-    // EPG収集時刻を取得\r
-    String *collect_epg_time = _controller->_props->stringForKey(KEY_COLLECT_EPG_TIME);\r
-    if (collect_epg_time != NULL)\r
-    {\r
-        Controller::getTimeWithString(collect_epg_time, &resume_time);\r
-    }\r
-\r
-    // 録画予約をチェック\r
-    for (int tuner = 0; tuner < _controller->_tuner_count; ++tuner)\r
-    {\r
-        Array *array = _reservations->arrayForKey(_tuners[tuner]->name());\r
-        if ((array == NULL) || (array->count() == 0))\r
-        {\r
-            // next tuner\r
-            continue;\r
-        }\r
-\r
-        Dictionary *epg = (Dictionary *)array->objectAtIndex(0);\r
-        time_t start = 0;\r
-        time_t end = 0;\r
-        Controller::getTimeWithEPG(epg, &start, &end);\r
-        if ((start != 0) && (end != 0))\r
-        {\r
-            if (start < resume_time)\r
-            {\r
-                resume_time = start;\r
-            }\r
-        }\r
-    }\r
-\r
-    //\r
-    TM resume_tm;\r
-    resume_time += OFFSET_OF_WAKEUP;    // 起動時刻を 5分前に設定(OFFSET_OF_WAKEUPで調整)\r
-    if (localtime_s(&resume_tm, &resume_time) == 0)\r
-    {\r
-        _controller->resetWakeSchedule();\r
-        if (_controller->setWakeSchedule(resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min))\r
-        {\r
-            DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",\r
-                      resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);\r
-        }\r
-    }\r
-\r
-    // unlock\r
-    RaymUnlock(_controller);\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
-                      _tuners[tuner]->channel(), _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::removePastEPGs()\r
-{\r
-    DebugLog2("Reservation::removePastEPGs()");\r
-\r
-    time_t now = time(NULL);\r
-\r
-    RaymLock(_controller);\r
-\r
-    Array *keys1 = _epgs->allKeys();\r
-    for (uint i = 0; i < keys1->count(); ++i)\r
-    {\r
-        Dictionary *events = _epgs->dictionaryForKey((String *)keys1->objectAtIndex(i));\r
-        if (events != NULL)\r
-        {\r
-            Array *keys2 = events->allKeys();\r
-            for (uint j = 0; j < keys2->count(); ++j)\r
-            {\r
-                String *key = (String *)keys2->objectAtIndex(j);\r
-                Dictionary *epg = events->dictionaryForKey(key);\r
-                if (epg != NULL)\r
-                {\r
-                    time_t start = 0;\r
-                    time_t end = 0;\r
-                    Controller::getTimeWithEPG(epg, &start, &end);\r
-\r
-                    if (now > end)\r
-                    {\r
-                        events->removeObjectForKey(key);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    RaymUnlock(_controller);\r
-}\r
-\r
-void Reservation::collectEPGsForTuner(int tuner, TimeInterval limit)\r
-{\r
-    DebugLog2("Reservation::collectEPGsForTuner(%d) start.", tuner);\r
-\r
-    // 既にロックされた状態でコールされる前提\r
-    bool locked = false;\r
-    RaymLock(_controller);\r
-    if ((0 <= tuner) && (tuner < _controller->_tuner_count))\r
-    {\r
-        locked = _tuners[tuner]->isLocked();\r
-    }\r
-    RaymUnlock(_controller);\r
-    if (!locked)\r
-    {\r
-        DebugLog2("Reservation::collectEPGsForTuner(%d) end(no locked).", tuner);\r
-        return;\r
-    }\r
-\r
-    // \r
-    Array *collected = Array::arrayWithCapacity(0);\r
-\r
-    // 開始時刻取得\r
-    Date *start = Date::date();\r
-\r
-    // 取得開始\r
-    bool done = false;\r
-    while (!done)\r
-    {\r
-        AutoreleasePool *pool = AutoreleasePool::alloc()->init();\r
-\r
-        // EPG取得\r
-        MPEG2::TS::Analyzer an;\r
-        an.setFlag(MPEG2::TS::Analyzer::FLAG_EIT);\r
-        _tuners[tuner]->setListener(&an);\r
-        Array *epgs = an.epgInfos();\r
-        _tuners[tuner]->setListener(NULL);\r
-\r
-        if (epgs != NULL)\r
-        {\r
-            // 取得成功\r
-            collected->addObjectsFromArray(epgs);\r
-        }\r
-\r
-        // リミットチェック\r
-        if (Date::date()->timeIntervalSinceDate(start) >= limit)\r
-        {\r
-            done = true;\r
-        }\r
-\r
-        // キャンセル確認\r
-        RaymLock(_controller);\r
-        if (!done)\r
-        {\r
-            done = _cancel_epg_collect;\r
-        }\r
-        RaymUnlock(_controller);\r
-\r
-        pool->release();\r
-    }\r
-\r
-    // lock\r
-    RaymLock(_controller);\r
-\r
-    for (uint j = 0; j < collected->count(); ++j)\r
-    {\r
-        Dictionary *epg1 = (Dictionary *)collected->objectAtIndex(j);\r
-\r
-        if (epg1->stringForKey(KEY_EPG_TITLE) == NULL)\r
-        {\r
-            // タイトルが無い場合は不要\r
-            continue;\r
-        }\r
-\r
-        // Service ID を Primary Key\r
-        String *key = epg1->stringForKey(KEY_EPG_SERVICE_ID);\r
-        if (key != NULL)\r
-        {\r
-            Dictionary *epgs_of_service = _epgs->dictionaryForKey(key);\r
-            if (epgs_of_service == NULL)\r
-            {\r
-                // 無い場合は作成\r
-                epgs_of_service = Dictionary::dictionaryWithCapacity(0);\r
-                _epgs->setObject(epgs_of_service, key);\r
-            }\r
-            // Event ID を Secondary Key\r
-            key = epg1->stringForKey(KEY_EPG_EVENT_ID);\r
-            if (key != NULL)\r
-            {\r
-                epgs_of_service->setObject(epg1, key);\r
-            }\r
-        }\r
-    }\r
-\r
-    // ファイルへ書き出し\r
-    _epgs->writeToFile(_epgs_path, true);\r
-\r
-    // unlock\r
-    RaymUnlock(_controller);\r
-\r
-    DebugLog2("Reservation::collectEPGsForTuner(%d) end.", tuner);\r
-}\r
-\r
-bool Reservation::collectEPGs(Tuner::Type type)\r
-{\r
-    DebugLog0("Reservation::collectEPGs(%s) start.", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
-\r
-    // 使用するチューナを決定\r
-    int tuner = 0;\r
-    bool locked = false;\r
-    RaymLock(_controller);\r
-    for (int i = _controller->_tuner_count - 1; i >= 0; --i)\r
-    {\r
-        if (_controller->isTunerEnabled(i))\r
-        {\r
-            if ((!_tuners[i]->isLocked()) && (_tuners[i]->type() == type))\r
-            {\r
-                if (_tuners[i]->lock())\r
-                {\r
-                    tuner = i;\r
-                    locked = true;\r
-                    break;\r
-                }\r
-            }\r
-        }\r
-    }\r
-    RaymUnlock(_controller);\r
-\r
-    // ロック確認\r
-    if (!locked)\r
-    {\r
-        DebugLog0("Controller::collectEPGs(%s) end(Can't locked).", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
-        // ロックできない場合は収集しない\r
-        return false;\r
-    }\r
-\r
-    bool canceled = false;\r
-    DebugLog0("start collect EPG of \"%s(#%d)\".", _tuners[tuner]->name(), tuner);\r
-\r
-    // 現在のチャンネルを保存\r
-    int channel = _tuners[tuner]->channel();\r
-\r
-    // チャンネルを変更しつつEPGを取得\r
-    int max_channel = (type == Tuner::ISDB_S ? Tuner::MAX_CHANNELS_ISDB_S : Tuner::MAX_CHANNELS_ISDB_T);\r
-    for (int ch = 0; ch <= max_channel; ++ch)\r
-    {\r
-        // チャンネルが有効かチェック\r
-        if (_controller->isChannelEnabled(tuner, ch))\r
-        {\r
-            // チャンネル設定\r
-            if (_tuners[tuner]->setChannel(ch))\r
-            {\r
-                // EPG取集\r
-                collectEPGsForTuner(tuner, ((type == Tuner::ISDB_S) ? DEF_COLLECT_EPG_LIMIT_S : DEF_COLLECT_EPG_LIMIT_T));\r
-\r
-                RaymLock(_controller);\r
-                if (_cancel_epg_collect)\r
-                {\r
-                    ch = Tuner::MAX_CHANNELS_ISDB_T + 1;\r
-                    canceled = true;\r
-                }\r
-                RaymUnlock(_controller);\r
-\r
-                // キャンセル確認\r
-                //   終了不可 -> 録画待機中/録画中  なので、収集は諦める\r
-                if (!canTerminate())\r
-                {\r
-                    ch = Tuner::MAX_CHANNELS_ISDB_T + 1;\r
-                    canceled = true;\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    // 元のチャンネルに戻す\r
-    _tuners[tuner]->setChannel(channel);\r
-\r
-    RaymLock(_controller);\r
-\r
-    // チューナをアンロック\r
-    _tuners[tuner]->unlock();\r
-\r
-    RaymUnlock(_controller);\r
-\r
-    if (canceled)\r
-    {\r
-        DebugLog0("collect EPG of \"%s\" was canceled.", _tuners[tuner]->name());\r
-    }\r
-    else\r
-    {\r
-        DebugLog0("collect EPG of \"%s\" was finished.", _tuners[tuner]->name());\r
-\r
-        // 過去のEPGを削除\r
-        removePastEPGs();\r
-    }\r
-\r
-    DebugLog2("Reservation::collectEPGs(%s) end.", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");\r
-\r
-    return true;\r
-}\r
-\r
-void Reservation::periodic()\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->_tuner_count; ++tuner)\r
-    {\r
-        Array *array = _reservations->arrayForKey(_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 = _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\"", _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 (_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 (_tuners[tuner]->startRecording(fd))\r
-                            {\r
-                                DebugLog2("startRecording() ok.");\r
-                                DebugLog0("start recording of \"%s\" to %s.", _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
-    // EPG収集時刻を取得\r
-    String *collect_str = _controller->_props->stringForKey(KEY_COLLECT_EPG_TIME);\r
-    if (collect_str != NULL)\r
-    {\r
-        // 秒に変換\r
-        time_t collect_time = 0;\r
-        Controller::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 = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);\r
-                if (_timer_epg_s != NULL)\r
-                {\r
-                    _timer_epg_s->fire();\r
-                }\r
-            }\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 = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);\r
-                if (_timer_epg_t != NULL)\r
-                {\r
-                    _timer_epg_t->fire();\r
-                }\r
-            }\r
-        }\r
-    }\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
-void Reservation::timerExpired(Timer *timer, void *userInfo)\r
-{\r
-    switch ((long long)userInfo)\r
-    {\r
-    case CMD_PERIODIC:\r
-        periodic();\r
-        break;\r
-\r
-    case CMD_COLLECT_EPG_ISDB_S:\r
-        if (collectEPGs(Tuner::ISDB_S))\r
-        {\r
-            _timer_epg_s->setRepeats(false);\r
-        }\r
-        else\r
-        {\r
-            _timer_epg_s->setTimeInterval(DEF_COLLECT_EPG_RETRY);\r
-        }\r
-        break;\r
-\r
-    case CMD_COLLECT_EPG_ISDB_T:\r
-        if (collectEPGs(Tuner::ISDB_T))\r
-        {\r
-            _timer_epg_t->setRepeats(false);\r
-        }\r
-        else\r
-        {\r
-            _timer_epg_t->setTimeInterval(DEF_COLLECT_EPG_RETRY);\r
-        }\r
-        break;\r
-    }\r
-}\r
-\r
-} // iPTd\r
-} // ry0\r