5 //#include "stdafx.h"
\r
8 #include <Raym/Log.h>
\r
12 #include <sys/types.h>
\r
13 #include <sys/stat.h>
\r
18 #include <winsock2.h>
\r
19 #include <ws2tcpip.h>
\r
20 #include <Iphlpapi.h>
\r
22 #include "ry0/iPTd/Controller.h"
\r
23 #include "ry0/iPTd/HTTPLiveStreaming.h"
\r
24 #include "mpeg2/ts/Analyzer.h"
\r
26 #include "b25/arib_std_b25.h"
\r
27 #include "b25/b_cas_card.h"
\r
29 using namespace Raym;
\r
30 using namespace NET;
\r
31 using namespace ry0::device;
\r
38 static const char *PLIST_PREFIX = "com.gmail.tim.and.pom";
\r
41 static const char * DEF_NAME = "iPTd_R2";
\r
42 static const char * DEF_HOSTNAME = "localhost";
\r
43 static const int DEF_HTTP_PORT = 50080; // HTTPポート
\r
44 static const int DEF_BEGIN_UDP_PORT = 51000; // UDPポートの開始位置
\r
45 static const int DEF_SUSPEND_TIME = 5; // 休止するまでの時間(分単位)
\r
46 static const int DEF_FORCED_SUSPEND_TIME = 120; // 強制休止するまでの時間(分単位)
\r
47 static const char * DEF_COLLECT_EPG_TIME = "02:00:00"; // EPG収集する時刻 HH:MM::SS
\r
50 static const long long CMD_RESTART = 0x0001; // 再開処理
\r
51 static const long long CMD_SUSPEND = 0x0002; // サスペンド
\r
52 static const long long CMD_PERIODIC = 0x0003; // 周期処理
\r
53 static const long long CMD_PERIODIC_2 = 0x0004; // 周期処理2
\r
54 static const long long CMD_COLLECT_EPG_ISDB_S = 0x0005; // 番組情報取得(ISDB-S)
\r
55 static const long long CMD_COLLECT_EPG_ISDB_T = 0x0006; // 番組情報取得(ISDB-T)
\r
58 static const TimeInterval DEF_COLLECT_EPG_DELAY = 1.0;
\r
59 static const TimeInterval DEF_COLLECT_EPG_RETRY = 60.0;
\r
60 static const TimeInterval DEF_COLLECT_EPG_LIMIT_S = 10.5;
\r
61 static const TimeInterval DEF_COLLECT_EPG_LIMIT_T = 20.5;
\r
63 static const time_t OFFSET_OF_START_TIME = -2; // 録画開始時刻の補正(秒単位)
\r
64 static const time_t OFFSET_OF_END_TIME = -3; // 録画停止時刻の補正(秒単位)
\r
65 static const time_t OFFSET_OF_WAKEUP = -240; // 起動スケジュールの補正(秒単位) 注:休止するまでの時間(DEF_SUSPEND_TIME)よりも短くすること
\r
66 static const time_t OFFSET_OF_SUPPRESSION_TIME = -600; // 録画開始前に休止の抑制を開始する時間(秒単位)
\r
71 void Controller::delaySuspend()
\r
74 Timer *timer = Timer::scheduledTimerWithTimeInterval(1.0, this, (void *)CMD_SUSPEND, false);
\r
77 DebugLog0("Can't start timer.");
\r
82 std::string Controller::createVideoPath(int tuner)
\r
84 DebugLog2("Controller::createVideoPath()");
\r
86 std::string result = "";
\r
93 if (localtime_s(&tm, &now) != 0)
\r
98 result = _store_path->cString();
\r
99 DebugLog2("result: %s\n", result.c_str());
\r
102 if (sprintf_s(tmp, sizeof(tmp), "\\%04d", tm.tm_year + 1900) < 0)
\r
104 DebugLog0("sprintf_s() error: year\n");
\r
109 DebugLog2("result: %s\n", result.c_str());
\r
112 if (_stat(result.c_str(), &stat) != 0)
\r
114 if (_mkdir(result.c_str()) != 0)
\r
116 DebugLog0("_mkdir() error: year\n");
\r
120 _stat(result.c_str(), &stat);
\r
122 if ((stat.st_mode & _S_IFDIR) != _S_IFDIR)
\r
124 DebugLog0("%s is not directory.\n", result.c_str());
\r
129 if (sprintf_s(tmp, sizeof(tmp), "\\%02d", tm.tm_mon + 1) < 0)
\r
131 DebugLog0("sprintf_s() error: month\n");
\r
136 DebugLog2("result: %s\n", result.c_str());
\r
138 if (_stat(result.c_str(), &stat) != 0)
\r
140 if (_mkdir(result.c_str()) != 0)
\r
142 DebugLog0("_mkdir() error: month\n");
\r
146 _stat(result.c_str(), &stat);
\r
148 if ((stat.st_mode & _S_IFDIR) != _S_IFDIR)
\r
150 DebugLog0("%s is not directory.", result.c_str());
\r
155 if (sprintf_s(tmp, sizeof(tmp),
\r
156 "\\%04d%02d%02d_%02d%02d%02d_%03d_%s.ts",
\r
157 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
\r
158 _tuners[tuner]->channel(), _tuners[tuner]->name()) < 0)
\r
160 DebugLog0("sprintf_s() error: filename");
\r
165 DebugLog2("result: %s\n", result.c_str());
\r
175 #pragma mark ------- EPG関連 -------
\r
178 void Controller::removePastEPGs()
\r
180 DebugLog2("Controller::removePastEPGs()");
\r
183 time_t now = time(NULL);
\r
189 Array *keys1 = _epgs->allKeys();
\r
190 for (uint i = 0; i < keys1->count(); ++i)
\r
193 Dictionary *events = _epgs->dictionaryForKey((String *)keys1->objectAtIndex(i));
\r
194 if (events != NULL)
\r
197 Array *keys2 = events->allKeys();
\r
198 for (uint j = 0; j < keys2->count(); ++j)
\r
201 String *key = (String *)keys2->objectAtIndex(j);
\r
202 Dictionary *epg = events->dictionaryForKey(key);
\r
208 getTimeWithEPG(epg, &start, &end);
\r
214 events->removeObjectForKey(key);
\r
225 void Controller::collectEPGsForTuner(int tuner, TimeInterval limit)
\r
227 DebugLog2("Controller::collectEPGsForTuner(%d) start.", tuner);
\r
229 // 既にロックされた状態でコールされる前提
\r
230 bool locked = false;
\r
232 if ((0 <= tuner) && (tuner < _tunerCount))
\r
234 locked = _tuners[tuner]->isLocked();
\r
239 DebugLog2("Controller::collectEPGsForTuner(%d) end(no locked).", tuner);
\r
244 Array *collected = Array::arrayWithCapacity(0);
\r
247 Date *start = Date::date();
\r
253 AutoreleasePool *pool = AutoreleasePool::alloc()->init();
\r
256 MPEG2::TS::Analyzer an;
\r
257 an.setFlag(MPEG2::TS::Analyzer::FLAG_EIT);
\r
258 _tuners[tuner]->setListener(&an);
\r
259 Array *epgs = an.epgInfos();
\r
260 _tuners[tuner]->setListener(NULL);
\r
265 collected->addObjectsFromArray(epgs);
\r
269 if (Date::date()->timeIntervalSinceDate(start) >= limit)
\r
278 done = _cancel_epg_collect;
\r
288 for (uint j = 0; j < collected->count(); ++j)
\r
290 Dictionary *epg1 = (Dictionary *)collected->objectAtIndex(j);
\r
292 if (epg1->stringForKey(KEY_EPG_TITLE) == NULL)
\r
298 // Service ID を Primary Key
\r
299 String *key = epg1->stringForKey(KEY_EPG_SERVICE_ID);
\r
302 Dictionary *epgs_of_service = _epgs->dictionaryForKey(key);
\r
303 if (epgs_of_service == NULL)
\r
306 epgs_of_service = Dictionary::dictionaryWithCapacity(0);
\r
307 _epgs->setObject(epgs_of_service, key);
\r
309 // Event ID を Secondary Key
\r
310 key = epg1->stringForKey(KEY_EPG_EVENT_ID);
\r
313 epgs_of_service->setObject(epg1, key);
\r
319 _epgs->writeToFile(_epgs_path, true);
\r
324 DebugLog2("Controller::collectEPGsForTuner(%d) end.", tuner);
\r
327 bool Controller::collectEPGs(Tuner::Type type)
\r
329 DebugLog0("Controller::collectEPGs(%s) start.", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");
\r
333 bool locked = false;
\r
335 for (int i = _tunerCount - 1; i >= 0; --i)
\r
337 if (isTunerEnabled(i))
\r
339 if ((!_tuners[i]->isLocked()) && (_tuners[i]->type() == type))
\r
341 if (_tuners[i]->lock())
\r
355 DebugLog0("Controller::collectEPGs(%s) end(Can't locled).", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");
\r
360 bool canceled = false;
\r
361 DebugLog0("start collect EPG of \"%s(#%d)\".", _tuners[tuner]->name(), tuner);
\r
364 int channel = _tuners[tuner]->channel();
\r
366 // チャンネルを変更しつつEPGを取得
\r
367 int max_channel = (type == Tuner::ISDB_S ? Tuner::MAX_CHANNELS_ISDB_S : Tuner::MAX_CHANNELS_ISDB_T);
\r
368 for (int ch = 0; ch <= max_channel; ++ch)
\r
371 if (isChannelEnabled(tuner, ch))
\r
374 if (_tuners[tuner]->setChannel(ch))
\r
377 collectEPGsForTuner(tuner, ((type == Tuner::ISDB_S) ? DEF_COLLECT_EPG_LIMIT_S : DEF_COLLECT_EPG_LIMIT_T));
\r
381 if (_cancel_epg_collect)
\r
383 ch = Tuner::MAX_CHANNELS_ISDB_T + 1;
\r
389 // 終了不可 -> 録画待機中/録画中 なので、収集は諦める
\r
390 if (!canTerminate())
\r
392 ch = Tuner::MAX_CHANNELS_ISDB_T + 1;
\r
400 _tuners[tuner]->setChannel(channel);
\r
406 _tuners[tuner]->unlock();
\r
413 DebugLog0("collect EPG of \"%s\" was canceled.", _tuners[tuner]->name());
\r
417 DebugLog0("collect EPG of \"%s\" was finished.", _tuners[tuner]->name());
\r
423 DebugLog2("Controller::collectEPGs(%s) end.", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");
\r
430 #pragma mark ------- 予約録画関連 -------
\r
434 // 録画予約:サービスID/イベントID指定
\r
435 // EPGデータから指定のサービスID/イベントIDのEPGを取り出し、EPG指定の録画予約をコール
\r
437 bool Controller::reserve(int service_id, int event_id)
\r
439 DebugLog2("Controller::reserve(service_id, event_id)");
\r
441 bool result = false;
\r
448 Dictionary *events = _epgs->dictionaryForKey(String::stringWithFormat("%d", service_id));
\r
449 if (events != NULL)
\r
451 Dictionary *epg = events->dictionaryForKey(String::stringWithFormat("%d", event_id));
\r
454 result = reserve(epg);
\r
467 // EPGからサービスIDを取り出し、チューナ情報を検索して一致するサービスIDがあったらチューナ/EPG指定の録画予約を試行
\r
469 bool Controller::reserve(Dictionary *in_epg)
\r
471 DebugLog2("Controller::reserve(epg)");
\r
473 bool result = false;
\r
478 while (in_epg != NULL)
\r
481 Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg);
\r
484 DebugLog3("Dictionary::dictionaryWithDictionary() ng.");
\r
489 String *service_id = epg->stringForKey(KEY_EPG_SERVICE_ID);
\r
490 if (service_id == NULL)
\r
492 DebugLog3("epg->stringForKey(KEY_EPG_SERVICE_ID) ng.");
\r
495 DebugLog3("service_id: %s\n", service_id->cString());
\r
498 Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);
\r
499 if (tunerInfos == NULL)
\r
501 DebugLog3("_props->dictionaryForKey(KEY_TUNERS) ng.");
\r
506 for (int i = 0; (!result) && (i < _tunerCount); ++i)
\r
509 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name());
\r
510 if (tunerInfo == NULL)
\r
512 DebugLog3("tunerInfos->dictionaryForKey(_tuners[%d]->name()) ng.", i);
\r
517 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
518 if (channels == NULL)
\r
520 DebugLog3("tunerInfo->dictionaryForKey(KEY_CHANNELS) ng.");
\r
525 Array *chkeys = channels->allKeys();
\r
526 for (uint ch = 0; ch < chkeys->count(); ++ch)
\r
529 Dictionary *channel = channels->dictionaryForKey((String *)chkeys->objectAtIndex(ch));
\r
530 if (channel == NULL)
\r
532 DebugLog3("channels->dictionaryForKey() ng.");
\r
537 Array *services = (Array *)channel->objectForKey(KEY_SERVICES);
\r
538 if (services == NULL)
\r
540 DebugLog3("channel->objectForKey() ng.");
\r
544 for (uint s = 0; s < services->count(); ++s)
\r
547 Dictionary *service = (Dictionary *)services->objectAtIndex(s);
\r
548 if (service == NULL)
\r
550 DebugLog3("service->objectAtIndex() ng.");
\r
555 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
556 if ((sid != NULL) && sid->isEqualToString(service_id))
\r
559 epg->setString((String *)chkeys->objectAtIndex(ch), KEY_EPG_CHANNEL);
\r
562 result = reserve(i, epg);
\r
564 // チャンネルループのカウンタを更新(=ループを終了させる)
\r
565 ch = chkeys->count();
\r
584 bool Controller::reserve(int tuner, Dictionary *in_epg)
\r
586 DebugLog2("Controller::reserve(tuner, epg)");
\r
588 bool result = false;
\r
593 while ((0 <= tuner) && (tuner < _tunerCount) && (in_epg != NULL))
\r
595 Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg);
\r
598 DebugLog3("Dictionary::dictionaryWithDictionary() ng.");
\r
602 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
605 array = Array::arrayWithCapacity(0);
\r
606 _reservations->setObject(array, _tuners[tuner]->name());
\r
611 getTimeWithEPG(epg, &epg_start, &epg_end);
\r
612 DebugLog2("epg start: %ld, end: %ld\n", epg_start, epg_end);
\r
614 time_t pre_start = 0;
\r
615 time_t pre_end = 0;
\r
616 pre_end = time(NULL);
\r
617 DebugLog2("pre_end: %ld", pre_end);
\r
619 for (uint i = 0; i < array->count(); ++i)
\r
621 Dictionary *cur = (Dictionary *)array->objectAtIndex(i);
\r
624 getTimeWithEPG(cur, &cur_start, &cur_end);
\r
625 DebugLog2("cur start: %ld, end: %ld\n", cur_start, cur_end);
\r
626 if ((pre_end <= epg_start) && (epg_end <= cur_start))
\r
628 DebugLog2("insert: %d\n", i);
\r
629 array->insertObject(epg, i);
\r
633 pre_start = cur_start;
\r
639 if (pre_end <= epg_start)
\r
641 DebugLog2("add\n");
\r
642 array->addObject(epg);
\r
647 DebugLog2("no add\n");
\r
652 epg->setInteger(_reservation_seq_id, KEY_EPG_RESV_ID);
\r
653 _reservation_seq_id = (_reservation_seq_id + 1) % 1000000;
\r
654 _reservations->setInteger(_reservation_seq_id, KEY_EPG_LAST_RESV_ID);
\r
657 _reservations->writeToFile(_reservations_path, true);
\r
670 // tuner: 0 - (_tunerCount - 1) cancel current
\r
671 // tuner: -1 cancel reserve_id
\r
673 bool Controller::cancel(int tuner, int reserve_id)
\r
675 bool result = false;
\r
681 if ((0 <= tuner) && (tuner < _tunerCount))
\r
683 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
686 if (array->count() > 0)
\r
688 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
689 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
690 if (status != NULL)
\r
692 if (status->isEqualToString("running"))
\r
694 epg->setString("stop", KEY_EPG_STATUS);
\r
703 else if ((tuner < 0) && (0 <= reserve_id) && (reserve_id < 1000000))
\r
705 for (int i = 0; i < _tunerCount; ++i)
\r
707 Array *array = _reservations->arrayForKey(_tuners[i]->name());
\r
710 for (uint j = 0; j < array->count(); ++j)
\r
712 Dictionary *epg = (Dictionary *)array->objectAtIndex(j);
\r
713 if (reserve_id == epg->integerForKey(KEY_EPG_RESV_ID))
\r
715 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
716 if ((status != NULL) && status->isEqualToString("running"))
\r
718 epg->setString("stop", KEY_EPG_STATUS);
\r
722 array->removeObjectAtIndex(j);
\r
738 _reservations->writeToFile(_reservations_path, true);
\r
750 void Controller::periodic(void)
\r
752 bool need_update = false;
\r
754 #ifdef OBJC_MEMORY_CHECK
\r
755 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
762 time_t now = time(NULL);
\r
764 DebugLog2("periodic: %d", now);
\r
767 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
769 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
770 if ((array == NULL) || (array->count() == 0))
\r
777 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
780 getTimeWithEPG(epg, &start, &end);
\r
785 bool stop_need = false;
\r
788 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
789 if (status != NULL)
\r
791 if (status->isEqualToString("stop"))
\r
796 if (!status->isEqualToString("running"))
\r
801 if (end + OFFSET_OF_END_TIME <= now)
\r
809 DebugLog2("I try stop\n");
\r
810 int fd =_tuners[tuner]->stopRecording();
\r
813 DebugLog1("stopRecording() error.\n");
\r
817 DebugLog2("stopRecording() ok\n");
\r
818 DebugLog0("stop recording of \"%s\"", _tuners[tuner]->name());
\r
821 array->removeObject(epg);
\r
823 if (array->count() > 0)
\r
825 epg = (Dictionary *)array->objectAtIndex(0);
\r
831 need_update = true;
\r
843 bool start_need = false;
\r
845 getTimeWithEPG(epg, &start, &end);
\r
846 if ((start != 0) && (end != 0))
\r
848 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
849 if ((status == NULL) || !(status->isEqualToString("running")))
\r
851 if (end + OFFSET_OF_END_TIME <= now)
\r
853 // 既に終了時間が経過しているので削除する
\r
854 array->removeObject(epg);
\r
856 else if (start + OFFSET_OF_START_TIME <= now)
\r
865 DebugLog2("I need start.\n");
\r
866 String *ch = epg->stringForKey(KEY_EPG_CHANNEL);
\r
869 int channel = atoi(ch->cString());
\r
870 DebugLog2("channel: %d\n", channel);
\r
871 std::string videopath = createVideoPath(tuner);
\r
872 if (videopath != "")
\r
874 DebugLog2("videopath: %s\n", videopath.c_str());
\r
876 if (_sopen_s(&fd, videopath.c_str(),
\r
877 (_O_CREAT | _O_EXCL | _O_WRONLY | _O_BINARY | _O_TRUNC), _SH_DENYRW, (_S_IREAD | _S_IWRITE)) == 0)
\r
879 DebugLog2("open ok.\n");
\r
880 bool startResult = true;
\r
881 if (_tuners[tuner]->channel() != channel)
\r
883 if (!setChannel(tuner, channel))
\r
885 DebugLog3("setChannel() ng.");
\r
886 startResult = false;
\r
892 if (_tuners[tuner]->startRecording(fd))
\r
894 DebugLog2("startRecording() ok.");
\r
895 DebugLog0("start recording of \"%s\" to %s.", _tuners[tuner]->name(), videopath.c_str());
\r
899 DebugLog3("Tuner::startRecording() failed.");
\r
900 startResult = false;
\r
906 epg->setString("running", KEY_EPG_STATUS);
\r
915 DebugLog0("open ng. 0x%08x\n", errno);
\r
920 DebugLog0("Can't create videopath.\n");
\r
925 DebugLog0("error.\n");
\r
933 _reservations->writeToFile(_reservations_path, true);
\r
938 String *collect_str = _props->stringForKey(KEY_COLLECT_EPG_TIME);
\r
939 if (collect_str != NULL)
\r
942 time_t collect_time = 0;
\r
943 getTimeWithString(collect_str, &collect_time);
\r
946 if ((collect_time <= now) && (now < collect_time + 1))
\r
949 if ((_timer_epg_s == NULL) || !_timer_epg_s->valid())
\r
951 // EPG収集用タイマ起動(ISDB-S)
\r
952 RELEASE(_timer_epg_s);
\r
953 _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);
\r
954 if (_timer_epg_s != NULL)
\r
956 _timer_epg_s->fire();
\r
961 if ((_timer_epg_t == NULL) || !_timer_epg_t->valid())
\r
963 // EPG収集用タイマ起動(ISDB-T)
\r
964 RELEASE(_timer_epg_t);
\r
965 _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);
\r
966 if (_timer_epg_t != NULL)
\r
968 _timer_epg_t->fire();
\r
979 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
980 // ただし、windowsは精度が低いので期待しないことw
\r
983 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
984 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
986 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
990 GetSystemTimeAsFileTime(&ft);
\r
993 __time64_t now_sec;
\r
994 __time64_t now_usec;
\r
995 now_sec = ft.dwHighDateTime;
\r
997 now_sec |= ft.dwLowDateTime;
\r
998 now_sec /= 10; /*convert into microseconds*/
\r
999 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
1000 now_usec = (now_sec % 1000000UL);
\r
1001 now_sec = now_sec / 1000000UL;
\r
1003 TimeInterval interval = (TimeInterval)now_usec;
\r
1004 interval = interval / 1000000;
\r
1005 _timer_periodic->setTimeInterval(1.005 - interval);
\r
1007 #ifdef OBJC_MEMORY_CHECK
\r
1008 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
1012 void Controller::updateKeywordsReservation()
\r
1014 DebugLog2("Controller::updateKeywordsReservation()");
\r
1019 // 予約情報からキーワード予約フラグが設定されているものを削除
\r
1020 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
1022 Array *epgs = _reservations->arrayForKey(_tuners[tuner]->name());
\r
1025 for (uint epgs_idx_offset = epgs->count(); epgs_idx_offset > 0; --epgs_idx_offset)
\r
1027 Dictionary *epg = (Dictionary *)epgs->objectAtIndex(epgs_idx_offset - 1);
\r
1028 if (epg->boolForKey(KEY_EPG_RESERVED_BY_KEYWORDS))
\r
1030 epgs->removeObject(epg);
\r
1037 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
1038 if (keywords_info != NULL)
\r
1042 // _epgs からキー(サービスID)を取得
\r
1043 Array *service_id_keys = _epgs->allKeys();
\r
1046 for (uint service_id_keys_idx = 0; service_id_keys_idx < service_id_keys->count(); ++service_id_keys_idx)
\r
1049 String *service_id = (String *)service_id_keys->objectAtIndex(service_id_keys_idx);
\r
1052 String *stationName = stationNameForServiceID(service_id);
\r
1053 if (stationName == NULL)
\r
1055 // 局名が取得できなかったら次のサービスIDへ
\r
1059 // 指定サービスIDのEPGを取得
\r
1060 Dictionary *events = _epgs->dictionaryForKey((String *)service_id_keys->objectAtIndex(service_id_keys_idx));
\r
1063 Array *event_id_keys = events->allKeys();
\r
1066 for (uint event_id_keys_idx = 0; event_id_keys_idx < event_id_keys->count(); ++event_id_keys_idx)
\r
1068 // 指定イベントIDのEPGを取得
\r
1069 Dictionary *epg = events->dictionaryForKey((String *)event_id_keys->objectAtIndex(event_id_keys_idx));
\r
1071 // 取得したEPGがキーワードの条件にマッチするか
\r
1074 getTimeWithString(epg->stringForKey(KEY_EPG_START), &start);
\r
1077 Array *keywords = keywords_info->allKeys();
\r
1078 for (uint keywords_idx = 0; keywords_idx < keywords->count(); ++keywords_idx)
\r
1081 String *kwd = (String *)keywords->objectAtIndex(keywords_idx);
\r
1084 Array *kwds = kwd->componentsSeparatedByString(",");
\r
1091 Dictionary *kwdinf = keywords_info->dictionaryForKey(kwd);
\r
1094 String *kwdinf_service_id = kwdinf->stringForKey(KEY_EPG_SERVICE_ID);
\r
1095 if (kwdinf_service_id != NULL)
\r
1098 String *sname = stationNameForServiceID(kwdinf_service_id);
\r
1099 if (sname != NULL)
\r
1101 if (!stationName->isEqualToString(sname))
\r
1103 // 局名が異なる場合は次のキーワードへ
\r
1110 String *kwdinf_start = kwdinf->stringForKey(KEY_EPG_START);
\r
1111 if (kwdinf_start != NULL)
\r
1114 String *st = kwdinf_start->stringByAppendingString(":00");
\r
1115 time_t kwd_st, kwd_ed;
\r
1116 getTimeWithString(st, &kwd_st);
\r
1117 kwd_ed = kwd_st + 3600;
\r
1119 // 開始時刻フィルタの時刻 <= EPGの開始時刻 <= 開始時刻フィルタの時刻+60min ならOK
\r
1120 if ((kwd_st > start) || (start > kwd_ed))
\r
1128 String *title = epg->stringForKey(KEY_EPG_TITLE);
\r
1129 bool title_flag = (title != NULL);
\r
1132 String *desc = epg->stringForKey(KEY_EPG_DESCRIPTION);
\r
1133 bool desc_flag = (desc != NULL);
\r
1135 // キーワード(分割)がタイトル/概要のどちらかに、全て(AND)含まれていたら予約対象とする
\r
1136 for (uint kwds_idx = 0; kwds_idx < kwds->count(); ++kwds_idx)
\r
1138 String *kw = ((String *)kwds->objectAtIndex(kwds_idx))->stringByTrimming();
\r
1141 if (title != NULL)
\r
1143 Range r = title->rangeOfString(kw);
\r
1144 if (r.location == NotFound)
\r
1146 title_flag = false;
\r
1153 Range r = desc->rangeOfString(kw);
\r
1154 if (r.location == NotFound)
\r
1156 desc_flag = false;
\r
1161 if (title_flag || desc_flag)
\r
1163 // タイトル/概要のどちらかに、キーワード(分割)が全て含まれていたので
\r
1164 // この EPG を予約対象とする
\r
1165 Dictionary *epg2 = Dictionary::dictionaryWithDictionary(epg);
\r
1168 DebugLog0("kwd: %s", kwd->cString());
\r
1169 if (title != NULL)
\r
1171 DebugLog0("title: %s", title->cString());
\r
1175 DebugLog0("desc: %s", desc->cString());
\r
1177 epg2->setBool(true, KEY_EPG_RESERVED_BY_KEYWORDS);
\r
1190 void Controller::updateSchedule()
\r
1192 DebugLog2("Controller::updateSchedule()");
\r
1198 time_t resume_time = 0;
\r
1201 String *collect_epg_time = _props->stringForKey(KEY_COLLECT_EPG_TIME);
\r
1202 if (collect_epg_time != NULL)
\r
1204 getTimeWithString(collect_epg_time, &resume_time);
\r
1208 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
1210 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
1211 if ((array == NULL) || (array->count() == 0))
\r
1217 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
1220 getTimeWithEPG(epg, &start, &end);
\r
1221 if ((start != 0) && (end != 0))
\r
1223 if (start < resume_time)
\r
1225 resume_time = start;
\r
1232 resume_time += OFFSET_OF_WAKEUP; // 起動時刻を 5分前に設定(OFFSET_OF_WAKEUPで調整)
\r
1233 if (localtime_s(&resume_tm, &resume_time) == 0)
\r
1235 resetWakeSchedule();
\r
1236 if (setWakeSchedule(resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min))
\r
1238 DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",
\r
1239 resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);
\r
1249 #pragma mark ------- チューナ制御 -------
\r
1252 void Controller::scanChannel(int tuner)
\r
1254 DebugLog2("Controller::scanChannel(%d)", tuner);
\r
1256 if ((tuner < 0) || (_tunerCount <= tuner))
\r
1258 DebugLog3("Invalid tuner: %d", tuner);
\r
1262 DebugLog0("start channel scan of \"%s\".", _tuners[tuner]->name());
\r
1267 // 設定ファイルから全チューナ情報取得
\r
1268 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
1269 if (tunersInfo == NULL)
\r
1272 tunersInfo = Dictionary::dictionaryWithCapacity(0);
\r
1273 _props->setObject(tunersInfo, KEY_TUNERS);
\r
1276 // 全チューナ情報から指定のチューナ情報を取得
\r
1277 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1278 if (tunerInfo == NULL)
\r
1281 tunerInfo = Dictionary::dictionaryWithCapacity(0);
\r
1282 tunersInfo->setObject(tunerInfo, _tuners[tuner]->name());
\r
1286 tunerInfo->setBool(false, KEY_INITIALIZED);
\r
1292 Dictionary *channels = Dictionary::dictionaryWithCapacity(0);
\r
1293 tunerInfo->setObject(channels, KEY_CHANNELS);
\r
1295 // チューナタイプにより最大チャンネル数を設定
\r
1297 Tuner::Type type = _tuners[tuner]->type();
\r
1298 if (type == Tuner::ISDB_S)
\r
1300 max_channel = Tuner::MAX_CHANNELS_ISDB_S;
\r
1304 max_channel = Tuner::MAX_CHANNELS_ISDB_T;
\r
1307 // 最終設定成功チャンネル保持用変数
\r
1308 int lastChannel = -1;
\r
1311 for (int ch = 0; ch <= max_channel; ++ch)
\r
1314 Dictionary *channelInfo = Dictionary::dictionaryWithCapacity(0);
\r
1316 // チャンネルキー(10進数:PTに対するチャンネル番号)
\r
1318 sprintf_s(chkey, sizeof(chkey), "%03d", ch);
\r
1319 channels->setObject(channelInfo, chkey);
\r
1321 // チャンネルID(論理チャンネル番号)
\r
1322 char channelID[8];
\r
1323 if (type == Tuner::ISDB_S)
\r
1327 sprintf_s(channelID, sizeof(channelID), "BS%02d", 1 + 2 * ch);
\r
1331 sprintf_s(channelID, sizeof(channelID), "ND%02d", 2 + 2 * (ch - 12));
\r
1335 sprintf_s(channelID, sizeof(channelID), "ND%02d", 1 + 2 * (ch -24));
\r
1340 static int TABLE[][3] =
\r
1350 for (i = 0; i < sizeof(TABLE)/sizeof(*TABLE); ++i)
\r
1352 if (ch <= TABLE[i][0])
\r
1354 sprintf_s(channelID, sizeof(channelID), "%s%d", TABLE[i][1] ? "C" : "", ch + TABLE[i][2] - TABLE[i][0]);
\r
1361 channelInfo->setString(channelID, KEY_CHANNEL_ID);
\r
1367 if (_tuners[tuner]->setChannel(ch))
\r
1370 DebugLog0(" CH %s: OK", chkey);
\r
1373 channelInfo->setBool(true, KEY_ENABLED);
\r
1376 MPEG2::TS::Analyzer an;
\r
1377 an.setFlag(MPEG2::TS::Analyzer::FLAG_SDT);
\r
1378 _tuners[tuner]->setListener(&an);
\r
1379 uint32_t count = 0;
\r
1380 while (count++ < 8)
\r
1382 Dictionary *stationInfo = an.stationInfo();
\r
1383 if (stationInfo != NULL)
\r
1385 if (stationInfo->stringForKey(KEY_NAME) != NULL)
\r
1387 channelInfo->setString(stationInfo->stringForKey(KEY_NAME), KEY_NAME);
\r
1389 if (stationInfo->objectForKey(KEY_SERVICES) != NULL)
\r
1391 channelInfo->setObject(stationInfo->objectForKey(KEY_SERVICES), KEY_SERVICES);
\r
1395 if ((channelInfo->stringForKey(KEY_NAME) != NULL) && (channelInfo->objectForKey(KEY_SERVICES) != NULL))
\r
1401 if (channelInfo->stringForKey(KEY_NAME) != NULL)
\r
1403 DebugLog0(" Name: %s", channelInfo->stringForKey(KEY_NAME)->cString());
\r
1405 _tuners[tuner]->setListener(NULL);
\r
1412 DebugLog0(" CH %s: NG", chkey);
\r
1423 tunerInfo->setBool(true, KEY_INITIALIZED);
\r
1425 // 設定が成功したチャンネルが有るか
\r
1426 if (lastChannel >= 0)
\r
1429 tunerInfo->setBool(true, KEY_ENABLED);
\r
1431 // 最終チャンネルをステータスファイルに設定
\r
1432 Dictionary *tunersInfo = _status->dictionaryForKey(KEY_TUNERS);
\r
1433 if (tunersInfo == NULL)
\r
1435 tunersInfo = Dictionary::dictionaryWithCapacity(0);
\r
1436 _status->setObject(tunersInfo, KEY_TUNERS);
\r
1439 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1440 if (tunerInfo == NULL)
\r
1442 tunerInfo = Dictionary::dictionaryWithCapacity(0);
\r
1443 tunersInfo->setObject(tunerInfo, _tuners[tuner]->name());
\r
1446 tunerInfo->setInteger(lastChannel, KEY_CHANNEL);
\r
1448 _status->writeToFile(_status_path, false);
\r
1452 _props->writeToFile(_props_path, true);
\r
1458 int Controller::getChannel(int tuner)
\r
1460 DebugLog2("Controller::getChannel()");
\r
1464 if ((0 <= tuner) && (tuner < _tunerCount))
\r
1469 Dictionary *tunersInfo = _status->dictionaryForKey(KEY_TUNERS);
\r
1470 if (tunersInfo != NULL)
\r
1472 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1473 if (tunerInfo != NULL)
\r
1475 channel = tunerInfo->integerForKey(KEY_CHANNEL);
\r
1486 bool Controller::setChannel(int tuner, int channel)
\r
1488 DebugLog2("Controller::setChannel()");
\r
1490 bool result = false;
\r
1492 if ((0 <= tuner) && (tuner < _tunerCount))
\r
1497 if (!_tuners[tuner]->isLocked())
\r
1499 Dictionary *tunersInfo = _status->dictionaryForKey(KEY_TUNERS);
\r
1500 if (tunersInfo == NULL)
\r
1502 tunersInfo = Dictionary::dictionaryWithCapacity(0);
\r
1503 _status->setObject(tunersInfo, KEY_TUNERS);
\r
1506 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1507 if (tunerInfo == NULL)
\r
1509 tunerInfo = Dictionary::dictionaryWithCapacity(0);
\r
1510 tunersInfo->setObject(tunerInfo, _tuners[tuner]->name());
\r
1513 if (channel != _tuners[tuner]->channel())
\r
1515 if (_tuners[tuner]->setChannel(channel))
\r
1517 tunerInfo->setInteger(channel, KEY_CHANNEL);
\r
1519 _status->writeToFile(_status_path, false);
\r
1525 DebugLog0("set channel failed. %d, %d", tuner, channel);
\r
1539 #pragma mark ------- システム関連 周期処理 -------
\r
1543 // チューナ(streaming)制御/システム関連 周期処理
\r
1545 void Controller::periodic_2(void)
\r
1551 // マッピング(UDPPort:tuner,ch)情報取得
\r
1552 Dictionary *mapping = NULL;
\r
1553 if ((_streaming_ctrls != NULL) && ((mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL)) != NULL))
\r
1558 // どれだけ使用中なのか不明なので、まずは必要サイズを調べる
\r
1560 if (GetExtendedUdpTable(NULL, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
1562 // ERROR_INSUFFICIENT_BUFFER の場合、必要なバッファサイズが size に格納される
\r
1565 PMIB_UDPTABLE_OWNER_PID udptable = (PMIB_UDPTABLE_OWNER_PID)malloc(size);
\r
1566 if (udptable != NULL)
\r
1571 if (GetExtendedUdpTable(udptable, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == NO_ERROR)
\r
1574 DebugLog3("udptable->dwNumEntries: %d", udptable->dwNumEntries);
\r
1577 Dictionary *using_port = _streaming_ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
1578 if (using_port != NULL)
\r
1581 Array *using_ports = using_port->allKeys();
\r
1582 if (using_ports != NULL)
\r
1585 for (uint i = 0; i < using_ports->count(); ++i)
\r
1588 bool stop_need = true;
\r
1591 for (uint j = 0; j < udptable->dwNumEntries; ++j)
\r
1593 if (((String *)using_ports->objectAtIndex(i))->intValue() == ntohs((WORD)udptable->table[j].dwLocalPort))
\r
1596 stop_need = false;
\r
1605 String *tuner_and_channel = mapping->stringForKey((String *)using_ports->objectAtIndex(i));
\r
1606 if (tuner_and_channel != NULL)
\r
1609 Range r = tuner_and_channel->rangeOfString(",");
\r
1610 if (r.location != NotFound)
\r
1612 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
1613 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
1614 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
1616 DebugLog0("auto streaming stop: %s", ((String *)using_ports->objectAtIndex(i))->cString());
\r
1618 _tuners[tuner]->stopStreaming();
\r
1619 using_port->removeObjectForKey((String *)using_ports->objectAtIndex(i));
\r
1629 for (uint i = 0; i < udptable->dwNumEntries; ++i)
\r
1633 sprintf_s(port, "%d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
1634 DebugLog3("port = %s", port);
\r
1637 String *tuner_and_channel = mapping->stringForKey(port);
\r
1638 if (tuner_and_channel != NULL)
\r
1640 // 取得OK: 監視対象ポートが使用されている
\r
1643 bool auto_streaming = false;
\r
1644 char exec_path[MAX_PATH];
\r
1645 memset(exec_path, 0, sizeof(exec_path));
\r
1648 size_t returnValue;
\r
1649 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, udptable->table[i].dwOwningPid);
\r
1650 if (hProcess != NULL)
\r
1652 TCHAR exec[MAX_PATH];
\r
1653 memset(exec, 0, sizeof(exec));
\r
1654 DWORD len = sizeof(exec) - 1;
\r
1657 if (QueryFullProcessImageName(hProcess, 0, exec, &len))
\r
1660 if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) == 0)
\r
1664 // とりあえず、、、現状は "ffmpeg.exe" / "vlc.exe" / "Kodi.exe" があったら auto_streaming を true にする
\r
1665 if ((strstr(exec_path, "ffmpeg.exe") != NULL) ||
\r
1666 (strstr(exec_path, "vlc.exe") != NULL) ||
\r
1667 (strstr(exec_path, "Kodi.exe") != NULL))
\r
1669 auto_streaming = true;
\r
1675 CloseHandle(hProcess);
\r
1678 if (auto_streaming)
\r
1681 Range r = tuner_and_channel->rangeOfString(",");
\r
1682 if (r.location != NotFound)
\r
1684 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
1685 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
1686 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
1691 // 非ストリーミング中 かつ 非レコーディング中 または チャンネルが同じ 場合
\r
1692 if (!_tuners[tuner]->isStreaming() && (!_tuners[tuner]->isRecording() || _tuners[tuner]->channel() == channel))
\r
1696 if (_tuners[tuner]->channel() != channel)
\r
1698 setChannel(tuner, channel);
\r
1701 SOCKADDR_IN dst_addr;
\r
1702 dst_addr.sin_family = AF_INET;
\r
1703 dst_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
\r
1704 dst_addr.sin_port = (WORD)udptable->table[i].dwLocalPort;
\r
1706 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
1709 DebugLog0("auto streaming start: %d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
1712 using_port = _streaming_ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
1713 if (using_port == NULL)
\r
1715 using_port = Dictionary::dictionaryWithCapacity(0);
\r
1716 _streaming_ctrls->setObject(using_port, KEY_UDP_IN_USE);
\r
1718 using_port->setBool(true, port);
\r
1739 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
1740 if (hls_info != NULL)
\r
1742 for (int i = 0; i < _tunerCount; ++i)
\r
1745 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[i]->name());
\r
1746 if (hls_info_tuner != NULL)
\r
1748 int counter = hls_info_tuner->integerForKey(KEY_COUNTER);
\r
1751 hls_info_tuner->setInteger(counter + 1, KEY_COUNTER);
\r
1755 hls_info->removeObjectForKey(_tuners[i]->name());
\r
1764 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
1767 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
1768 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
1770 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
1774 GetSystemTimeAsFileTime(&ft);
\r
1777 __time64_t now_sec;
\r
1778 __time64_t now_usec;
\r
1779 now_sec = ft.dwHighDateTime;
\r
1781 now_sec |= ft.dwLowDateTime;
\r
1782 now_sec /= 10; /*convert into microseconds*/
\r
1783 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
1784 now_usec = (now_sec % 1000000UL);
\r
1785 now_sec = now_sec / 1000000UL;
\r
1787 TimeInterval interval = (TimeInterval)now_usec;
\r
1788 interval = interval / 1000000;
\r
1789 _timer_periodic_2->setTimeInterval(1.005 - interval);
\r
1794 #pragma mark ------- HTTP制御 -------
\r
1797 static std::string epg_regist_form(Dictionary *epg)
\r
1799 DebugLog3("epg_regist_form() start.");
\r
1803 if ((epg != NULL) &&
\r
1804 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
1805 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
1806 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
1807 (epg->stringForKey(KEY_EPG_END) != NULL) &&
\r
1808 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
1809 (epg->stringForKey(KEY_EPG_TITLE) != NULL))
\r
1811 epgs += "<form id=\"";
\r
1813 epgs += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
1815 epgs += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
1816 epgs += "\" title=\"";
\r
1817 epgs += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
1819 epgs += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
1820 epgs += "\" class=\"panel\" action=\"regist.cgi\" method=\"GET\" target=\"_self\" onclick='return confirm(\"Is it ok?\");'>";
\r
1824 epgs += LocalizedString(KEY_I18N_Broadcasting_Time, NULL)->cString();
\r
1826 epgs += "<fieldset>";
\r
1827 epgs += "<p class=\"normalText\"> ";
\r
1828 epgs += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
1830 epgs += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
1832 epgs += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
1834 epgs += "</fieldset>";
\r
1838 epgs += LocalizedString(KEY_I18N_Program_Title, NULL)->cString();
\r
1840 epgs += "<fieldset>";
\r
1841 epgs += "<p class=\"normalText\"> ";
\r
1842 epgs += epg->stringForKey(KEY_EPG_TITLE)->cString();
\r
1844 epgs += "</fieldset>";
\r
1847 if (epg->stringForKey(KEY_EPG_DESCRIPTION) != NULL)
\r
1850 epgs += LocalizedString(KEY_I18N_Description, NULL)->cString();
\r
1852 epgs += "<fieldset>";
\r
1853 epgs += "<p class=\"normalText\"> ";
\r
1854 epgs += epg->stringForKey(KEY_EPG_DESCRIPTION)->cString();
\r
1856 epgs += "</fieldset>";
\r
1860 epgs += "<input type=\"hidden\" name=\"service_id\" value=\"";
\r
1861 epgs += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
1863 epgs += "<input type=\"hidden\" name=\"event_id\" value=\"";
\r
1864 epgs += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
1866 epgs += "<input class=\"redButton\" type=\"submit\" value=\"";
\r
1867 epgs += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
1869 // epgs += "<a class=\"redButton\" type=\"submit\">";
\r
1870 // epgs += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
1871 // epgs += "</a>";
\r
1872 epgs += "</form>";
\r
1878 HTTPResponse *responseWithDictionary(HTTPRequest *request, Dictionary *dictionary)
\r
1880 HTTPResponse *result = NULL;
\r
1881 if ((request != NULL) && (dictionary != NULL))
\r
1883 std::string xml = dictionary->toString();
\r
1886 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
1889 // Content-Encoding
\r
1892 header->setFieldBodyWithName("application/xml", "Content-Type");
\r
1894 // Tranfer-Encoding
\r
1896 header->setFieldBodyWithName(String::stringWithFormat("%I64u", xml.length()), "Content-Length");
\r
1899 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(xml.c_str()));
\r
1902 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
1905 if (message != NULL)
\r
1907 result = HTTPResponse::alloc()->init();
\r
1908 result->autorelease();
\r
1909 result->setVersion(request->version());
\r
1910 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
1911 result->setStatus(200);
\r
1912 result->setMessage(message);
\r
1919 // positive response by XML
\r
1920 HTTPResponse *responseForSuccess(HTTPRequest *request)
\r
1922 Dictionary *dict = Dictionary::dictionaryWithCapacity(0);
\r
1923 dict->setString("Success", KEY_RESULT);
\r
1924 return responseWithDictionary(request, dict);
\r
1927 // negative response by XML
\r
1928 HTTPResponse *responseForFailed(HTTPRequest *request)
\r
1930 Dictionary *dict = Dictionary::dictionaryWithCapacity(0);
\r
1931 dict->setString("Failed", KEY_RESULT);
\r
1932 return responseWithDictionary(request, dict);
\r
1935 HTTPResponse *Controller::responseWithHTML(HTTPRequest *request, String *html)
\r
1937 HTTPResponse *result = NULL;
\r
1938 if ((html != NULL) && (request != NULL))
\r
1941 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
1944 // Content-Encoding
\r
1947 header->setFieldBodyWithName("text/html", "Content-Type");
\r
1949 // Tranfer-Encoding
\r
1951 header->setFieldBodyWithName(String::stringWithFormat("%I64u", html->length()), "Content-Length");
\r
1954 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(html);
\r
1957 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
1960 if (message != NULL)
\r
1962 // result = HTTPResponse::response();
\r
1963 result = HTTPResponse::alloc()->init();
\r
1964 result->setVersion(request->version());
\r
1965 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
1966 result->setStatus(200);
\r
1967 result->setMessage(message);
\r
1968 result->autorelease();
\r
1975 HTTPResponse *Controller::responseWithUTF8Text(HTTPRequest *request, String *text)
\r
1977 HTTPResponse *result = NULL;
\r
1978 if ((text != NULL) && (request != NULL))
\r
1981 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
1984 // Content-Encoding
\r
1987 header->setFieldBodyWithName("text/plane; charset=UTF-8", "Content-Type");
\r
1989 // Tranfer-Encoding
\r
1991 header->setFieldBodyWithName(String::stringWithFormat("%I64u", text->length()), "Content-Length");
\r
1994 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(text);
\r
1997 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
2000 if (message != NULL)
\r
2002 // result = HTTPResponse::response();
\r
2003 result = HTTPResponse::alloc()->init();
\r
2004 result->setVersion(request->version());
\r
2005 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
2006 result->setStatus(200);
\r
2007 result->setMessage(message);
\r
2008 result->autorelease();
\r
2015 HTTPResponse *Controller::responseByResultAndReferer(HTTPRequest *request, bool result, const char *referer)
\r
2017 HTTPResponse *retval = NULL;
\r
2021 String *ref = NULL;
\r
2022 InternetTextMessage *msg = request->message();
\r
2025 InternetTextMessageHeader *header = msg->header();
\r
2026 if (header != NULL)
\r
2028 String *field_referer = header->fieldBodyForName("Referer");
\r
2029 if (field_referer != NULL)
\r
2031 String *field_host = header->fieldBodyForName("Host");
\r
2032 if (field_host != NULL)
\r
2034 std::string tmp = "http://";
\r
2035 tmp += field_host->cString();
\r
2038 iui = field_referer->isEqualToString(tmp.c_str());
\r
2039 DebugLog2("tmp: %s", tmp.c_str());
\r
2040 DebugLog2("ref: %s", field_referer->cString());
\r
2045 // if ((ref != NULL) && match(ref->cString(), referer))
\r
2046 // if ((ref != NULL) && ref->isEqualToString(referer))
\r
2049 String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");
\r
2050 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2053 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", "Result");
\r
2054 std::string contents;
\r
2055 std::string reservations;
\r
2056 contents += "<div id=\"home\" class=\"panel\" title=\"Result\" selected=\"true\">";
\r
2059 contents += "<h2>Success</h2>";
\r
2063 contents += "<h2>Failed</h2>";
\r
2065 contents += "</div>";
\r
2067 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2068 retval = responseWithHTML(request, html);
\r
2075 retval = responseForSuccess(request);
\r
2079 retval = responseForFailed(request);
\r
2086 HTTPResponse *Controller::responseForMain(HTTPRequest *request, SOCKADDR_IN *client)
\r
2088 DebugLog2("Controller::responseForMain()");
\r
2090 HTTPResponse *result = NULL;
\r
2091 while ((request != NULL) && (client != NULL))
\r
2093 String *path = _httpd->rootPath();
\r
2096 DebugLog3("_httpd->rootPath() ng.");
\r
2100 path = path->stringByAppendingPathComponent("template1.html");
\r
2103 DebugLog3("path->stringByAppendingPathComponent() ng.");
\r
2107 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2110 DebugLog3("String::stringWithContentsOfFile() ng.");
\r
2114 String *server_name = _props->stringForKey(KEY_NAME);
\r
2115 if (server_name == NULL)
\r
2117 DebugLog3("_props->stringForKey(KEY_NAME) ng.");
\r
2121 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", server_name);
\r
2124 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2128 html = html->stringByReplacingOccurrencesOfString("%%PAGE_TITLE%%", LocalizedString(KEY_I18N_Main_Menu, NULL));
\r
2131 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2134 std::string contents;
\r
2135 contents += "<div id=\"home\" class=\"panel\" selected=\"true\">";
\r
2136 contents += "<ul>";
\r
2137 contents += "<li><a target=\"_self\" href=\"/programs.html\">";
\r
2138 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2139 contents += "</a></li>";
\r
2140 contents += "<li><a target=\"_self\" href=\"/tv.html\">";
\r
2141 contents += LocalizedString(KEY_I18N_TV, NULL)->cString();
\r
2142 contents += "</a></li>";
\r
2143 contents += "<li><a target=\"_self\" href=\"/video.html\">";
\r
2144 contents += LocalizedString(KEY_I18N_Video, NULL)->cString();
\r
2145 contents += "</a></li>";
\r
2146 contents += "<li><a target=\"_self\" href=\"/reservation.html\">";
\r
2147 contents += LocalizedString(KEY_I18N_Reservation, NULL)->cString();
\r
2148 contents += "</a></li>";
\r
2149 contents += "</ul>";
\r
2151 contents += "<ul>";
\r
2152 contents += "<li><a target=\"_self\" href=\"/exec_vlc.html\">VLC media player";
\r
2153 contents += "</ul>";
\r
2155 contents += "<ul>";
\r
2156 contents += "<li><a target=\"_self\" href=\"/status.html\">";
\r
2157 contents += LocalizedString(KEY_I18N_Tuner_Status, NULL)->cString();
\r
2158 contents += "</a></li>";
\r
2159 contents += "</ul>";
\r
2160 contents += "<center><a target=\"_self\" href=\"/iptd.log\">Ver. ";
\r
2161 contents += VERSION;
\r
2162 contents += "</a></center>";
\r
2163 contents += "</div>";
\r
2165 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2168 result = responseWithHTML(request, html);
\r
2177 HTTPResponse *Controller::responseForPrograms(HTTPRequest *request, SOCKADDR_IN *client)
\r
2179 DebugLog2("Controller::responseForPrograms() start.");
\r
2181 HTTPResponse *result = NULL;
\r
2182 while ((request != NULL) && (client != NULL))
\r
2184 String *path = _httpd->rootPath();
\r
2187 DebugLog3("_httpd->rootPath() ng.");
\r
2191 path = path->stringByAppendingPathComponent("template2.html");
\r
2194 DebugLog3("path->stringByAppendingPathComponent() ng.");
\r
2198 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2201 DebugLog3("String::stringWithContentsOfFile() ng.");
\r
2205 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Programs, NULL));
\r
2208 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2212 std::string contents;
\r
2215 contents += "<ul id=\"home\" title=\"";
\r
2216 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2217 contents += "\" selected=\"true\">";
\r
2219 contents += "<li>";
\r
2220 contents += "<a href=\"#isdb_t\">";
\r
2221 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2222 contents += "</a></li>";
\r
2224 contents += "<li>";
\r
2225 contents += "<a href=\"#isdb_s\">";
\r
2226 contents += "BS/CS";
\r
2227 contents += "</a></li>";
\r
2229 contents += "</ul>";
\r
2232 contents += "<ul id=\"isdb_t\" title=\"";
\r
2233 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2234 contents += "\">";
\r
2235 Array *stations = stationInfos(Tuner::ISDB_T);
\r
2236 for (uint i = 0; i < stations->count(); ++i)
\r
2238 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2239 if ((station != NULL) &&
\r
2240 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2241 (station->stringForKey(KEY_NAME) != NULL))
\r
2243 contents += "<li>";
\r
2244 contents += "<a href=\"#isdb_t_";
\r
2245 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2246 contents += "\">";
\r
2247 contents += station->stringForKey(KEY_NAME)->cString();
\r
2248 contents += "</a></li>";
\r
2251 contents += "</ul>";
\r
2254 for (uint i = 0; i < stations->count(); ++i)
\r
2256 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2257 if ((station != NULL) &&
\r
2258 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2259 (station->stringForKey(KEY_NAME) != NULL))
\r
2262 contents += "<ul id=\"isdb_t_";
\r
2263 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2264 contents += "\" title=\"";
\r
2265 contents += station->stringForKey(KEY_NAME)->cString();
\r
2266 contents += "\">";
\r
2268 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2269 for (uint i = 0; i < programs->count(); ++i)
\r
2271 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2272 if ((epg != NULL) &&
\r
2273 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2274 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2275 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2276 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2277 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2279 contents += "<li>";
\r
2280 contents += "<a href=\"#epg_";
\r
2281 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2283 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2284 contents += "\">";
\r
2285 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2286 contents += " ";
\r
2287 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2289 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2290 contents += "</a></li>";
\r
2292 epgs += epg_regist_form(epg);
\r
2295 contents += "</ul>";
\r
2300 contents += "<ul id=\"isdb_s\" title=\"";
\r
2301 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2302 contents += "\">";
\r
2303 stations = stationInfos(Tuner::ISDB_S);
\r
2304 for (uint i = 0; i < stations->count(); ++i)
\r
2306 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2307 if ((station != NULL) &&
\r
2308 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2309 (station->stringForKey(KEY_NAME) != NULL))
\r
2311 contents += "<li>";
\r
2312 contents += "<a href=\"#isdb_s_";
\r
2313 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2314 contents += "\">";
\r
2315 contents += station->stringForKey(KEY_NAME)->cString();
\r
2316 contents += "</a></li>";
\r
2319 contents += "</ul>";
\r
2322 for (uint i = 0; i < stations->count(); ++i)
\r
2324 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2325 if ((station != NULL) &&
\r
2326 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2327 (station->stringForKey(KEY_NAME) != NULL))
\r
2329 contents += "<ul id=\"isdb_s_";
\r
2330 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2331 contents += "\" title=\"";
\r
2332 contents += station->stringForKey(KEY_NAME)->cString();
\r
2333 contents += "\">";
\r
2335 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2336 for (uint i = 0; i < programs->count(); ++i)
\r
2338 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2339 if ((epg != NULL) &&
\r
2340 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2341 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2342 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2343 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2344 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2346 contents += "<li>";
\r
2347 contents += "<a href=\"#epg_";
\r
2348 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2350 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2351 contents += "\">";
\r
2352 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2353 contents += " ";
\r
2354 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2356 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2357 contents += "</a></li>";
\r
2359 epgs += epg_regist_form(epg);
\r
2362 contents += "</ul>";
\r
2367 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2370 result = responseWithHTML(request, html);
\r
2378 HTTPResponse *Controller::responseForReservation(HTTPRequest *request, SOCKADDR_IN *client)
\r
2380 DebugLog2("Controller::responseForReservation() start.");
\r
2385 HTTPResponse *result = NULL;
\r
2386 while ((request != NULL) && (client != NULL))
\r
2388 // create array of reservations sorted by seq_id.
\r
2389 Array *array = Array::arrayWithCapacity(0);
\r
2390 for (int i = 0; i < _tunerCount; ++i)
\r
2392 Array *tmp = _reservations->arrayForKey(_tuners[i]->name());
\r
2397 for (uint idx = 0; idx < tmp->count(); ++idx)
\r
2399 Dictionary *epg = (Dictionary *)tmp->objectAtIndex(idx);
\r
2407 getTimeWithEPG(epg, &epg_start, &tmp_end);
\r
2409 bool inserted = false;
\r
2410 for (uint j = 0; j < array->count(); ++j)
\r
2412 Dictionary *epg2 = (Dictionary *)array->objectAtIndex(j);
\r
2418 time_t epg2_start;
\r
2419 getTimeWithEPG(epg2, &epg2_start, &tmp_end);
\r
2421 if (epg_start <= epg2_start)
\r
2423 array->insertObject(epg, j);
\r
2431 array->addObject(epg);
\r
2436 String *path = _httpd->rootPath();
\r
2442 path = path->stringByAppendingPathComponent("template2.html");
\r
2448 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2454 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Reservation, NULL));
\r
2460 std::string contents;
\r
2461 std::string reservations;
\r
2462 contents += "<ul id=\"home\" title=\"";
\r
2463 contents += LocalizedString(KEY_I18N_Reservation, NULL)->cString();
\r
2464 contents += "\" selected=\"true\">";
\r
2467 contents += "<li><a href=\"#tuners\">";
\r
2468 contents += "<font color=\"blue\">[";
\r
2469 contents += LocalizedString(KEY_I18N_Tuner, NULL)->cString();
\r
2470 contents += "]</font>";
\r
2471 contents += "</a></li>";
\r
2477 contents += "<li><a href=\"#new_reservation\">";
\r
2478 contents += "<font color=\"red\">[";
\r
2479 contents += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
2480 contents += "]</font>";
\r
2481 contents += "</a></li>";
\r
2486 contents += "<li><a href=\"#keywords\">";
\r
2487 contents += "<font color=\"blue\">[";
\r
2488 contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2489 contents += "]</font>";
\r
2490 contents += "</a></li>";
\r
2495 for (uint i = 0; i < array->count(); ++i)
\r
2497 Dictionary *epg = (Dictionary *)array->objectAtIndex(i);
\r
2499 sprintf_s(seq_id, "%06d", epg->integerForKey(KEY_EPG_RESV_ID) % 1000000);
\r
2500 contents += "<li>";
\r
2501 contents += "<a href=\"#seqid";
\r
2502 contents += seq_id;
\r
2503 contents += "\">";
\r
2504 String *title = epg->stringForKey(KEY_EPG_TITLE);
\r
2505 if (title != NULL)
\r
2507 contents += title->cString();
\r
2513 Controller::getTimeWithEPG(epg, &start, &end);
\r
2515 if (localtime_s(&tm, &start) == 0)
\r
2517 char date_time[24];
\r
2518 sprintf_s(date_time, "%04d/%02d/%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
\r
2519 contents += date_time;
\r
2523 contents += seq_id;
\r
2526 contents += "</a></li>";
\r
2529 reservations += "<div id=\"";
\r
2530 reservations += "seqid";
\r
2531 reservations += seq_id;
\r
2532 reservations += "\" title=\"";
\r
2533 reservations += "xxxxxx";
\r
2534 reservations += "\" class=\"panel\">";
\r
2536 //reservations += "<h2>Status</h2>";
\r
2537 reservations += "<fieldset>";
\r
2540 reservations += "<div class=\"row\">";
\r
2541 reservations += "<label>Date</label>";
\r
2542 reservations += "<span>";
\r
2543 String *tmp = epg->stringForKey(KEY_EPG_DATE);
\r
2544 reservations += tmp->cString();
\r
2545 reservations += "</span>";
\r
2546 reservations += "</div>";
\r
2548 reservations += "<div class=\"row\">";
\r
2549 reservations += "<label>Start</label>";
\r
2550 reservations += "<span>";
\r
2551 tmp = epg->stringForKey(KEY_EPG_START);
\r
2552 reservations += tmp->cString();
\r
2553 reservations += "</span>";
\r
2554 reservations += "</div>";
\r
2556 reservations += "<div class=\"row\">";
\r
2557 reservations += "<label>End</label>";
\r
2558 reservations += "<span>";
\r
2559 tmp = epg->stringForKey(KEY_EPG_END);
\r
2560 reservations += tmp->cString();
\r
2561 reservations += "</span>";
\r
2562 reservations += "</div>";
\r
2564 reservations += "</fieldset>";
\r
2566 reservations += "<a class=\"whiteButton\" type=\"submit\" href=\"/cancel.cgi?";
\r
2567 reservations += "resv_id=";
\r
2568 reservations += seq_id;
\r
2569 reservations += "\" onclick='return confirm(\"To cancel. Is it ok?\");'>";
\r
2570 reservations += LocalizedString(KEY_I18N_Cancel, NULL)->cString();
\r
2571 reservations += "</a>";
\r
2573 reservations += "</div>";
\r
2576 contents += "</ul>";
\r
2577 contents += reservations;
\r
2585 time_t time1 = time(NULL);
\r
2586 time1 = (time1 + 15 * 60) / (15 * 60);
\r
2587 time1 = time1 * 15 * 60;
\r
2588 time_t time2 = time1 + 15 * 60;
\r
2589 localtime_s(&tm1, &time1);
\r
2590 localtime_s(&tm2, &time2);
\r
2592 contents += "<form name=\"reservation\" id=\"new_reservation\" class=\"panel\" method=\"GET\" action=\"regist.cgi\" target=\"_self\">";
\r
2593 contents += "<fieldset>";
\r
2594 contents += "<div class=\"row\">";
\r
2595 contents += "<label>";
\r
2596 contents += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
2597 contents += " : </label>";
\r
2598 contents += "<span>";
\r
2599 contents += "<select name=\"service_id\" size=\"1\">";
\r
2602 Array *stationInfos = Controller::stationInfos(Tuner::ISDB_T);
\r
2603 if (stationInfos != NULL)
\r
2605 stationInfos->addObjectsFromArray(Controller::stationInfos(Tuner::ISDB_S));
\r
2609 stationInfos = Controller::stationInfos(Tuner::ISDB_S);
\r
2611 for (uint i = 0; (stationInfos != NULL) && (i < stationInfos->count()); ++i)
\r
2613 Array *services = ((Dictionary *)stationInfos->objectAtIndex(i))->arrayForKey(KEY_SERVICES);
\r
2615 // とりえあず、現状は最初のサービスのみ表示
\r
2616 // for (uint j = 0; (services != NULL) && (j < services->count()); ++j)
\r
2617 for (uint j = 0; (services != NULL) && (j < 1); ++j)
\r
2619 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
2622 if ((service->stringForKey(KEY_SERVICE_TYPE) != NULL) && service->stringForKey(KEY_SERVICE_TYPE)->isEqualToString("1"))
\r
2624 String *name = service->stringForKey(KEY_NAME);
\r
2625 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
2626 if ((name != NULL) && (sid != NULL))
\r
2628 String *tmp = String::stringWithFormat("<option value=\"%s\">%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
2629 contents += tmp->cString();
\r
2635 contents += "</select>";
\r
2636 contents += "</span>";
\r
2637 contents += "</div>";
\r
2638 contents += "<div class=\"row\">";
\r
2639 contents += "<label>";
\r
2640 contents += LocalizedString(KEY_I18N_Date, NULL)->cString();
\r
2641 contents += " : </label>";
\r
2642 contents += "<span>";
\r
2643 contents += "<select name=\"year\" size=\"1\">";
\r
2644 for (int year = tm1.tm_year + 1900; year < tm1.tm_year + 1900 + 3; ++year)
\r
2646 char year_buf[64];
\r
2647 sprintf_s(year_buf, "<option value=\"%d\">%d</option>", year, year);
\r
2648 contents += year_buf;
\r
2650 contents += "</select>";
\r
2651 contents += "<select name=\"month\" size=\"1\">";
\r
2652 for (int month = 1; month < 13; ++month)
\r
2654 char month_buf[64];
\r
2655 if (month == tm1.tm_mon + 1)
\r
2657 sprintf_s(month_buf, "<option value=\"%d\" selected>%d</option>", month, month);
\r
2661 sprintf_s(month_buf, "<option value=\"%d\">%d</option>", month, month);
\r
2663 contents += month_buf;
\r
2665 contents += "</select>";
\r
2666 contents += "<select name=\"day\" size=\"1\">";
\r
2667 for (int day = 1; day < 32; ++day)
\r
2670 if (day == tm1.tm_mday)
\r
2672 sprintf_s(day_buf, "<option value=\"%d\" selected>%d</option>", day, day);
\r
2676 sprintf_s(day_buf, "<option value=\"%d\">%d</option>", day, day);
\r
2678 contents += day_buf;
\r
2680 contents += "</select>";
\r
2681 contents += "</span>";
\r
2682 contents += "</div>";
\r
2683 contents += "<div class=\"row\">";
\r
2684 contents += "<label>";
\r
2685 contents += LocalizedString(KEY_I18N_Start_Time, NULL)->cString();
\r
2686 contents += " : </label>";
\r
2687 contents += "<span>";
\r
2688 contents += "<select name=\"start_hour\" size=\"1\">";
\r
2689 for (int sh = 0; sh < 24; ++sh)
\r
2692 if (sh == tm1.tm_hour)
\r
2694 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
2698 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
2700 contents += sh_buf;
\r
2702 contents += "</select>";
\r
2703 contents += "<select name=\"start_min\" size=\"1\">";
\r
2704 for (int sm = 0; sm < 60; ++sm)
\r
2707 if (sm == tm1.tm_min)
\r
2709 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
2713 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
2715 contents += sm_buf;
\r
2717 contents += "</select>";
\r
2718 contents += "</span>";
\r
2719 contents += "</div>";
\r
2720 contents += "<div class=\"row\">";
\r
2721 contents += "<label>";
\r
2722 contents += LocalizedString(KEY_I18N_End_Time, NULL)->cString();
\r
2723 contents += " : </label>";
\r
2724 contents += "<span>";
\r
2725 contents += "<select name=\"end_hour\" size=\"1\">";
\r
2726 for (int eh = 0; eh < 24; ++eh)
\r
2729 if (eh == tm2.tm_hour)
\r
2731 sprintf_s(eh_buf, "<option value=\"%02d\" selected>%02d</option>", eh, eh);
\r
2735 sprintf_s(eh_buf, "<option value=\"%02d\">%02d</option>", eh, eh);
\r
2737 contents += eh_buf;
\r
2739 contents += "</select>";
\r
2740 contents += "<select name=\"end_min\" size=\"1\">";
\r
2741 for (int em = 0; em < 60; ++em)
\r
2744 if (em == tm2.tm_min)
\r
2746 sprintf_s(em_buf, "<option value=\"%02d\" selected>%02d</option>", em, em);
\r
2750 sprintf_s(em_buf, "<option value=\"%02d\">%02d</option>", em, em);
\r
2752 contents += em_buf;
\r
2754 contents += "</select>";
\r
2755 contents += "</span>";
\r
2756 contents += "</div>";
\r
2757 contents += "<div class=\"row\">";
\r
2758 contents += "<label>";
\r
2759 contents += LocalizedString(KEY_I18N_Repeat, NULL)->cString();
\r
2760 contents += " : </label>";
\r
2761 contents += "<span>";
\r
2762 contents += "<select name=\"repeat\" size=\"1\">";
\r
2763 contents += "<option value=\"off\" selected>";
\r
2764 contents += LocalizedString(KEY_I18N_Repeat_off, NULL)->cString();
\r
2765 contents += "</option>";
\r
2766 contents += "<option value=\"everyday\">";
\r
2767 contents += LocalizedString(KEY_I18N_Repeat_everyday, NULL)->cString();
\r
2768 contents += "</option>";
\r
2769 contents += "<option value=\"weekly\">";
\r
2770 contents += LocalizedString(KEY_I18N_Repeat_weekly, NULL)->cString();
\r
2771 contents += "</option>";
\r
2772 contents += "<option value=\"weekday\">";
\r
2773 contents += LocalizedString(KEY_I18N_Repeat_weekday, NULL)->cString();
\r
2774 contents += "</option>";
\r
2775 contents += "</select>";
\r
2776 contents += "</span>";
\r
2777 contents += "</div>";
\r
2778 contents += "</fieldset>";
\r
2780 contents += "<input type=\"submit\" class=\"whiteButton\" value=\"";
\r
2781 contents += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
2782 contents += "\">";
\r
2783 contents += "</form>";
\r
2793 contents += "<ul id=\"tuners\" title=\"";
\r
2794 contents += LocalizedString(KEY_I18N_Tuner, NULL)->cString();
\r
2795 contents += "\">";
\r
2797 std::string controls;
\r
2798 Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);
\r
2799 if (tunerInfos != NULL)
\r
2801 for (int i = 0; i < _tunerCount; ++i)
\r
2803 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name());
\r
2804 if (tunerInfo != NULL)
\r
2806 if (tunerInfo->boolForKey(KEY_INITIALIZED) && tunerInfo->boolForKey(KEY_ENABLED))
\r
2809 sprintf_s(key, "%03d", i);
\r
2812 contents += "<li>";
\r
2813 contents += "<a href=\"#tuner";
\r
2815 contents += "\">";
\r
2818 Dictionary *dict = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
2822 sprintf_s(chkey, "%03d", tunerInfo->integerForKey(KEY_CHANNEL));
\r
2823 dict = dict->dictionaryForKey(chkey);
\r
2824 String *name = dict->stringForKey(KEY_NAME);
\r
2827 contents += name->cString();
\r
2836 contents += _tuners[i]->name();
\r
2838 contents += "</a></li>";
\r
2841 controls += "<form name=\"control\" id=\"tuner";
\r
2843 controls += "\" class=\"panel\" method=\"GET\" action=\"/";
\r
2845 controls += "/recording=on\" target=\"_self\">";
\r
2848 controls += "<fieldset>";
\r
2851 controls += "<div class=\"row\">";
\r
2852 controls += "<label>";
\r
2853 controls += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
2854 controls += " : </label>";
\r
2855 controls += "<span>";
\r
2856 controls += "<select name=\"channel\" size=\"1\">";
\r
2857 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
2858 if (channels != NULL)
\r
2860 for (int ch = 0; ch <= Tuner::MAX_CHANNELS_ISDB_T; ++ch)
\r
2863 sprintf_s(chkey, "%03d", ch);
\r
2864 dict = channels->dictionaryForKey(chkey);
\r
2869 Array *services = (Array *)dict->objectForKey(KEY_SERVICES);
\r
2870 if (services != NULL)
\r
2872 for (uint s = 0; s < services->count(); ++s)
\r
2874 Dictionary *service = (Dictionary *)services->objectAtIndex(s);
\r
2875 if (service != NULL)
\r
2878 sprintf_s(sid, "%d", service->integerForKey(KEY_SERVICE_ID));
\r
2879 controls += "<option value=\"";
\r
2880 controls += chkey;
\r
2884 String *name = service->stringForKey(KEY_NAME);
\r
2887 controls += name->cString();
\r
2891 controls += "]</option>";
\r
2897 controls += "</select>";
\r
2898 controls += "</span>";
\r
2899 controls += "</div>";
\r
2903 controls += "<div class=\"row\">";
\r
2904 controls += "<label>";
\r
2905 controls += LocalizedString(KEY_I18N_Time, NULL)->cString();
\r
2906 controls += " : </label>";
\r
2907 controls += "<span>";
\r
2908 controls += "<select name=\"hour\" size=\"1\">";
\r
2909 for (int sh = 0; sh < 24; ++sh)
\r
2914 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
2918 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
2920 controls += sh_buf;
\r
2922 controls += "</select>";
\r
2923 controls += "<select name=\"min\" size=\"1\">";
\r
2924 for (int sm = 0; sm < 60; ++sm)
\r
2929 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
2933 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
2935 controls += sm_buf;
\r
2937 controls += "</select>";
\r
2938 controls += "</span>";
\r
2939 controls += "</div>";
\r
2942 controls += "</fieldset>";
\r
2945 controls += "<input type=\"submit\" class=\"whiteButton\" value=\"";
\r
2946 controls += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
2947 controls += "\">";
\r
2948 controls += "</form>";
\r
2953 contents += "</ul>";
\r
2954 contents += controls;
\r
2963 contents += "<ul id=\"keywords\" title=\"";
\r
2964 contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2965 contents += "\">";
\r
2967 contents += "<li><a href=\"#dialogForm\">";
\r
2968 contents += "<font color=\"red\">[";
\r
2969 // contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2970 contents += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
2971 contents += "]</font>";
\r
2972 contents += "</a></li>";
\r
2975 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
2976 if (keywords_info != NULL)
\r
2979 Array *keys = keywords_info->allKeys();
\r
2982 for (uint i = 0; i < keys->count(); ++i)
\r
2984 Dictionary *kwd_inf = keywords_info->dictionaryForKey((String *)keys->objectAtIndex(i));
\r
2985 if (kwd_inf == NULL)
\r
2991 sprintf_s(tmp, "%d", i);
\r
2992 contents += "<li><a href=\"#keywords_";
\r
2994 contents += "\">";
\r
2995 contents += ((String *)keys->objectAtIndex(i))->cString();
\r
2996 contents += "</a></li>";
\r
2998 controls += "<form name=\"filter\" id=\"keywords_";
\r
3000 controls += "\" class=\"panel\" method=\"GET\" action=\"mod_keywords.cgi\" target=\"_self\">";
\r
3001 controls += "<input type=\"hidden\" name=\"keywords\" value=\"";
\r
3002 controls += ((String *)keys->objectAtIndex(i))->cString();
\r
3003 controls += "\">";
\r
3004 controls += "<fieldset>";
\r
3006 controls += "<div class=\"row\">";
\r
3007 controls += "<label>";
\r
3008 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3009 controls += " : </label>";
\r
3010 controls += "<span>";
\r
3011 controls += ((String *)keys->objectAtIndex(i))->cString();
\r
3012 controls += "</span>";
\r
3013 controls += "</div>";
\r
3015 controls += "<div class=\"row\">";
\r
3016 controls += "<label>";
\r
3017 controls += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
3018 controls += " : </label>";
\r
3019 controls += "<span>";
\r
3020 controls += "<select name=\"service_id\" size=\"1\">";
\r
3021 controls += "<option value=\"-\">----</option>";
\r
3023 String *service_id = kwd_inf->stringForKey(KEY_EPG_SERVICE_ID);
\r
3026 Array *stationInfos = Controller::stationInfos(Tuner::ISDB_T);
\r
3027 if (stationInfos != NULL)
\r
3029 stationInfos->addObjectsFromArray(Controller::stationInfos(Tuner::ISDB_S));
\r
3033 stationInfos = Controller::stationInfos(Tuner::ISDB_S);
\r
3035 for (uint i = 0; (stationInfos != NULL) && (i < stationInfos->count()); ++i)
\r
3037 Array *services = ((Dictionary *)stationInfos->objectAtIndex(i))->arrayForKey(KEY_SERVICES);
\r
3039 for (uint j = 0; (services != NULL) && (j < 1); ++j)
\r
3041 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
3044 if ((service->stringForKey(KEY_SERVICE_TYPE) != NULL) && service->stringForKey(KEY_SERVICE_TYPE)->isEqualToString("1"))
\r
3046 String *name = service->stringForKey(KEY_NAME);
\r
3047 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
3048 if ((name != NULL) && (sid != NULL))
\r
3050 if ((service_id != NULL) && (service_id->isEqualToString(sid)))
\r
3052 String *tmp = String::stringWithFormat("<option value=\"%s\" selected>%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
3053 controls += tmp->cString();
\r
3057 String *tmp = String::stringWithFormat("<option value=\"%s\">%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
3058 controls += tmp->cString();
\r
3065 controls += "</select>";
\r
3066 controls += "</span>";
\r
3067 controls += "</div>";
\r
3069 controls += "<div class=\"row\">";
\r
3070 controls += "<label>";
\r
3071 controls += LocalizedString(KEY_I18N_Start_Time, NULL)->cString();
\r
3072 controls += " : </label>";
\r
3073 controls += "<span>";
\r
3074 controls += "<select name=\"start_hour\" size=\"1\">";
\r
3075 controls += "<option value=\"-\">--</option>";
\r
3076 String *sh_str = kwd_inf->stringForKey(KEY_EPG_START);
\r
3077 for (int sh = 0; sh < 24; ++sh)
\r
3080 if ((sh_str != NULL) && (sh_str->length() == 5) && (sh_str->substringToIndex(2)->intValue() == sh))
\r
3082 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
3086 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
3088 controls += sh_buf;
\r
3090 controls += "</select>";
\r
3091 controls += "<select name=\"start_min\" size=\"1\">";
\r
3092 controls += "<option value=\"-\">--</option>";
\r
3093 for (int sm = 0; sm < 60; ++sm)
\r
3096 if ((sh_str != NULL) && (sh_str->length() == 5) && (sh_str->substringFromIndex(3)->intValue() == sm))
\r
3098 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
3102 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
3104 controls += sm_buf;
\r
3106 controls += "</select>";
\r
3107 controls += "</span>";
\r
3108 controls += "</div>";
\r
3110 controls += "</fieldset>";
\r
3112 controls += "<input type=\"submit\" class=\"whiteButton\" name=\"req_mod\" value=\"";
\r
3113 controls += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
3114 controls += "\">";
\r
3116 controls += "<input type=\"submit\" class=\"redButton\" name=\"req_del\" value=\"";
\r
3117 controls += LocalizedString(KEY_I18N_Delete, NULL)->cString();
\r
3118 // controls += "\">";
\r
3119 controls += "\" onclick='return confirm(\"To delete. Is it ok?\");'>";
\r
3121 controls += "</form>";
\r
3126 contents += "</ul>";
\r
3127 contents += controls;
\r
3129 controls = "<form id=\"dialogForm\" title=\"";
\r
3130 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3131 controls += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3132 controls += "\" class=\"dialog\" target=\"_self\" action=\"add_keywords.cgi\" method=\"GET\">";
\r
3133 controls += "<fieldset>";
\r
3134 controls += "<h1>";
\r
3135 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3136 controls += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3137 controls += "</h1>";
\r
3138 controls += "<a class=\"button leftButton\" type=\"cancel\">Cancel</a>";
\r
3139 controls += "<a class=\"button blueButton\" type=\"submit\">Submit</a>";
\r
3140 controls += "<label>Parm1:</label>";
\r
3141 controls += "<input type=\"text\" name=\"keywords\" value=\"";
\r
3142 // controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3143 controls += "\"/>";
\r
3144 controls += "</fieldset>";
\r
3145 controls += "<div class=\"spinner\"></div>";
\r
3146 controls += "</form>";
\r
3148 contents += controls;
\r
3153 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
3156 result = responseWithHTML(request, html);
\r
3168 HTTPResponse *Controller::responseForStatus(HTTPRequest *request, SOCKADDR_IN *client)
\r
3170 HTTPResponse *result = NULL;
\r
3171 if ((request != NULL) && (client != NULL))
\r
3173 String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");
\r
3174 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
3177 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Tuner_Status, NULL));
\r
3178 std::string contents;
\r
3179 std::string status;
\r
3180 contents += "<ul id=\"home\" title=\"";
\r
3181 contents += LocalizedString(KEY_I18N_Tuner_Status, NULL)->cString();
\r
3182 contents += "\" selected=\"true\">";
\r
3183 DebugLog2("_tunerCount = %d", _tunerCount);
\r
3184 for (int i = 0; i < _tunerCount; ++i)
\r
3187 sprintf_s(key, sizeof(key), "%03d", i);
\r
3189 if (isTunerInitialized(i))
\r
3191 contents += "<li>";
\r
3192 contents += "<a href=\"#tuner";
\r
3194 contents += "\">";
\r
3197 contents += _tuners[i]->name();
\r
3198 contents += "</a></li>";
\r
3201 status += "<div id=\"";
\r
3202 status += "tuner";
\r
3204 status += "\" title=\"";
\r
3205 status += _tuners[i]->name();
\r
3206 status += "\" class=\"panel\">";
\r
3208 status += "<h2>Status</h2>";
\r
3209 status += "<fieldset>";
\r
3212 status += "<div class=\"row\">";
\r
3213 status += "<label>Type</label>";
\r
3214 status += "<span>";
\r
3215 switch (_tuners[i]->type())
\r
3217 case Tuner::ISDB_S:
\r
3218 status += "ISDB-S";
\r
3220 case Tuner::ISDB_T:
\r
3221 status += "ISDB-T";
\r
3223 case Tuner::TYPE_NA:
\r
3228 status += "</span>";
\r
3229 status += "</div>";
\r
3232 status += "<div class=\"row\">";
\r
3233 status += "<label>LnbPower</label>";
\r
3234 status += "<span>";
\r
3235 switch (_tuners[i]->lnbPower())
\r
3237 case Tuner::LNB_POWER_11V:
\r
3240 case Tuner::LNB_POWER_15V:
\r
3243 case Tuner::LNB_POWER_OFF:
\r
3248 status += "</span>";
\r
3249 status += "</div>";
\r
3253 status += "<div class=\"row\">";
\r
3254 status += "<label>Channel</label>";
\r
3255 status += "<span>";
\r
3256 sprintf_s(tmpstr, sizeof(tmpstr), "%03d", _tuners[i]->channel());
\r
3258 status += "</span>";
\r
3259 status += "</div>";
\r
3261 // C/N[dB] AGC xxx/255
\r
3262 uint32_t cn100 = 0;
\r
3264 uint32_t maxAgc = 0;
\r
3265 _tuners[i]->getCnAgc(&cn100, &agc, &maxAgc);
\r
3267 sprintf_s(tmpstr, sizeof(tmpstr), "%d.%02d[dB]", cn100 / 100, cn100 % 100);
\r
3269 status += "<div class=\"row\">";
\r
3270 status += "<label>C/N</label>";
\r
3271 status += "<span>";
\r
3273 status += "</span>";
\r
3274 status += "</div>";
\r
3276 sprintf_s(tmpstr, sizeof(tmpstr), "%03d/%03d", agc, maxAgc);
\r
3278 status += "<div class=\"row\">";
\r
3279 status += "<label>AGC</label>";
\r
3280 status += "<span>";
\r
3282 status += "</span>";
\r
3283 status += "</div>";
\r
3285 status += "</fieldset>";
\r
3286 status += "</div>";
\r
3291 contents += "<li>";
\r
3292 contents += _tuners[i]->name();
\r
3293 contents += "[uninitialized]";
\r
3294 contents += "</li>";
\r
3297 contents += "</ul>";
\r
3298 contents += status;
\r
3299 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
3300 result = responseWithHTML(request, html);
\r
3304 DebugLog2("responseForStatus() html is null\n");
\r
3310 HTTPResponse *Controller::responseForRegistCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3312 DebugLog2("Controller::responseForRegistCGI()");
\r
3314 HTTPResponse *result = NULL;
\r
3317 Dictionary *cgi = request->parseAsCGI();
\r
3321 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/regist.cgi")))
\r
3324 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3325 if (params != NULL)
\r
3328 if (params->count() == 2)
\r
3331 String *service_id = NULL;
\r
3332 String *event_id = NULL;
\r
3334 for (uint i = 0; i < params->count(); ++i)
\r
3336 Dictionary *param = (Dictionary *)params->objectAtIndex(i);
\r
3337 String *value = param->stringForKey("service_id");
\r
3338 if ((value != NULL) && value->isMatch("^\\d+$"))
\r
3340 service_id = value;
\r
3342 value = param->stringForKey("event_id");
\r
3343 if ((value != NULL) && value->isMatch("^\\d+$"))
\r
3350 if ((service_id != NULL) && (event_id != NULL))
\r
3352 DebugLog2("valid request");
\r
3354 result = responseByResultAndReferer(request, reserve(service_id->intValue(), event_id->intValue()), URI_PROGRAMS_HTML);
\r
3359 else if (params->count() == 9)
\r
3362 String *service_id = NULL;
\r
3363 String *year = NULL;
\r
3364 String *month = NULL;
\r
3365 String *day = NULL;
\r
3366 String *start_hour = NULL;
\r
3367 String *start_min = NULL;
\r
3368 String *end_hour = NULL;
\r
3369 String *end_min = NULL;
\r
3370 String *repeat = NULL;
\r
3374 String **variable;
\r
3375 const char *regex;
\r
3379 {"service_id", &service_id, "^\\d+$"},
\r
3380 {"year", &year, "^\\d{4}$"},
\r
3381 {"month", &month, "^([1-9]|1[0-2])$"},
\r
3382 {"day", &day, "^([1-9]|[12][0-9]|3[01])$"},
\r
3383 {"start_hour", &start_hour, "^\\d{2}$"},
\r
3384 {"start_min", &start_min, "^\\d{2}$"},
\r
3385 {"end_hour", &end_hour, "^\\d{2}$"},
\r
3386 {"end_min", &end_min, "^\\d{2}$"},
\r
3387 {"repeat", &repeat, "^(off|everyday|weekly|weekday)$"},
\r
3388 {NULL, NULL, NULL}
\r
3391 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
3393 for (uint j = 0; j < params->count(); ++j)
\r
3395 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
3396 String *value = param->stringForKey(cgi[i].name);
\r
3397 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
3399 *(cgi[i].variable) = value;
\r
3406 if ((service_id != NULL) && (year != NULL) && (month != NULL) && (day != NULL) &&
\r
3407 (start_hour != NULL) && (start_min != NULL) && (end_hour != NULL) && (end_min != NULL) && (repeat != NULL))
\r
3410 DebugLog1("valid param");
\r
3412 Dictionary *epg = Dictionary::dictionaryWithCapacity(0);
\r
3415 epg->setString(String::stringWithFormat("%s/%02d/%02d", year->cString(), month->intValue(), day->intValue()), KEY_EPG_DATE);
\r
3418 epg->setString(String::stringWithFormat("%s:%s:00", start_hour->cString(), start_min->cString()), KEY_EPG_START);
\r
3421 epg->setString(String::stringWithFormat("%s:%s:00", end_hour->cString(), end_min->cString()), KEY_EPG_END);
\r
3424 epg->setString(repeat, KEY_EPG_REPEAT);
\r
3427 epg->setString(service_id, KEY_EPG_SERVICE_ID);
\r
3430 epg->setString("ready", KEY_EPG_STATUS);
\r
3432 result = responseByResultAndReferer(request, reserve(epg), URI_RESERVATION_HTML);
\r
3442 HTTPResponse *Controller::responseForCancelCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3444 DebugLog2("Controller::responseForCancelCGI()");
\r
3446 HTTPResponse *result = NULL;
\r
3449 Dictionary *cgi = request->parseAsCGI();
\r
3453 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/cancel.cgi")))
\r
3456 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3457 if (params != NULL)
\r
3460 if (params->count() == 1)
\r
3462 Dictionary *param = (Dictionary *)params->objectAtIndex(0);
\r
3463 String *value = param->stringForKey("resv_id");
\r
3464 if ((value != NULL) && value->isMatch("^\\d{6}$"))
\r
3466 result = responseByResultAndReferer(request, cancel(-1, value->intValue()), URI_RESERVATION_HTML);
\r
3475 HTTPResponse *Controller::responseForAddKeywordsCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3477 DebugLog2("Controller::responseForAddKeywordsCGI()");
\r
3479 HTTPResponse *result = NULL;
\r
3482 Dictionary *cgi = request->parseAsCGI();
\r
3486 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/add_keywords.cgi")))
\r
3489 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3490 if (params != NULL)
\r
3493 if (params->count() == 1)
\r
3495 Dictionary *param = (Dictionary *)params->objectAtIndex(0);
\r
3496 String *value = param->stringForKey("keywords");
\r
3497 if (value != NULL)
\r
3499 value = value->stringByReplacingOccurrencesOfString("+", " ");
\r
3500 if (value != NULL)
\r
3502 value = value->stringByRemovingPercentEncoding();
\r
3505 if (value != NULL)
\r
3510 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3511 if (keywords_info == NULL)
\r
3513 keywords_info = Dictionary::dictionaryWithCapacity(0);
\r
3514 _reservations->setObject(keywords_info, KEY_EPG_KEYWORDS);
\r
3517 if (keywords_info->dictionaryForKey(value) == NULL)
\r
3520 keywords_info->setObject(Dictionary::dictionaryWithCapacity(0), value);
\r
3523 updateKeywordsReservation();
\r
3529 _reservations->writeToFile(_reservations_path, true);
\r
3534 result = responseForReloadURI(request, client, "/reservation.html#_keywords");
\r
3543 HTTPResponse *Controller::responseForModKeywordsCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3545 DebugLog2("Controller::responseForModKeywordsCGI()");
\r
3547 HTTPResponse *result = NULL;
\r
3550 Dictionary *cgi = request->parseAsCGI();
\r
3553 DebugLog3("cgi != NULL");
\r
3556 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/mod_keywords.cgi")))
\r
3558 DebugLog3("CGI path OK.");
\r
3561 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3562 if (params != NULL)
\r
3564 DebugLog3("params != NULL");
\r
3567 String *keywords = NULL;
\r
3568 String *service_id = NULL;
\r
3569 String *start_hour = NULL;
\r
3570 String *start_min = NULL;
\r
3571 String *req_mod = NULL;
\r
3572 String *req_del = NULL;
\r
3576 String **variable;
\r
3577 const char *regex;
\r
3581 {"keywords", &keywords, ".*"},
\r
3582 {"service_id", &service_id, "^(\\d+|-)$"},
\r
3583 {"start_hour", &start_hour, "^(\\d{2}|-)$"},
\r
3584 {"start_min", &start_min, "^(\\d{2}|-)$"},
\r
3585 {"req_mod", &req_mod, ".*"},
\r
3586 {"req_del", &req_del, ".*"},
\r
3587 {NULL, NULL, NULL}
\r
3590 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
3592 for (uint j = 0; j < params->count(); ++j)
\r
3594 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
3595 String *value = param->stringForKey(cgi[i].name);
\r
3596 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
3598 *(cgi[i].variable) = value;
\r
3604 if (keywords != NULL)
\r
3606 keywords = keywords->stringByReplacingOccurrencesOfString("+", " ");
\r
3607 if (keywords != NULL)
\r
3609 keywords = keywords->stringByRemovingPercentEncoding();
\r
3613 if ((keywords != NULL) && (service_id != NULL) && (start_hour != NULL) && (start_min != NULL) &&
\r
3614 ((req_mod != NULL) && (req_del == NULL)) || ((req_mod == NULL) && (req_del != NULL)))
\r
3620 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3621 if (keywords_info != NULL)
\r
3623 if (req_mod != NULL)
\r
3625 DebugLog0("keywords: %s", keywords->cString());
\r
3626 DebugLog0("service_id: %s", service_id->cString());
\r
3627 DebugLog0("start_hour: %s", start_hour->cString());
\r
3628 DebugLog0("start_min: %s", start_min->cString());
\r
3629 Dictionary *kwd_inf = keywords_info->dictionaryForKey(keywords);
\r
3630 if (kwd_inf != NULL)
\r
3632 if (!service_id->isEqualToString("-"))
\r
3634 kwd_inf->setString(service_id, KEY_EPG_SERVICE_ID);
\r
3638 kwd_inf->removeObjectForKey(KEY_EPG_SERVICE_ID);
\r
3640 if (!start_hour->isEqualToString("-") && !start_min->isEqualToString("-"))
\r
3642 kwd_inf->setString(String::stringWithFormat("%s:%s", start_hour->cString(), start_min->cString()), KEY_EPG_START);
\r
3646 kwd_inf->removeObjectForKey(KEY_EPG_START);
\r
3650 else if (req_del != NULL)
\r
3652 DebugLog0("keywords: %s", keywords->cString());
\r
3653 keywords_info->removeObjectForKey(keywords);
\r
3657 updateKeywordsReservation();
\r
3663 _reservations->writeToFile(_reservations_path, true);
\r
3669 result = responseForReloadURI(request, client, "/reservation.html#_keywords");
\r
3677 HTTPResponse *Controller::responseForReloadURI(NET::HTTPRequest *request, SOCKADDR_IN *client, const char *uri, int sec)
\r
3679 HTTPResponse *result = NULL;
\r
3683 std::string contents;
\r
3684 contents = "<html>";
\r
3685 contents += "<head>";
\r
3687 contents += "<meta http-equiv=\"refresh\" content=\"0;URL=";
\r
3689 contents += "<meta http-equiv=\"refresh\" content=\"";
\r
3691 contents += ";URL=";
\r
3694 contents += "\">";
\r
3695 contents += "</head>";
\r
3696 contents += "</html>";
\r
3697 String *html = String::stringWithUTF8String(contents.c_str());
\r
3700 result = responseWithHTML(request, html);
\r
3707 HTTPResponse *Controller::responseForPlaylist(HTTPRequest *request, SOCKADDR_IN *client)
\r
3709 HTTPResponse *result = NULL;
\r
3710 // http://bit.ly/iptv_feb2015
\r
3716 #EXTINF:-1, [COLOR yellow]Updated 15/04/2015 @ 03:45 [/COLOR]
\r
3717 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3718 #EXTINF:-1, [COLOR green] --Uk Live Tv--[/COLOR]
\r
3719 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3720 #EXTINF:-1, [COLOR green] --Free Collection of IPTV sports links--[/COLOR]
\r
3721 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3722 #EXTINF:-1, [COLOR red] --Links will go down. Please note that it will take time to update--[/COLOR]
\r
3723 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3724 #EXTINF:-1, [COLOR red] --Please contact me at the husham.com website--[/COLOR]
\r
3725 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3727 #EXTINF:-1, Sky sports news
\r
3728 rtmp://89.248.172.159:443/liverepeater playpath=35 swfUrl=http://popeoftheplayers.eu/atdedead.swf pageUrl=http://popeoftheplayers.eu/crichd.php?id=35&width=600&height=450 token=#atd%#$ZH
\r
3729 #EXTINF:-1,Bt sports 1
\r
3730 rtmp://80.82.78.87:443/liverepeater/starsp pageUrl=http://xxxxxxxxxxxxxxxx.xx/rtmpe://strm.dcast.tv:1935/live/asdfadfaa/pageUrl=http://xxxxx.xx/rtmp://80.82.64.90:443/liverepeater/79/pageUrl=http://filotv.pw/rtmpe://strm.ukcast.tv:1935/redirect/FUNKTSN/pageUrl=http://ukcast.tv/rtmp://173.192.81.176:443/liverepeater/stream1/token%ZZri(nKa@#Z/pageUrl=http://hdcast.org/cdn.kingofplayers.com/rtmpe://46.246.29.152:1935/redirect/HDMNBC playpath=41?18?49?33?48?38?11 pageUrl=http://popeoftheplayers.eu/hdcast.org/rtmp://31.220.0.134:1935/live/tsn2/pageUrl=http://www.eucast.tv/rtmp://195.154.236.152:80/liverepeater/141449/pageUrl=http://goodcast.pw/rtmp://77.81.98.134/tv/bt1h28qn?v=pageUrl=http://castok.com/rtmp://89.46.102.70:443/liveedge/bt1pageUrl=http://hqstreams.tv/rtmpe://play.finecast.tv/live/hqbt1page/playpath=42?finecast.tv/rtmpe://cdn.hdcast.org:1935/redirect/swfUrl=http://www.hdcast.org/aplayer/jwplayer.flash.swfpageUrl=http://www.hdcast.org/token=Fo5_n0w?U.rA6l3-70w47ch@#8x12pX@ token=#atd%#$ZH
\r
3735 std::string contents;
\r
3736 contents = "#EXTM3U\r\n";
\r
3737 contents += "\r\n";
\r
3739 Dictionary *tuner_channel_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
3740 if (tuner_channel_to_udp != NULL)
\r
3742 Tuner::Type types[] = {Tuner::ISDB_T, Tuner::ISDB_S};
\r
3743 for (int t = 0; t < sizeof(types) / sizeof(Tuner::Type); ++t)
\r
3745 for (int i = 0; i < _tunerCount; ++i)
\r
3747 if (isTunerInitialized(i) && (_tuners[i]->type() == types[t]))
\r
3749 uint ch_max = ((types[t] == Tuner::ISDB_T) ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S);
\r
3750 for (uint ch = 0; ch <= ch_max; ++ch)
\r
3752 if (isChannelEnabled(i, ch))
\r
3754 char tuner_and_channel[10];
\r
3755 sprintf_s(tuner_and_channel, "%d,%d", i, ch);
\r
3756 char *chstr = strchr(tuner_and_channel, ',');
\r
3757 if (chstr != NULL)
\r
3762 String *udp_str = tuner_channel_to_udp->stringForKey(tuner_and_channel);
\r
3763 if (udp_str != NULL)
\r
3765 contents += "#EXTINF:-1 tvg-id=\"";
\r
3766 contents += tuner_and_channel;
\r
3767 contents += "\" tvg-logo=\"";
\r
3768 contents += ((types[t] == Tuner::ISDB_T) ? "t_" : "s_");
\r
3769 if (chstr != NULL)
\r
3771 contents += chstr;
\r
3775 contents += "ffff";
\r
3777 contents += "\" group-title=\"";
\r
3778 contents += _tuners[i]->name();
\r
3779 contents += "\", ";
\r
3780 String *station_name = stationName(types[t], ch);
\r
3781 if (station_name != NULL)
\r
3783 contents += station_name->cString();
\r
3787 contents += tuner_and_channel;
\r
3789 contents += "\r\n";
\r
3790 contents += "udp://0.0.0.0:";
\r
3791 contents += udp_str->cString();
\r
3792 contents += "\r\n";
\r
3802 String *text = String::stringWithUTF8String(contents.c_str());
\r
3805 result = responseWithUTF8Text(request, text);
\r
3812 * @brief HTTP Live Streaming制御
\r
3814 * http://hogehoge/チューナ番号/チャンネル番号/streaming[-プリセット名].m3u8 がリクエスト(プリセットはオプション)され、
\r
3815 * チューナ番号/チャンネル番号/プリセット名(ある場合)が有効値の場合にコールされる
\r
3817 * @param [in] request HTTPリクエスト
\r
3818 * @param [in] client リクエストしたクライアントのアドレス
\r
3819 * @param [in] tuner チューナ番号
\r
3820 * @param [in] channel チャンネル番号
\r
3821 * @param [in] preset プリセット(URLで省略された場合 "default" )
\r
3823 HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner, int channel, String *preset)
\r
3825 DebugLog2("Controller::responseForHLSControl()");
\r
3827 HTTPResponse *result = NULL;
\r
3829 // client からホスト名を取得
\r
3830 char hostname[NI_MAXHOST];
\r
3831 if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
\r
3833 // ストリーミング制御情報からHLS情報を取得
\r
3834 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
3835 if (hls_info == NULL)
\r
3837 hls_info = Dictionary::dictionaryWithCapacity(0);
\r
3838 _streaming_ctrls->setObject(hls_info, KEY_HLS_INFO);
\r
3841 // HLS情報から指定チューナの情報を取得
\r
3842 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[tuner]->name());
\r
3843 if (hls_info_tuner == NULL)
\r
3845 hls_info_tuner = Dictionary::dictionaryWithCapacity(0);
\r
3846 hls_info->setObject(hls_info_tuner, _tuners[tuner]->name());
\r
3849 // 指定チューナの情報からホスト名を確認
\r
3850 if ((hls_info_tuner->stringForKey(KEY_HOSTNAME) == NULL) || hls_info_tuner->stringForKey(KEY_HOSTNAME)->isEqualToString(hostname))
\r
3853 hls_info_tuner->setString(hostname, KEY_HOSTNAME);
\r
3856 HTTPLiveStreaming *hls = (HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE);
\r
3860 hls = HTTPLiveStreaming::alloc()->init()->autorelease();
\r
3861 hls_info_tuner->setObject(hls, KEY_HLS_INSTANCE);
\r
3864 // 異チャンネルへのリクエスト、または、プリセット変更の場合
\r
3865 if (((hls_info_tuner->integerForKey(KEY_CHANNEL) != 0) && (hls_info_tuner->integerForKey(KEY_CHANNEL) != channel)) ||
\r
3866 ((hls_info_tuner->stringForKey(KEY_PRESET) != NULL) && !hls_info_tuner->stringForKey(KEY_PRESET)->isEqualToString(preset)))
\r
3871 // チャンネルとプリセットは一旦削除
\r
3872 hls_info_tuner->removeObjectForKey(KEY_CHANNEL);
\r
3873 hls_info_tuner->removeObjectForKey(KEY_PRESET);
\r
3876 // 初回リクエスト or チャンネル/プリセット変更 か?
\r
3877 if ((hls_info_tuner->integerForKey(KEY_CHANNEL) == 0) && (hls_info_tuner->stringForKey(KEY_PRESET) == NULL))
\r
3880 Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
3881 if (mapping != NULL)
\r
3883 Array *ports = mapping->allKeys();
\r
3884 if (ports != NULL)
\r
3886 char tuner_and_channel[10];
\r
3887 sprintf_s(tuner_and_channel, "%d,%d", tuner, channel);
\r
3889 for (uint i = 0; i < ports->count(); ++i)
\r
3891 String *port = (String *)ports->objectAtIndex(i);
\r
3892 String *tmp = mapping->stringForKey(port);
\r
3893 if (tmp->isEqualToString(tuner_and_channel))
\r
3895 DebugLog0("udp mapping %d -> %d,%d", port->intValue(), tuner, channel);
\r
3898 hls->setSource(String::stringWithFormat("udp://@0.0.0.0:%d", port->intValue()));
\r
3901 // hls->setTranscode(_props->dictionaryForKey(KEY_PRESETS)->dictionaryForKey(preset));
\r
3904 String *outpath = _props->stringForKey(KEY_CACHE_PATH)->stringByAppendingPathComponent(String::stringWithFormat("%03d", tuner));
\r
3905 _mkdir(outpath->cString());
\r
3906 hls->setOutputPath(outpath);
\r
3909 hls->setIndexName(String::stringWithFormat("live_%03d_%03d", tuner, channel));
\r
3914 DebugLog0("hls->start() success");
\r
3917 hls_info_tuner->setInteger(channel, KEY_CHANNEL);
\r
3920 hls_info_tuner->setString(preset, KEY_PRESET);
\r
3932 String *index_path = hls->indexPath();
\r
3933 FileManager *fm = FileManager::defaultManager();
\r
3935 while (count++ < 30)
\r
3937 bool isDirectory = false;
\r
3938 if (fm->fileExistsAtPath(index_path, &isDirectory))
\r
3942 DebugLog0("file exists");
\r
3943 bool done = false;
\r
3947 result = _httpd->responseWithPath(index_path, request);
\r
3949 if (result != NULL)
\r
3963 if (result == NULL)
\r
3965 DebugLog0("file no exists");
\r
3966 result = responseForReloadURI(request, client, request->URI()->cString(), 10);
\r
3970 hls_info_tuner->setInteger(0, KEY_COUNTER);
\r
3982 HTTPResponse *Controller::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner)
\r
3984 DebugLog2("%s\n", __FUNCTION__);
\r
3986 HTTPResponse *result = NULL;
\r
3992 String *uri = request->URI();
\r
3993 while (uri != NULL)
\r
3996 Dictionary *cgi = request->parseAsCGI();
\r
3999 uri = cgi->stringForKey(HTTPRequest::KEY_CGI);
\r
4009 if (uri->isMatch("^/[0-9]{3}/info.xml$") && (cgi == NULL))
\r
4015 // /ttt/channel=nnn
\r
4017 else if (uri->isMatch("^/[0-9]{3}/channel=[0-9]{1,3}$") && (cgi == NULL))
\r
4019 DebugLog0("ch set");
\r
4020 String *ch = uri->substringFromIndex(13);
\r
4025 int channel = ch->intValue();
\r
4026 DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
\r
4027 DebugLog2("set channel:%d(%s)\n", channel, ch->cString());
\r
4028 if (setChannel(tuner, channel))
\r
4031 DebugLog2("success.\n");
\r
4032 result = responseForSuccess(request);
\r
4037 DebugLog2("failed.\n");
\r
4038 result = responseForFailed(request);
\r
4043 // 録画開始(最大23:59まで)
\r
4044 // /ttt/recording=on?hour=hh&min=mm[&channel=nnn]
\r
4046 else if (uri->isMatch("^/[0-9]{3}/recording=on$") && (cgi != NULL))
\r
4049 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4050 if (params == NULL)
\r
4056 if ((params->count() != 2) && (params->count() != 3))
\r
4062 String *p_hour = NULL;
\r
4063 String *p_min = NULL;
\r
4064 String *p_channel = NULL;
\r
4068 String **variable;
\r
4069 const char *regex;
\r
4073 {"hour", &p_hour, "^[0-2][0-9]$"},
\r
4074 {"min", &p_min, "^[0-5][0-9]$"},
\r
4075 {"channel", &p_channel, "^[0-9]{3}$"},
\r
4076 {NULL, NULL, NULL}
\r
4079 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4081 *(cgi[i].variable) = NULL;
\r
4082 for (uint j = 0; j < params->count(); ++j)
\r
4084 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4085 String *value = param->stringForKey(cgi[i].name);
\r
4086 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4088 *(cgi[i].variable) = value;
\r
4094 if ((p_hour == NULL) || (p_min == NULL))
\r
4101 if (p_channel != NULL)
\r
4103 channel = p_channel->intValue();
\r
4107 channel = _tuners[tuner]->channel();
\r
4113 int hour = p_hour->intValue();
\r
4114 int min = p_min->intValue();
\r
4118 Dictionary *epg = Dictionary::dictionaryWithCapacity(0);
\r
4123 now += 1; // margin
\r
4125 if (localtime_s(&tm, &now) != 0)
\r
4132 end.tm_hour += hour;
\r
4133 end.tm_min += min;
\r
4134 end.tm_sec += 1; // margin
\r
4135 if (mktime(&end) == -1)
\r
4144 sprintf_s(tmp, sizeof(tmp), "%04d/%02d/%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
\r
4145 epg->setString(tmp, KEY_EPG_DATE);
\r
4148 sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
\r
4149 epg->setString(tmp, KEY_EPG_START);
\r
4152 sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", end.tm_hour, end.tm_min, end.tm_sec);
\r
4153 epg->setString(tmp, KEY_EPG_END);
\r
4156 sprintf_s(tmp, sizeof(tmp), "%d", channel);
\r
4157 epg->setString(tmp, KEY_EPG_CHANNEL);
\r
4160 epg->setString("off", KEY_EPG_REPEAT);
\r
4163 epg->setString("ready", KEY_EPG_STATUS);
\r
4171 result = responseByResultAndReferer(request, reserve(tuner, epg), URI_RESERVATION_HTML);
\r
4179 // /ttt/recording=off
\r
4181 else if (uri->isMatch("^/[0-9]{3}/recording=off$") && (cgi == NULL))
\r
4184 DebugLog2("recording off: %s\n", uri->cString());
\r
4185 if (cancel(tuner, -1))
\r
4188 DebugLog2("success.\n");
\r
4189 result = responseForSuccess(request);
\r
4194 DebugLog2("failed.\n");
\r
4195 result = responseForFailed(request);
\r
4201 // /ttt/streaming=on?udp=nnnnn(&host=aaaaaa)
\r
4203 else if (uri->isMatch("^/[0-9]{3}/streaming=on$") && (cgi != NULL))
\r
4206 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4207 if (params == NULL)
\r
4213 if ((params->count() != 1) && (params->count() != 2))
\r
4219 String *p_udp = NULL;
\r
4220 String *p_host = NULL;
\r
4224 String **variable;
\r
4225 const char *regex;
\r
4229 {"udp", &p_udp, "^[0-9]{1,5}$"},
\r
4230 {"host", &p_host, "^.+$"},
\r
4231 {NULL, NULL, NULL}
\r
4234 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4236 *(cgi[i].variable) = NULL;
\r
4237 for (uint j = 0; j < params->count(); ++j)
\r
4239 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4240 String *value = param->stringForKey(cgi[i].name);
\r
4241 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4243 *(cgi[i].variable) = value;
\r
4249 if (p_udp == NULL)
\r
4254 SOCKADDR_IN dst_addr;
\r
4256 if (p_host != NULL)
\r
4259 std::string host = udpstr.substr(idx + 5);
\r
4260 udpstr = udpstr.substr(0, idx - 1);
\r
4261 DebugLog2("udp: %s\n", udpstr.c_str());
\r
4262 DebugLog2("host: %s\n", host.c_str());
\r
4263 struct hostent *ent = gethostbyname(host.c_str());
\r
4268 memcpy(&dst_addr, client, sizeof(SOCKADDR_IN));
\r
4270 dst_addr.sin_port = htons(p_udp->intValue());
\r
4272 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
4275 DebugLog2("success.\n");
\r
4276 result = responseForSuccess(request);
\r
4281 DebugLog2("failed.\n");
\r
4282 result = responseForFailed(request);
\r
4288 // /ttt/streaming=off(?host=aaaa)
\r
4290 else if (uri->isMatch("^/[0-9]{3}/streaming=off$"))
\r
4293 String *p_host = NULL;
\r
4298 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4299 if (params == NULL)
\r
4305 if ((params->count() != 0) && (params->count() != 1))
\r
4312 String **variable;
\r
4313 const char *regex;
\r
4317 {"host", &p_host, "^.+$"},
\r
4318 {NULL, NULL, NULL}
\r
4321 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4323 *(cgi[i].variable) = NULL;
\r
4324 for (uint j = 0; j < params->count(); ++j)
\r
4326 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4327 String *value = param->stringForKey(cgi[i].name);
\r
4328 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4330 *(cgi[i].variable) = value;
\r
4336 SOCKADDR_IN dst_addr;
\r
4337 if (p_host != NULL)
\r
4344 _tuners[tuner]->stopStreaming();
\r
4347 DebugLog2("success.\n");
\r
4348 result = responseForSuccess(request);
\r
4354 else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming(-[^\\.]+)?.m3u8$") && (cgi == NULL))
\r
4356 // URIからチャンネル番号を抽出
\r
4358 int ch = uri->substringFromIndex(5)->substringToIndex(3)->intValue();
\r
4360 // presetが指定されている場合、presetを抽出
\r
4361 String *preset = NULL;
\r
4362 if (uri->isMatch("streaming-"))
\r
4364 preset = uri->substringFromIndex(19);
\r
4365 preset = preset->substringToIndex(preset->length() - 5);
\r
4370 preset = String::stringWithUTF8String(KEY_DEFAULT);
\r
4373 // チャンネル/presetが有効か確認
\r
4374 if (isChannelEnabled(tuner, ch) &&
\r
4375 (_props->dictionaryForKey(KEY_PRESETS) != NULL) &&
\r
4376 (_props->dictionaryForKey(KEY_PRESETS)->objectForKey(preset) != NULL))
\r
4379 result = responseForHLSControl(request, client, tuner, ch, preset);
\r
4383 result = responseForFailed(request);
\r
4386 else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming-[0-9]+.ts$") && (cgi == NULL))
\r
4388 // URIからチャンネル番号を抽出
\r
4390 int ch = uri->substringFromIndex(5)->substringToIndex(3)->intValue();
\r
4392 // client からホスト名を取得
\r
4393 char hostname[NI_MAXHOST];
\r
4394 if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
\r
4396 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
4397 if (hls_info != NULL)
\r
4399 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[tuner]->name());
\r
4400 if (hls_info_tuner != NULL)
\r
4402 if (hls_info_tuner->stringForKey(KEY_HOSTNAME)->isEqualToString(hostname) &&
\r
4403 (hls_info_tuner->integerForKey(KEY_CHANNEL) == ch))
\r
4405 String *path = ((HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE))->outputPath();
\r
4408 result = _httpd->responseWithPath(path->stringByAppendingPathComponent(uri->substringFromIndex(9)), request);
\r
4425 HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)
\r
4427 DebugLog2("%s\n", __FUNCTION__);
\r
4430 bool flag = false;
\r
4432 flag = _initialized;
\r
4439 HTTPResponse *response = NULL;
\r
4441 if (request->method()->isEqualToString("GET") ||
\r
4442 request->method()->isEqualToString("HEAD"))
\r
4445 String *uri = request->URI();
\r
4446 DebugLog0("request: %s\n", uri->cString());
\r
4451 if (uri->isMatch("^(/|/index\\.(htm|html))$"))
\r
4453 response = responseForMain(request, client);
\r
4456 else if (uri->isMatch("^/status.html$"))
\r
4458 response = responseForStatus(request, client);
\r
4462 else if (uri->isMatch("^/info.xml$"))
\r
4465 else if (uri->isMatch("^/video.xml$"))
\r
4470 else if (uri->isMatch("^/suspend.xml$"))
\r
4474 // response = responseForSuccess(request);
\r
4475 // delaySuspend();
\r
4479 // response = responseForFailed(request);
\r
4484 else if (uri->isMatch("^/exec_vlc.html$"))
\r
4486 // _vlc->execute();
\r
4487 // return responseForRefreshMain(request, client);
\r
4493 else if (uri->isMatch("^/[0-9]{3}/"))
\r
4495 // String::substringWithRange() を実装するのを後回しにするので。。
\r
4496 std::string s = uri->cString();
\r
4497 int tuner = atoi(s.substr(1, 3).c_str());
\r
4498 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4500 response = requestTunerControl(request, client, tuner);
\r
4505 // reservation control
\r
4507 else if (uri->isMatch("^/reservation.html$"))
\r
4509 response = responseForReservation(request, client);
\r
4511 else if (uri->isMatch("^/regist.cgi"))
\r
4513 response = responseForRegistCGI(request, client);
\r
4515 else if (uri->isMatch("^/cancel.cgi"))
\r
4517 response = responseForCancelCGI(request, client);
\r
4519 else if (uri->isMatch("^/add_keywords.cgi"))
\r
4521 response = responseForAddKeywordsCGI(request, client);
\r
4523 else if (uri->isMatch("^/mod_keywords.cgi"))
\r
4525 response = responseForModKeywordsCGI(request, client);
\r
4527 else if (uri->isMatch("^/reservation.xml$"))
\r
4530 else if (uri->isMatch("^/[0-9]{6}/"))
\r
4532 // DebugLog2("reservation: %s\n", uri.c_str());
\r
4538 else if (uri->isMatch("^/[0-9]{9}/"))
\r
4540 // DebugLog2("video: %s\n", uri.c_str());
\r
4546 // else if (match(uri.c_str(), "^/programs.html$"))
\r
4547 else if (uri->isMatch("^/" URI_PROGRAMS_HTML "$"))
\r
4549 response = responseForPrograms(request, client);
\r
4551 else if (uri->isMatch("^/programs.xml$"))
\r
4554 // return responseWithDictionary(request, _programs);
\r
4559 else if (uri->isMatch("^/tv.html$"))
\r
4561 // return responseForTV(request, client);
\r
4565 else if (uri->isMatch("^/iptv.m3u8$"))
\r
4567 return responseForPlaylist(request, client);
\r
4571 else if (uri->isMatch("^/iptd.log$"))
\r
4573 String *path = _system_path->stringByAppendingPathComponent("log");
\r
4576 path = path->stringByAppendingPathComponent("iptd.log");
\r
4579 response = _httpd->responseWithPath(path, request);
\r
4580 if (response != NULL)
\r
4582 if (response->message() != NULL)
\r
4584 if (response->message()->header() != NULL)
\r
4586 response->message()->header()->setFieldBodyWithName("text/plane; charset=UTF-8", "Content-Type");
\r
4594 else if (request->method()->isEqualToString("POST"))
\r
4597 String *uri = request->URI();
\r
4598 DebugLog1("POST: %s\n", uri->cString());
\r
4599 InternetTextMessage *message = request->message();
\r
4600 if (message != NULL)
\r
4602 DebugLog3("message: ");
\r
4603 InternetTextMessageHeader *header = message->header();
\r
4604 if (header != NULL)
\r
4606 DebugLog3("header: ");
\r
4608 InternetTextMessageBody *body = message->body();
\r
4611 DebugLog3("body: ");
\r
4621 #pragma mark ------- プロパティ取得 -------
\r
4624 bool Controller::isTunerInitialized(int tuner)
\r
4626 DebugLog2("Controller::isTunerInitialized()");
\r
4628 bool result = false;
\r
4630 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4635 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4636 if (tunersInfo != NULL)
\r
4638 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
4639 if (tunerInfo != NULL)
\r
4641 result = tunerInfo->boolForKey(KEY_INITIALIZED);
\r
4652 bool Controller::isTunerEnabled(int tuner)
\r
4654 DebugLog2("Controller::isTunerEnabled()");
\r
4656 bool result = false;
\r
4658 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4663 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4664 if (tunersInfo != NULL)
\r
4666 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
4667 if (tunerInfo != NULL)
\r
4669 result = tunerInfo->boolForKey(KEY_ENABLED);
\r
4680 bool Controller::isChannelEnabled(int tuner, int channel)
\r
4682 DebugLog2("Controller::isChannelEnabled()");
\r
4684 bool result = false;
\r
4686 if ((0 <= tuner) && (tuner < _tunerCount) && (0 <= channel) && (channel <= Tuner::MAX_CHANNELS_ISDB_T))
\r
4691 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4692 if (tunersInfo != NULL)
\r
4694 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
4695 if (tunerInfo != NULL)
\r
4697 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4698 if (channels != NULL)
\r
4701 sprintf_s(key, "%03d", channel);
\r
4702 Dictionary *chInfo = channels->dictionaryForKey(key);
\r
4703 if (chInfo != NULL)
\r
4705 result = chInfo->boolForKey(KEY_ENABLED);
\r
4718 Array *Controller::stationInfos(Tuner::Type type)
\r
4720 DebugLog2("Controller::stationInfosForISDB_T()");
\r
4722 Array *result = Array::arrayWithCapacity(0);
\r
4727 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4728 if (tunersInfo != NULL)
\r
4730 for (int i = 0; i < _tunerCount; ++i)
\r
4732 if (_tuners[i]->type() == type)
\r
4734 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[i]->name());
\r
4735 if (tunerInfo != NULL)
\r
4737 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4738 if (channels != NULL)
\r
4740 for (uint ch = 0; ch <= (type == Tuner::ISDB_T ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S); ++ch)
\r
4743 sprintf_s(chkey, "%03d", ch);
\r
4744 Dictionary *channel = channels->dictionaryForKey(chkey);
\r
4745 if ((channel != NULL) && channel->boolForKey(KEY_ENABLED))
\r
4747 result->addObject(channel);
\r
4763 String *Controller::stationName(Tuner::Type type, int channel)
\r
4765 DebugLog2("Controller::stationName()");
\r
4767 String *result = NULL;
\r
4772 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4773 if (tunersInfo != NULL)
\r
4775 for (int i = 0; i < _tunerCount; ++i)
\r
4777 if (_tuners[i]->type() == type)
\r
4779 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[i]->name());
\r
4780 if (tunerInfo != NULL)
\r
4782 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4783 if (channels != NULL)
\r
4786 sprintf_s(chkey, "%03d", channel);
\r
4787 Dictionary *channel = channels->dictionaryForKey(chkey);
\r
4788 if ((channel != NULL) && channel->boolForKey(KEY_ENABLED))
\r
4790 result = channel->stringForKey(KEY_NAME);
\r
4805 // epgの開始時刻でソートする為の比較関数
\r
4806 Integer compareFunction(Object *obj1, Object *obj2, void *context)
\r
4808 if (isKindOfClass(Dictionary, obj1) && isKindOfClass(Dictionary, obj2))
\r
4812 Controller::getTimeWithEPG((Dictionary *)obj1, &st1, &ed1);
\r
4816 Controller::getTimeWithEPG((Dictionary *)obj2, &st2, &ed2);
\r
4820 return OrderedAscending;
\r
4822 else if (st1 > st2)
\r
4824 return OrderedDescending;
\r
4830 return OrderedAscending;
\r
4832 else if (ed1 > ed2)
\r
4834 return OrderedDescending;
\r
4838 return OrderedSame;
\r
4841 Array *Controller::programsForServices(Array *services)
\r
4843 DebugLog2("Controller::programsForServices()");
\r
4845 Array *result = Array::arrayWithCapacity(0);
\r
4850 for (uint i = 0; i < services->count(); ++i)
\r
4852 Dictionary *service = (Dictionary *)services->objectAtIndex(i);
\r
4853 Dictionary *events = _epgs->dictionaryForKey(service->stringForKey(KEY_SERVICE_ID));
\r
4854 if (events != NULL)
\r
4856 Array *keys = events->allKeys();
\r
4857 for (uint j = 0; j < keys->count(); ++j)
\r
4859 result->addObject(events->objectForKey((String *)keys->objectAtIndex(j)));
\r
4865 result = result->sortedArrayUsingFunction(compareFunction, this);
\r
4874 String *Controller::stationNameForServiceID(String *service_id)
\r
4876 DebugLog2("Controller::stationNameForServiceID()");
\r
4878 String *result = NULL;
\r
4880 if (service_id != NULL)
\r
4885 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4886 if (tunersInfo != NULL)
\r
4888 Array *tuners_key = tunersInfo->allKeys();
\r
4890 for (uint i = 0; (result == NULL) && (i < tuners_key->count()); ++i)
\r
4892 Dictionary *tunerInfo = tunersInfo->dictionaryForKey((String *)tuners_key->objectAtIndex(i));
\r
4893 if (tunerInfo != NULL)
\r
4895 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4896 if (channels != NULL)
\r
4898 Array *chkey = channels->allKeys();
\r
4899 for (uint ch = 0; (result == NULL) && (ch < chkey->count()); ++ch)
\r
4901 Dictionary *channel = channels->dictionaryForKey((String *)chkey->objectAtIndex(ch));
\r
4902 if (channel != NULL)
\r
4904 Array *services = channel->arrayForKey(KEY_SERVICES);
\r
4905 if (services != NULL)
\r
4907 for (uint j = 0; j < services->count(); ++j)
\r
4909 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
4910 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
4913 if (sid->isEqualToString(service_id))
\r
4915 result = service->stringForKey(KEY_NAME);
\r
4937 #pragma mark ------- タイマディスパッチャ -------
\r
4940 void Controller::timerExpired(Timer *timer, void *userInfo)
\r
4942 DebugLog2("Controller::timerExpired()");
\r
4946 switch ((long long)userInfo)
\r
4949 if (restart() > 0)
\r
4952 DebugLog2("tuner initialize success.");
\r
4954 // EPG収集用タイマ起動(ISDB-S)
\r
4955 _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);
\r
4956 if (_timer_epg_s != NULL)
\r
4958 _timer_epg_s->fire();
\r
4961 // EPG収集用タイマ起動(ISDB-T)
\r
4962 _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);
\r
4963 if (_timer_epg_t != NULL)
\r
4965 _timer_epg_t->fire();
\r
4971 DebugLog0("tuner initialize failed.");
\r
4982 case CMD_PERIODIC: // 周期処理
\r
4986 case CMD_PERIODIC_2: // 周期処理2
\r
4990 case CMD_COLLECT_EPG_ISDB_S: // EPG収集(ISDB-S)
\r
4992 if (collectEPGs(Tuner::ISDB_S))
\r
4995 _timer_epg_s->setRepeats(false);
\r
5000 _timer_epg_s->setTimeInterval(DEF_COLLECT_EPG_RETRY);
\r
5004 case CMD_COLLECT_EPG_ISDB_T: // 番組情報収集(ISDB-T)
\r
5005 if (collectEPGs(Tuner::ISDB_T))
\r
5008 _timer_epg_t->setRepeats(false);
\r
5013 _timer_epg_t->setTimeInterval(DEF_COLLECT_EPG_RETRY);
\r
5021 #pragma mark ------- 起動/停止関連 -------
\r
5024 // システム状態をチェックしてサスペンド可能かを返す
\r
5025 bool Controller::canSuspend()
\r
5027 return isIdleState(true);
\r
5030 bool Controller::canTerminate()
\r
5032 return isIdleState(false);
\r
5035 bool Controller::isIdleState(bool suspend)
\r
5037 DebugLog2("Controller::isIdleState() start.");
\r
5039 bool result = false;
\r
5045 while (_initialized)
\r
5047 // EPG(ISDB-S)収集中か
\r
5048 if (suspend && (_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
5054 // EPG(ISDB-T)収集中か
\r
5055 if (suspend && (_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5065 // 10分後以内に開始の予約があったらサスペンド不可
\r
5068 time_t now = time(NULL);
\r
5070 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
5072 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
5073 if ((array == NULL) || (array->count() == 0))
\r
5080 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
5083 getTimeWithEPG(epg, &start, &end);
\r
5085 if (start + OFFSET_OF_SUPPRESSION_TIME <= now)
\r
5099 DebugLog2("Controller::isIdleState() end.");
\r
5105 * TrayApp::WndProc() からコールされる
\r
5107 * スレッドコンテキスト:メインスレッド
\r
5109 void Controller::systemWillSuspend()
\r
5111 DebugLog2("Controller::systemWillSuspend() start");
\r
5114 _cancel_epg_collect = true;
\r
5118 if ((_timer_restart != NULL) && _timer_restart->valid())
\r
5120 _timer_restart->invalidate();
\r
5122 if ((_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
5124 _timer_epg_s->invalidate();
\r
5126 if ((_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5128 _timer_epg_t->invalidate();
\r
5130 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
5132 _timer_periodic->invalidate();
\r
5134 if ((_timer_periodic_2 != NULL) && _timer_periodic_2->valid())
\r
5136 _timer_periodic_2->invalidate();
\r
5143 RELEASE(_timer_restart);
\r
5144 RELEASE(_timer_epg_s);
\r
5145 RELEASE(_timer_epg_t);
\r
5146 RELEASE(_timer_periodic);
\r
5147 RELEASE(_timer_periodic_2);
\r
5153 _initialized = false;
\r
5156 for (int i = 0; i < _tunerCount; ++i)
\r
5158 if (_tuners[i] != NULL)
\r
5160 delete _tuners[i];
\r
5161 _tuners[i] = NULL;
\r
5165 _cancel_epg_collect = false;
\r
5167 DebugLog0("system will suspend...");
\r
5172 #ifdef OBJC_MEMORY_CHECK
\r
5173 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
5176 DebugLog2("Controller::systemWillSuspend() end");
\r
5180 * TrayApp::WndProc() からコールされる
\r
5182 * スレッドコンテキスト:メインスレッド
\r
5184 void Controller::systemResumed()
\r
5186 DebugLog2("Controller::systemResumed() start");
\r
5188 DebugLog0("system resumed.");
\r
5190 if (_timer_restart == NULL)
\r
5193 _timer_restart = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_RESTART, false);
\r
5194 _timer_restart->fire();
\r
5197 DebugLog2("Controller::systemResumed()");
\r
5201 * TrayApp::WndProc() からコールされる
\r
5203 * スレッドコンテキスト:メインスレッド
\r
5205 void Controller::detectIdle()
\r
5207 DebugLog2("Controller::detectIdle()");
\r
5209 // ここはメインスレッドなのでARPを用意する
\r
5210 AutoreleasePool *pool = AutoreleasePool::alloc()->init();
\r
5218 if (_idle_count == 0)
\r
5220 DebugLog0("detect idle...");
\r
5226 // 起動中アプリと休止状態抑止アプリのチェック
\r
5227 bool found = false;
\r
5229 Array *dont_in_suspend = _props->arrayForKey(KEY_DO_NOT_IN_SUSPEND);
\r
5230 Array *running_apps = Workspace::sharedWorkspace()->runningApplications();
\r
5231 for (uint i = 0; (i < running_apps->count()) && !found; ++i)
\r
5233 RunningApplication *ra = (RunningApplication *)running_apps->objectAtIndex(i);
\r
5236 if (!ra->isRunning())
\r
5242 String *path = ra->executePath();
\r
5243 if ((path == NULL) || (path->length() == 0))
\r
5247 DebugLog3("exec path: %s", path->cString());
\r
5249 // 休止状態抑止アプリリストのチェック
\r
5250 for (uint j = 0; (j < dont_in_suspend->count()) && !found; ++j)
\r
5252 found = path->isMatch((String *)dont_in_suspend->objectAtIndex(j));
\r
5256 // 抑止有効なら KEY_FORCED_SUSPEND_TIME、無効なら KEY_SUSPEND_TIME で取得
\r
5257 int limit = _props->integerForKey(found ? KEY_FORCED_SUSPEND_TIME : KEY_SUSPEND_TIME);
\r
5258 DebugLog3("found: %d, _idle_count: %d, limit: %d", found, _idle_count, limit);
\r
5259 if (_idle_count >= limit)
\r
5264 // サスペンド前にARPを解放しておく
\r
5267 // 下記の TrayApp::suspend() を使用する場合、自アプリへsuspendメッセージが
\r
5268 // ブロードキャストされないため、自分でコールしておく
\r
5269 systemWillSuspend();
\r
5275 pool = AutoreleasePool::alloc()->init();
\r
5297 void Controller::detectNonIdle()
\r
5299 DebugLog2("Controller::detectNonIdle()");
\r
5304 if (_idle_count > 0)
\r
5306 DebugLog0("detect non idle...");
\r
5314 int Controller::restart()
\r
5320 _initialized = false;
\r
5323 for (int i = 0; i < _tunerCount; ++i)
\r
5325 if (_tuners[i] != NULL)
\r
5327 delete _tuners[i];
\r
5328 _tuners[i] = NULL;
\r
5336 _tunerCount = ry0::device::TunerFactory::scan(_tuners, _multi2_dll);
\r
5342 for (int i = 0; i < _tunerCount; ++i)
\r
5345 if (!isTunerInitialized(i))
\r
5351 if (isTunerEnabled(i))
\r
5354 setChannel(i, getChannel(i));
\r
5359 DebugLog0(" UDP Port Mapping :");
\r
5360 DebugLog0(" tuner, ch -> port");
\r
5361 int udpport = _props->integerForKey(KEY_BEGIN_UDP_PORT);
\r
5362 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
5364 uint max_channel = (_tuners[tuner]->type() == Tuner::ISDB_S ? Tuner::MAX_CHANNELS_ISDB_S : Tuner::MAX_CHANNELS_ISDB_T);
\r
5365 for (uint ch = 0; ch <= max_channel; ++ch)
\r
5367 if (isChannelEnabled(tuner, ch))
\r
5369 DebugLog0(" %5d,%3d -> %5d", tuner, ch, udpport);
\r
5371 Dictionary *udp_to_tuner_channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
5372 if (udp_to_tuner_channel == NULL)
\r
5374 udp_to_tuner_channel = Dictionary::dictionaryWithCapacity(0);
\r
5375 _streaming_ctrls->setObject(udp_to_tuner_channel, KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
5378 Dictionary *tuner_channel_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
5379 if (tuner_channel_to_udp == NULL)
\r
5381 tuner_channel_to_udp = Dictionary::dictionaryWithCapacity(0);
\r
5382 _streaming_ctrls->setObject(tuner_channel_to_udp, KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
5385 char port_str[10];
\r
5386 sprintf_s(port_str, "%d", udpport);
\r
5387 char tuner_and_channel[10];
\r
5388 sprintf_s(tuner_and_channel, "%d,%d", tuner, ch);
\r
5390 udp_to_tuner_channel->setString(tuner_and_channel, port_str);
\r
5391 tuner_channel_to_udp->setString(port_str, tuner_and_channel);
\r
5399 _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC, true);
\r
5400 _timer_periodic->fire();
\r
5403 _timer_periodic_2 = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC_2, true);
\r
5404 _timer_periodic_2->fire();
\r
5410 _initialized = true;
\r
5415 return (_tunerCount > 0);
\r
5418 int Controller::start()
\r
5422 Raym::LOG_NUM_MAX = 8;
\r
5424 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
\r
5425 if (hProcess != NULL)
\r
5427 if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == FALSE)
\r
5429 DebugLog0("SetPriorityClass failed.");
\r
5431 CloseHandle(hProcess);
\r
5434 #ifdef RAYM_MEMORY_CHECK
\r
5436 DebugLog0("global_raym_count_ = %d", Raym::global_raym_count_);
\r
5440 AutoreleasePool *pool = AutoreleasePool::alloc()->init();
\r
5443 _system_path = NULL;
\r
5444 _props_path = NULL;
\r
5446 _status_path = NULL;
\r
5448 _epgs_path = NULL;
\r
5450 _store_path = NULL;
\r
5451 _reservations = NULL;
\r
5452 _reservations_path = NULL;
\r
5453 _timer_restart = NULL;
\r
5454 _timer_periodic = NULL;
\r
5455 _timer_periodic_2 = NULL;
\r
5456 _timer_epg_s = NULL;
\r
5457 _timer_epg_t = NULL;
\r
5458 _multi2_dll = NULL;
\r
5459 _streaming_ctrls = NULL;
\r
5462 _initialized = false;
\r
5463 _reservation_seq_id = 0;
\r
5464 _cancel_epg_collect = false;
\r
5467 for (int i = 0; i < ry0::device::MAX_TUNERS; ++i)
\r
5469 _tuners[i] = NULL;
\r
5473 DebugLog0("------------------------------------------------------------------------");
\r
5474 DebugLog0("iPTd ver %s (rev.%d)", VERSION, REVISION);
\r
5475 DebugLog0("initialize...");
\r
5482 bool updated = false;
\r
5485 _system_path = String::stringWithFormat("%s", GetExecutePath());
\r
5486 if (_system_path == NULL)
\r
5488 DebugLog0("error: GetExecutePath()");
\r
5492 _system_path = _system_path->stringByReplacingOccurrencesOfString("iPTd.exe", "");
\r
5493 _system_path->retain();
\r
5494 DebugLog2("_system_path: %s", _system_path->cString());
\r
5497 _props_path = String::alloc()->initWithFormat("%s%s.iptd.plist", _system_path->cString(), PLIST_PREFIX);
\r
5498 if (_props_path == NULL)
\r
5500 DebugLog0("error: set property file path.");
\r
5506 _props = Dictionary::alloc()->initWithContentsOfFile(_props_path);
\r
5507 if (_props == NULL)
\r
5509 DebugLog1("property file: %s (created)", _props_path->cString());
\r
5510 _props = Dictionary::alloc()->initWithCapacity(0);
\r
5514 DebugLog1("property file: %s", _props_path->cString());
\r
5518 _status_path = String::alloc()->initWithFormat("%s%s.iptd.status.plist", _system_path->cString(), PLIST_PREFIX);
\r
5519 if (_status_path == NULL)
\r
5521 DebugLog0("error: set status file path.");
\r
5527 _status = Dictionary::alloc()->initWithContentsOfFile(_status_path);
\r
5528 if (_status == NULL)
\r
5530 DebugLog1("status file: %s (created)", _status_path->cString());
\r
5531 _status = Dictionary::alloc()->initWithCapacity(0);
\r
5535 DebugLog1("status file: %s", _status_path->cString());
\r
5539 if (_props->stringForKey(KEY_NAME) == NULL)
\r
5541 _props->setString(DEF_NAME, KEY_NAME);
\r
5546 if (_props->stringForKey(KEY_HOSTNAME) == NULL)
\r
5548 _props->setString(DEF_HOSTNAME, KEY_HOSTNAME);
\r
5552 // multi2デコード可否判定: multi2.dll が使えるか確認する
\r
5553 _multi2_dll = ::LoadLibrary(L"multi2.dll");
\r
5554 while (_multi2_dll != NULL)
\r
5557 ARIB_STD_B25 *(*func_b25)();
\r
5558 func_b25 = reinterpret_cast<ARIB_STD_B25 *(*)()>(::GetProcAddress(_multi2_dll, "create_arib_std_b25"));
\r
5559 if (func_b25 == NULL)
\r
5562 FreeLibrary(_multi2_dll);
\r
5563 _multi2_dll = NULL;
\r
5568 ARIB_STD_B25 * _b25;
\r
5569 _b25 = func_b25();
\r
5573 FreeLibrary(_multi2_dll);
\r
5574 _multi2_dll = NULL;
\r
5577 _b25->release(_b25);
\r
5580 B_CAS_CARD *(*func_bcas)();
\r
5581 func_bcas = reinterpret_cast<B_CAS_CARD *(*)()>(::GetProcAddress(_multi2_dll, "create_b_cas_card"));
\r
5582 if (func_bcas == NULL)
\r
5585 FreeLibrary(_multi2_dll);
\r
5586 _multi2_dll = NULL;
\r
5591 B_CAS_CARD * _bcas;
\r
5592 _bcas = func_bcas();
\r
5593 if (_bcas == NULL)
\r
5596 FreeLibrary(_multi2_dll);
\r
5597 _multi2_dll = NULL;
\r
5600 if (_bcas->init(_bcas) != 0)
\r
5603 FreeLibrary(_multi2_dll);
\r
5604 _multi2_dll = NULL;
\r
5607 _bcas->release(_bcas);
\r
5614 if (_props->integerForKey(KEY_HTTP_PORT) == 0)
\r
5616 _props->setInteger(DEF_HTTP_PORT, KEY_HTTP_PORT);
\r
5621 if ((_props->integerForKey(KEY_SUSPEND_TIME) < DEF_SUSPEND_TIME) ||
\r
5622 (_props->integerForKey(KEY_SUSPEND_TIME) >= _props->integerForKey(KEY_FORCED_SUSPEND_TIME)))
\r
5624 _props->setInteger(DEF_SUSPEND_TIME, KEY_SUSPEND_TIME);
\r
5629 if ((_props->integerForKey(KEY_FORCED_SUSPEND_TIME) == 0) ||
\r
5630 (_props->integerForKey(KEY_FORCED_SUSPEND_TIME) <= _props->integerForKey(KEY_SUSPEND_TIME)))
\r
5632 _props->setInteger(DEF_FORCED_SUSPEND_TIME, KEY_FORCED_SUSPEND_TIME);
\r
5637 if (_props->integerForKey(KEY_BEGIN_UDP_PORT) == 0)
\r
5639 _props->setInteger(DEF_BEGIN_UDP_PORT, KEY_BEGIN_UDP_PORT);
\r
5644 if ((_props->stringForKey(KEY_COLLECT_EPG_TIME) == NULL) ||
\r
5645 !_props->stringForKey(KEY_COLLECT_EPG_TIME)->isMatch(String::stringWithUTF8String("^\\d\\d:\\d\\d:\\d\\d$")))
\r
5647 _props->setString(DEF_COLLECT_EPG_TIME, KEY_COLLECT_EPG_TIME);
\r
5652 if (_props->arrayForKey(KEY_DO_NOT_IN_SUSPEND) == NULL)
\r
5654 Array *apps = Array::arrayWithCapacity(0);
\r
5655 apps->addObject(String::stringWithUTF8String("PIXELACORPORATION.*DtvView\\.exe$"));
\r
5656 apps->addObject(String::stringWithUTF8String("Common7\\\\IDE\\\\devenv\\.exe$"));
\r
5657 apps->addObject(String::stringWithUTF8String("Kodi\\\\Kodi\\.exe$"));
\r
5658 _props->setObject(apps, KEY_DO_NOT_IN_SUSPEND);
\r
5663 _store_path = _props->stringForKey(KEY_STORE_PATH);
\r
5664 if (_store_path == NULL)
\r
5667 // <Public Directory>/Videos を設定
\r
5668 const char *public_dir = GetPublicDirectory();
\r
5669 if (public_dir == NULL)
\r
5671 DebugLog0("error: GetPublicDirectory().");
\r
5675 _store_path = String::alloc()->initWithFormat("%s\\Videos", public_dir);
\r
5676 _props->setString(_store_path, KEY_STORE_PATH);
\r
5683 _store_path->retain();
\r
5686 // 実際にディレクトリが存在しているか確認
\r
5687 FileManager *fm = FileManager::defaultManager();
\r
5688 bool isDir = false;
\r
5689 if (!fm->fileExistsAtPath(_store_path, &isDir))
\r
5695 DebugLog0("error: \"%s\" is not exists.", _store_path->cString());
\r
5701 if (_props->dictionaryForKey(KEY_PRESETS) == NULL)
\r
5703 Dictionary *presets = Dictionary::dictionaryWithCapacity(0);
\r
5704 _props->setObject(presets, KEY_PRESETS);
\r
5707 // プリセットは、あとで実装。。。
\r
5711 preset = STR_ARRAY("-vcodec", "libx264",
\r
5714 "-acodec", "libfaac",
\r
5717 "-flags", "+loop-global_header",
\r
5719 "-bsf", "h264_mp4toannexb",
\r
5721 "-segment_format", "mpegts",
\r
5722 "-segment_time", "10",
\r
5724 presets->setObject(preset, KEY_DEFAULT);
\r
5729 // キャッシュ(HLSの一時ファイル格納先)パス
\r
5730 if (_props->stringForKey(KEY_CACHE_PATH) == NULL)
\r
5732 _props->setString(_store_path->stringByAppendingPathComponent("Cache"), KEY_CACHE_PATH);
\r
5733 _mkdir(_props->stringForKey(KEY_CACHE_PATH)->cString());
\r
5737 if (!fm->fileExistsAtPath(_props->stringForKey(KEY_CACHE_PATH), &isDir))
\r
5743 DebugLog0("error: \"%s\" is not exists.", _props->stringForKey(KEY_CACHE_PATH)->cString());
\r
5751 DebugLog0("props updated.");
\r
5752 if (!_props->writeToFile(_props_path, false))
\r
5754 DebugLog0("Can't write property file.");
\r
5761 DebugLog0(" Name : %s", _props->stringForKey(KEY_NAME)->cString());
\r
5762 DebugLog0(" Decode Enabled : %s", (_multi2_dll != NULL) ? "true" : "false");
\r
5763 DebugLog0(" HTTP Port : %d", _props->integerForKey(KEY_HTTP_PORT));
\r
5764 DebugLog0(" Suspend Time : %d min", _props->integerForKey(KEY_SUSPEND_TIME));
\r
5765 DebugLog0(" Forced Suspend Time : %d min", _props->integerForKey(KEY_FORCED_SUSPEND_TIME));
\r
5766 Array *apps = _props->arrayForKey(KEY_DO_NOT_IN_SUSPEND);
\r
5769 DebugLog1(" Do not in suspend :");
\r
5770 for (uint i = 0; i < apps->count(); ++i)
\r
5772 DebugLog1(" RegExp[%02d] : %s", i, ((String *)apps->objectAtIndex(i))->cString());
\r
5777 _epgs_path = String::alloc()->initWithFormat("%s%s.iptd.epgs.plist", _system_path->cString(), PLIST_PREFIX);
\r
5778 if (_epgs_path == NULL)
\r
5780 DebugLog0("error: set epgs file path.");
\r
5786 _epgs = Dictionary::alloc()->initWithContentsOfFile(_epgs_path);
\r
5787 if (_epgs == NULL)
\r
5789 DebugLog1("epgs file: %s (created)", _epgs_path->cString());
\r
5790 _epgs = Dictionary::alloc()->initWithCapacity(0);
\r
5794 DebugLog1("epgs file: %s", _epgs_path->cString());
\r
5801 _reservations_path = String::alloc()->initWithFormat("%s%s.iptd.reservations.plist", _system_path->cString(), PLIST_PREFIX);
\r
5802 if (_reservations_path == NULL)
\r
5804 DebugLog0("error: set reservations file path.");
\r
5810 _reservations = Dictionary::alloc()->initWithContentsOfFile(_reservations_path);
\r
5811 if (_reservations == NULL)
\r
5813 DebugLog1("reservations file: %s (created)", _reservations_path->cString());
\r
5814 _reservations = Dictionary::alloc()->initWithCapacity(0);
\r
5818 DebugLog1("reservations file: %s", _reservations_path->cString());
\r
5821 _reservation_seq_id = _reservations->integerForKey(KEY_EPG_LAST_RESV_ID);
\r
5825 _streaming_ctrls = Dictionary::alloc()->initWithCapacity(0);
\r
5828 String *rootPath = _system_path->stringByAppendingPathComponent("iptd_html");
\r
5829 if (!fm->fileExistsAtPath(rootPath, &isDir))
\r
5835 DebugLog0("error: \"%s\" is not exists.", rootPath->cString());
\r
5841 int port = _props->integerForKey(KEY_HTTP_PORT);
\r
5842 _httpd = NET::HTTPDaemon::alloc()->initWithPort(port, 10);
\r
5843 _httpd->setRootPath(rootPath);
\r
5844 _httpd->setDelegate(this);
\r
5845 if (!_httpd->start())
\r
5847 DebugLog0("Can't start httpd.");
\r
5853 _timer_restart = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_RESTART, false);
\r
5854 _timer_restart->fire();
\r
5859 // 初期化エラーがなければイベント待ちへ
\r
5862 result = Application::start();
\r
5864 DebugLog0("will terminate. 00");
\r
5870 DebugLog0("will terminate. 01");
\r
5873 _cancel_epg_collect = true;
\r
5877 if ((_timer_restart != NULL) && _timer_restart->valid())
\r
5879 _timer_restart->invalidate();
\r
5881 if ((_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
5883 _timer_epg_s->invalidate();
\r
5885 if ((_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5887 _timer_epg_t->invalidate();
\r
5889 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
5891 _timer_periodic->invalidate();
\r
5893 if ((_timer_periodic_2 != NULL) && _timer_periodic_2->valid())
\r
5895 _timer_periodic_2->invalidate();
\r
5899 for (int i = 0; i < _tunerCount; ++i)
\r
5901 if (_tuners[i] != NULL)
\r
5903 delete _tuners[i];
\r
5904 _tuners[i] = NULL;
\r
5909 resetWakeSchedule();
\r
5912 RELEASE(_timer_restart);
\r
5913 RELEASE(_timer_epg_s);
\r
5914 RELEASE(_timer_epg_t);
\r
5915 RELEASE(_timer_periodic);
\r
5916 RELEASE(_timer_periodic_2);
\r
5917 RELEASE(_streaming_ctrls);
\r
5919 RELEASE(_system_path);
\r
5920 RELEASE(_props_path);
\r
5922 RELEASE(_status_path);
\r
5924 RELEASE(_epgs_path);
\r
5926 RELEASE(_store_path);
\r
5927 RELEASE(_reservations_path);
\r
5928 RELEASE(_reservations);
\r
5930 if (_multi2_dll != NULL)
\r
5932 FreeLibrary(_multi2_dll);
\r
5938 DebugLog0("finished.");
\r
5940 #ifdef RAYM_MEMORY_CHECK
\r
5941 DebugLog0("global_raym_count_ = %d", Raym::global_raym_count_);
\r
5949 #pragma mark ------- コンストラクタ/デストラクタ -------
\r
5952 Controller::Controller()
\r
5956 Controller::~Controller()
\r
5960 Controller *Controller::alloc()
\r
5962 return new Controller();
\r
5967 #pragma mark ------- その他 -------
\r
5971 // HH:MM:SS 形式の文字列から time_t に変換
\r
5972 // 現在時刻が指定文字列の時刻以前の場合、当日の時刻。指定文字列の時刻よりも過ぎている場合、翌日の時刻を返す。
\r
5974 void Controller::getTimeWithString(String *str, time_t *time_var)
\r
5976 if ((str != NULL) && str->isMatch(String::stringWithUTF8String("^\\d\\d:\\d\\d:\\d\\d$")) && (time_var != NULL))
\r
5978 // 時:分:秒 を int型に分解
\r
5979 std::string time_str = str->cString();
\r
5980 int hour = atoi(time_str.substr(0, 2).c_str());
\r
5981 int min = atoi(time_str.substr(3, 2).c_str());
\r
5982 int sec = atoi(time_str.substr(6, 2).c_str());
\r
5983 DebugLog2("%02d:%02d:%02d", hour, min, sec);
\r
5986 time_t now = time(NULL);
\r
5988 if (localtime_s(&now_tm, &now) == 0)
\r
5990 int now_sec = now_tm.tm_hour * 3600 + now_tm.tm_min * 60 + now_tm.tm_sec;
\r
5991 int col_sec = hour * 3600 + min * 3600 + sec;
\r
5992 if (now_sec > col_sec)
\r
5996 now_tm.tm_hour = hour;
\r
5997 now_tm.tm_min = min;
\r
5998 now_tm.tm_sec = sec;
\r
6000 *time_var = mktime(&now_tm);
\r
6005 void Controller::getTimeWithEPG(Dictionary *epg, time_t *start, time_t *end)
\r
6007 if ((epg == NULL) || (start == NULL) || (end == NULL))
\r
6011 String *date = epg->stringForKey(KEY_EPG_DATE);
\r
6012 String *st = epg->stringForKey(KEY_EPG_START);
\r
6013 String *ed = epg->stringForKey(KEY_EPG_END);
\r
6014 if ((date == NULL) || (st == NULL) || (ed == NULL))
\r
6019 std::string dateStr = date->cString();
\r
6020 std::string stStr = st->cString();
\r
6021 std::string edStr = ed->cString();
\r
6023 tm_start.tm_year = atoi(dateStr.substr(0, 4).c_str()) - 1900;
\r
6024 tm_start.tm_mon = atoi(dateStr.substr(5, 2).c_str()) - 1;
\r
6025 tm_start.tm_mday = atoi(dateStr.substr(8, 2).c_str());
\r
6026 tm_start.tm_hour = atoi(stStr.substr(0, 2).c_str());
\r
6027 tm_start.tm_min = atoi(stStr.substr(3, 2).c_str());
\r
6028 tm_start.tm_sec = atoi(stStr.substr(6, 2).c_str());
\r
6031 tm_end.tm_year = atoi(dateStr.substr(0, 4).c_str()) - 1900;
\r
6032 tm_end.tm_mon = atoi(dateStr.substr(5, 2).c_str()) - 1;
\r
6033 tm_end.tm_mday = atoi(dateStr.substr(8, 2).c_str());
\r
6034 tm_end.tm_hour = atoi(edStr.substr(0, 2).c_str());
\r
6035 tm_end.tm_min = atoi(edStr.substr(3, 2).c_str());
\r
6036 tm_end.tm_sec = atoi(edStr.substr(6, 2).c_str());
\r
6037 if (stStr > edStr)
\r
6039 tm_end.tm_mday += 1;
\r
6041 *start = mktime(&tm_start);
\r
6042 *end = mktime(&tm_end);
\r