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
1538 // チューナ(streaming)制御/システム関連 周期処理
\r
1540 void Controller::periodic_2(void)
\r
1546 // マッピング(UDPPort:tuner,ch)情報取得
\r
1547 Dictionary *mapping = NULL;
\r
1548 if ((_streaming_ctrls != NULL) && ((mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL)) != NULL))
\r
1553 // どれだけ使用中なのか不明なので、まずは必要サイズを調べる
\r
1555 if (GetExtendedUdpTable(NULL, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
1557 // ERROR_INSUFFICIENT_BUFFER の場合、必要なバッファサイズが size に格納される
\r
1560 PMIB_UDPTABLE_OWNER_PID udptable = (PMIB_UDPTABLE_OWNER_PID)malloc(size);
\r
1561 if (udptable != NULL)
\r
1566 if (GetExtendedUdpTable(udptable, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == NO_ERROR)
\r
1569 DebugLog3("udptable->dwNumEntries: %d", udptable->dwNumEntries);
\r
1572 Dictionary *using_port = _streaming_ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
1573 if (using_port != NULL)
\r
1576 Array *using_ports = using_port->allKeys();
\r
1577 if (using_ports != NULL)
\r
1580 for (uint i = 0; i < using_ports->count(); ++i)
\r
1583 bool stop_need = true;
\r
1586 for (uint j = 0; j < udptable->dwNumEntries; ++j)
\r
1588 if (((String *)using_ports->objectAtIndex(i))->intValue() == ntohs((WORD)udptable->table[j].dwLocalPort))
\r
1591 stop_need = false;
\r
1600 String *tuner_and_channel = mapping->stringForKey((String *)using_ports->objectAtIndex(i));
\r
1601 if (tuner_and_channel != NULL)
\r
1604 Range r = tuner_and_channel->rangeOfString(",");
\r
1605 if (r.location != NotFound)
\r
1607 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
1608 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
1609 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
1611 DebugLog0("auto streaming stop: %s", ((String *)using_ports->objectAtIndex(i))->cString());
\r
1613 _tuners[tuner]->stopStreaming();
\r
1614 using_port->removeObjectForKey((String *)using_ports->objectAtIndex(i));
\r
1624 for (uint i = 0; i < udptable->dwNumEntries; ++i)
\r
1628 sprintf_s(port, "%d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
1629 DebugLog3("port = %s", port);
\r
1632 String *tuner_and_channel = mapping->stringForKey(port);
\r
1633 if (tuner_and_channel != NULL)
\r
1635 // 取得OK: 監視対象ポートが使用されている
\r
1638 bool auto_streaming = false;
\r
1639 char exec_path[MAX_PATH];
\r
1640 memset(exec_path, 0, sizeof(exec_path));
\r
1643 size_t returnValue;
\r
1644 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, udptable->table[i].dwOwningPid);
\r
1645 if (hProcess != NULL)
\r
1647 TCHAR exec[MAX_PATH];
\r
1648 memset(exec, 0, sizeof(exec));
\r
1649 DWORD len = sizeof(exec) - 1;
\r
1652 if (QueryFullProcessImageName(hProcess, 0, exec, &len))
\r
1655 if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) == 0)
\r
1659 // とりあえず、、、現状は "ffmpeg.exe" / "vlc.exe" / "Kodi.exe" があったら auto_streaming を true にする
\r
1660 if ((strstr(exec_path, "ffmpeg.exe") != NULL) ||
\r
1661 (strstr(exec_path, "vlc.exe") != NULL) ||
\r
1662 (strstr(exec_path, "Kodi.exe") != NULL))
\r
1664 auto_streaming = true;
\r
1670 CloseHandle(hProcess);
\r
1673 if (auto_streaming)
\r
1676 Range r = tuner_and_channel->rangeOfString(",");
\r
1677 if (r.location != NotFound)
\r
1679 int tuner = tuner_and_channel->substringToIndex(r.location)->intValue();
\r
1680 int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue();
\r
1681 DebugLog3("tuner: %d, channel: %d", tuner, channel);
\r
1686 // 非ストリーミング中 かつ 非レコーディング中 または チャンネルが同じ 場合
\r
1687 if (!_tuners[tuner]->isStreaming() && (!_tuners[tuner]->isRecording() || _tuners[tuner]->channel() == channel))
\r
1691 if (_tuners[tuner]->channel() != channel)
\r
1693 setChannel(tuner, channel);
\r
1696 SOCKADDR_IN dst_addr;
\r
1697 dst_addr.sin_family = AF_INET;
\r
1698 dst_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
\r
1699 dst_addr.sin_port = (WORD)udptable->table[i].dwLocalPort;
\r
1701 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
1704 DebugLog0("auto streaming start: %d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
1707 using_port = _streaming_ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
1708 if (using_port == NULL)
\r
1710 using_port = Dictionary::dictionaryWithCapacity(0);
\r
1711 _streaming_ctrls->setObject(using_port, KEY_UDP_IN_USE);
\r
1713 using_port->setBool(true, port);
\r
1734 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
1737 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
1738 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
1740 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
1744 GetSystemTimeAsFileTime(&ft);
\r
1747 __time64_t now_sec;
\r
1748 __time64_t now_usec;
\r
1749 now_sec = ft.dwHighDateTime;
\r
1751 now_sec |= ft.dwLowDateTime;
\r
1752 now_sec /= 10; /*convert into microseconds*/
\r
1753 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
1754 now_usec = (now_sec % 1000000UL);
\r
1755 now_sec = now_sec / 1000000UL;
\r
1757 TimeInterval interval = (TimeInterval)now_usec;
\r
1758 interval = interval / 1000000;
\r
1759 _timer_periodic_2->setTimeInterval(1.005 - interval);
\r
1764 #pragma mark ------- HTTP制御 -------
\r
1767 static std::string epg_regist_form(Dictionary *epg)
\r
1769 DebugLog3("epg_regist_form() start.");
\r
1773 if ((epg != NULL) &&
\r
1774 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
1775 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
1776 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
1777 (epg->stringForKey(KEY_EPG_END) != NULL) &&
\r
1778 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
1779 (epg->stringForKey(KEY_EPG_TITLE) != NULL))
\r
1781 epgs += "<form id=\"";
\r
1783 epgs += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
1785 epgs += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
1786 epgs += "\" title=\"";
\r
1787 epgs += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
1789 epgs += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
1790 epgs += "\" class=\"panel\" action=\"regist.cgi\" method=\"GET\" target=\"_self\" onclick='return confirm(\"Is it ok?\");'>";
\r
1794 epgs += LocalizedString(KEY_I18N_Broadcasting_Time, NULL)->cString();
\r
1796 epgs += "<fieldset>";
\r
1797 epgs += "<p class=\"normalText\"> ";
\r
1798 epgs += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
1800 epgs += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
1802 epgs += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
1804 epgs += "</fieldset>";
\r
1808 epgs += LocalizedString(KEY_I18N_Program_Title, NULL)->cString();
\r
1810 epgs += "<fieldset>";
\r
1811 epgs += "<p class=\"normalText\"> ";
\r
1812 epgs += epg->stringForKey(KEY_EPG_TITLE)->cString();
\r
1814 epgs += "</fieldset>";
\r
1817 if (epg->stringForKey(KEY_EPG_DESCRIPTION) != NULL)
\r
1820 epgs += LocalizedString(KEY_I18N_Description, NULL)->cString();
\r
1822 epgs += "<fieldset>";
\r
1823 epgs += "<p class=\"normalText\"> ";
\r
1824 epgs += epg->stringForKey(KEY_EPG_DESCRIPTION)->cString();
\r
1826 epgs += "</fieldset>";
\r
1830 epgs += "<input type=\"hidden\" name=\"service_id\" value=\"";
\r
1831 epgs += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
1833 epgs += "<input type=\"hidden\" name=\"event_id\" value=\"";
\r
1834 epgs += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
1836 epgs += "<input class=\"redButton\" type=\"submit\" value=\"";
\r
1837 epgs += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
1839 // epgs += "<a class=\"redButton\" type=\"submit\">";
\r
1840 // epgs += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
1841 // epgs += "</a>";
\r
1842 epgs += "</form>";
\r
1848 HTTPResponse *responseWithDictionary(HTTPRequest *request, Dictionary *dictionary)
\r
1850 HTTPResponse *result = NULL;
\r
1851 if ((request != NULL) && (dictionary != NULL))
\r
1853 std::string xml = dictionary->toString();
\r
1856 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
1859 // Content-Encoding
\r
1862 header->setFieldBodyWithName("application/xml", "Content-Type");
\r
1864 // Tranfer-Encoding
\r
1866 header->setFieldBodyWithName(String::stringWithFormat("%I64u", xml.length()), "Content-Length");
\r
1869 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(xml.c_str()));
\r
1872 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
1875 if (message != NULL)
\r
1877 result = HTTPResponse::alloc()->init();
\r
1878 result->autorelease();
\r
1879 result->setVersion(request->version());
\r
1880 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
1881 result->setStatus(200);
\r
1882 result->setMessage(message);
\r
1889 // positive response by XML
\r
1890 HTTPResponse *responseForSuccess(HTTPRequest *request)
\r
1892 Dictionary *dict = Dictionary::dictionaryWithCapacity(0);
\r
1893 dict->setString("Success", KEY_RESULT);
\r
1894 return responseWithDictionary(request, dict);
\r
1897 // negative response by XML
\r
1898 HTTPResponse *responseForFailed(HTTPRequest *request)
\r
1900 Dictionary *dict = Dictionary::dictionaryWithCapacity(0);
\r
1901 dict->setString("Failed", KEY_RESULT);
\r
1902 return responseWithDictionary(request, dict);
\r
1905 HTTPResponse *Controller::responseWithHTML(HTTPRequest *request, String *html)
\r
1907 HTTPResponse *result = NULL;
\r
1908 if ((html != NULL) && (request != NULL))
\r
1911 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
1914 // Content-Encoding
\r
1917 header->setFieldBodyWithName("text/html", "Content-Type");
\r
1919 // Tranfer-Encoding
\r
1921 header->setFieldBodyWithName(String::stringWithFormat("%I64u", html->length()), "Content-Length");
\r
1924 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(html);
\r
1927 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
1930 if (message != NULL)
\r
1932 // result = HTTPResponse::response();
\r
1933 result = HTTPResponse::alloc()->init();
\r
1934 result->setVersion(request->version());
\r
1935 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
1936 result->setStatus(200);
\r
1937 result->setMessage(message);
\r
1938 result->autorelease();
\r
1945 HTTPResponse *Controller::responseWithUTF8Text(HTTPRequest *request, String *text)
\r
1947 HTTPResponse *result = NULL;
\r
1948 if ((text != NULL) && (request != NULL))
\r
1951 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
1954 // Content-Encoding
\r
1957 header->setFieldBodyWithName("text/plane; charset=UTF-8", "Content-Type");
\r
1959 // Tranfer-Encoding
\r
1961 header->setFieldBodyWithName(String::stringWithFormat("%I64u", text->length()), "Content-Length");
\r
1964 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(text);
\r
1967 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
1970 if (message != NULL)
\r
1972 // result = HTTPResponse::response();
\r
1973 result = HTTPResponse::alloc()->init();
\r
1974 result->setVersion(request->version());
\r
1975 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
1976 result->setStatus(200);
\r
1977 result->setMessage(message);
\r
1978 result->autorelease();
\r
1985 HTTPResponse *Controller::responseByResultAndReferer(HTTPRequest *request, bool result, const char *referer)
\r
1987 HTTPResponse *retval = NULL;
\r
1991 String *ref = NULL;
\r
1992 InternetTextMessage *msg = request->message();
\r
1995 InternetTextMessageHeader *header = msg->header();
\r
1996 if (header != NULL)
\r
1998 String *field_referer = header->fieldBodyForName("Referer");
\r
1999 if (field_referer != NULL)
\r
2001 String *field_host = header->fieldBodyForName("Host");
\r
2002 if (field_host != NULL)
\r
2004 std::string tmp = "http://";
\r
2005 tmp += field_host->cString();
\r
2008 iui = field_referer->isEqualToString(tmp.c_str());
\r
2009 DebugLog2("tmp: %s", tmp.c_str());
\r
2010 DebugLog2("ref: %s", field_referer->cString());
\r
2015 // if ((ref != NULL) && match(ref->cString(), referer))
\r
2016 // if ((ref != NULL) && ref->isEqualToString(referer))
\r
2019 String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");
\r
2020 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2023 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", "Result");
\r
2024 std::string contents;
\r
2025 std::string reservations;
\r
2026 contents += "<div id=\"home\" class=\"panel\" title=\"Result\" selected=\"true\">";
\r
2029 contents += "<h2>Success</h2>";
\r
2033 contents += "<h2>Failed</h2>";
\r
2035 contents += "</div>";
\r
2037 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2038 retval = responseWithHTML(request, html);
\r
2045 retval = responseForSuccess(request);
\r
2049 retval = responseForFailed(request);
\r
2056 HTTPResponse *Controller::responseForMain(HTTPRequest *request, SOCKADDR_IN *client)
\r
2058 DebugLog2("Controller::responseForMain()");
\r
2060 HTTPResponse *result = NULL;
\r
2061 while ((request != NULL) && (client != NULL))
\r
2063 String *path = _httpd->rootPath();
\r
2066 DebugLog3("_httpd->rootPath() ng.");
\r
2070 path = path->stringByAppendingPathComponent("template1.html");
\r
2073 DebugLog3("path->stringByAppendingPathComponent() ng.");
\r
2077 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2080 DebugLog3("String::stringWithContentsOfFile() ng.");
\r
2084 String *server_name = _props->stringForKey(KEY_NAME);
\r
2085 if (server_name == NULL)
\r
2087 DebugLog3("_props->stringForKey(KEY_NAME) ng.");
\r
2091 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", server_name);
\r
2094 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2098 html = html->stringByReplacingOccurrencesOfString("%%PAGE_TITLE%%", LocalizedString(KEY_I18N_Main_Menu, NULL));
\r
2101 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2104 std::string contents;
\r
2105 contents += "<div id=\"home\" class=\"panel\" selected=\"true\">";
\r
2106 contents += "<ul>";
\r
2107 contents += "<li><a target=\"_self\" href=\"/programs.html\">";
\r
2108 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2109 contents += "</a></li>";
\r
2110 contents += "<li><a target=\"_self\" href=\"/tv.html\">";
\r
2111 contents += LocalizedString(KEY_I18N_TV, NULL)->cString();
\r
2112 contents += "</a></li>";
\r
2113 contents += "<li><a target=\"_self\" href=\"/video.html\">";
\r
2114 contents += LocalizedString(KEY_I18N_Video, NULL)->cString();
\r
2115 contents += "</a></li>";
\r
2116 contents += "<li><a target=\"_self\" href=\"/reservation.html\">";
\r
2117 contents += LocalizedString(KEY_I18N_Reservation, NULL)->cString();
\r
2118 contents += "</a></li>";
\r
2119 contents += "</ul>";
\r
2121 contents += "<ul>";
\r
2122 contents += "<li><a target=\"_self\" href=\"/exec_vlc.html\">VLC media player";
\r
2123 contents += "</ul>";
\r
2125 contents += "<ul>";
\r
2126 contents += "<li><a target=\"_self\" href=\"/status.html\">";
\r
2127 contents += LocalizedString(KEY_I18N_Tuner_Status, NULL)->cString();
\r
2128 contents += "</a></li>";
\r
2129 contents += "</ul>";
\r
2130 contents += "<center><a target=\"_self\" href=\"/iptd.log\">Ver. ";
\r
2131 contents += VERSION;
\r
2132 contents += "</a></center>";
\r
2133 contents += "</div>";
\r
2135 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2138 result = responseWithHTML(request, html);
\r
2147 HTTPResponse *Controller::responseForPrograms(HTTPRequest *request, SOCKADDR_IN *client)
\r
2149 DebugLog2("Controller::responseForPrograms() start.");
\r
2151 HTTPResponse *result = NULL;
\r
2152 while ((request != NULL) && (client != NULL))
\r
2154 String *path = _httpd->rootPath();
\r
2157 DebugLog3("_httpd->rootPath() ng.");
\r
2161 path = path->stringByAppendingPathComponent("template2.html");
\r
2164 DebugLog3("path->stringByAppendingPathComponent() ng.");
\r
2168 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2171 DebugLog3("String::stringWithContentsOfFile() ng.");
\r
2175 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Programs, NULL));
\r
2178 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2182 std::string contents;
\r
2185 contents += "<ul id=\"home\" title=\"";
\r
2186 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2187 contents += "\" selected=\"true\">";
\r
2189 contents += "<li>";
\r
2190 contents += "<a href=\"#isdb_t\">";
\r
2191 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2192 contents += "</a></li>";
\r
2194 contents += "<li>";
\r
2195 contents += "<a href=\"#isdb_s\">";
\r
2196 contents += "BS/CS";
\r
2197 contents += "</a></li>";
\r
2199 contents += "</ul>";
\r
2202 contents += "<ul id=\"isdb_t\" title=\"";
\r
2203 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2204 contents += "\">";
\r
2205 Array *stations = stationInfos(Tuner::ISDB_T);
\r
2206 for (uint i = 0; i < stations->count(); ++i)
\r
2208 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2209 if ((station != NULL) &&
\r
2210 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2211 (station->stringForKey(KEY_NAME) != NULL))
\r
2213 contents += "<li>";
\r
2214 contents += "<a href=\"#isdb_t_";
\r
2215 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2216 contents += "\">";
\r
2217 contents += station->stringForKey(KEY_NAME)->cString();
\r
2218 contents += "</a></li>";
\r
2221 contents += "</ul>";
\r
2224 for (uint i = 0; i < stations->count(); ++i)
\r
2226 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2227 if ((station != NULL) &&
\r
2228 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2229 (station->stringForKey(KEY_NAME) != NULL))
\r
2232 contents += "<ul id=\"isdb_t_";
\r
2233 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2234 contents += "\" title=\"";
\r
2235 contents += station->stringForKey(KEY_NAME)->cString();
\r
2236 contents += "\">";
\r
2238 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2239 for (uint i = 0; i < programs->count(); ++i)
\r
2241 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2242 if ((epg != NULL) &&
\r
2243 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2244 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2245 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2246 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2247 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2249 contents += "<li>";
\r
2250 contents += "<a href=\"#epg_";
\r
2251 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2253 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2254 contents += "\">";
\r
2255 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2256 contents += " ";
\r
2257 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2259 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2260 contents += "</a></li>";
\r
2262 epgs += epg_regist_form(epg);
\r
2265 contents += "</ul>";
\r
2270 contents += "<ul id=\"isdb_s\" title=\"";
\r
2271 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2272 contents += "\">";
\r
2273 stations = stationInfos(Tuner::ISDB_S);
\r
2274 for (uint i = 0; i < stations->count(); ++i)
\r
2276 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2277 if ((station != NULL) &&
\r
2278 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2279 (station->stringForKey(KEY_NAME) != NULL))
\r
2281 contents += "<li>";
\r
2282 contents += "<a href=\"#isdb_s_";
\r
2283 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2284 contents += "\">";
\r
2285 contents += station->stringForKey(KEY_NAME)->cString();
\r
2286 contents += "</a></li>";
\r
2289 contents += "</ul>";
\r
2292 for (uint i = 0; i < stations->count(); ++i)
\r
2294 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2295 if ((station != NULL) &&
\r
2296 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2297 (station->stringForKey(KEY_NAME) != NULL))
\r
2299 contents += "<ul id=\"isdb_s_";
\r
2300 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2301 contents += "\" title=\"";
\r
2302 contents += station->stringForKey(KEY_NAME)->cString();
\r
2303 contents += "\">";
\r
2305 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2306 for (uint i = 0; i < programs->count(); ++i)
\r
2308 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2309 if ((epg != NULL) &&
\r
2310 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2311 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2312 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2313 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2314 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2316 contents += "<li>";
\r
2317 contents += "<a href=\"#epg_";
\r
2318 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2320 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2321 contents += "\">";
\r
2322 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2323 contents += " ";
\r
2324 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2326 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2327 contents += "</a></li>";
\r
2329 epgs += epg_regist_form(epg);
\r
2332 contents += "</ul>";
\r
2337 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2340 result = responseWithHTML(request, html);
\r
2348 HTTPResponse *Controller::responseForReservation(HTTPRequest *request, SOCKADDR_IN *client)
\r
2350 DebugLog2("Controller::responseForReservation() start.");
\r
2355 HTTPResponse *result = NULL;
\r
2356 while ((request != NULL) && (client != NULL))
\r
2358 // create array of reservations sorted by seq_id.
\r
2359 Array *array = Array::arrayWithCapacity(0);
\r
2360 for (int i = 0; i < _tunerCount; ++i)
\r
2362 Array *tmp = _reservations->arrayForKey(_tuners[i]->name());
\r
2367 for (uint idx = 0; idx < tmp->count(); ++idx)
\r
2369 Dictionary *epg = (Dictionary *)tmp->objectAtIndex(idx);
\r
2377 getTimeWithEPG(epg, &epg_start, &tmp_end);
\r
2379 bool inserted = false;
\r
2380 for (uint j = 0; j < array->count(); ++j)
\r
2382 Dictionary *epg2 = (Dictionary *)array->objectAtIndex(j);
\r
2388 time_t epg2_start;
\r
2389 getTimeWithEPG(epg2, &epg2_start, &tmp_end);
\r
2391 if (epg_start <= epg2_start)
\r
2393 array->insertObject(epg, j);
\r
2401 array->addObject(epg);
\r
2406 String *path = _httpd->rootPath();
\r
2412 path = path->stringByAppendingPathComponent("template2.html");
\r
2418 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2424 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Reservation, NULL));
\r
2430 std::string contents;
\r
2431 std::string reservations;
\r
2432 contents += "<ul id=\"home\" title=\"";
\r
2433 contents += LocalizedString(KEY_I18N_Reservation, NULL)->cString();
\r
2434 contents += "\" selected=\"true\">";
\r
2437 contents += "<li><a href=\"#tuners\">";
\r
2438 contents += "<font color=\"blue\">[";
\r
2439 contents += LocalizedString(KEY_I18N_Tuner, NULL)->cString();
\r
2440 contents += "]</font>";
\r
2441 contents += "</a></li>";
\r
2447 contents += "<li><a href=\"#new_reservation\">";
\r
2448 contents += "<font color=\"red\">[";
\r
2449 contents += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
2450 contents += "]</font>";
\r
2451 contents += "</a></li>";
\r
2456 contents += "<li><a href=\"#keywords\">";
\r
2457 contents += "<font color=\"blue\">[";
\r
2458 contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2459 contents += "]</font>";
\r
2460 contents += "</a></li>";
\r
2465 for (uint i = 0; i < array->count(); ++i)
\r
2467 Dictionary *epg = (Dictionary *)array->objectAtIndex(i);
\r
2469 sprintf_s(seq_id, "%06d", epg->integerForKey(KEY_EPG_RESV_ID) % 1000000);
\r
2470 contents += "<li>";
\r
2471 contents += "<a href=\"#seqid";
\r
2472 contents += seq_id;
\r
2473 contents += "\">";
\r
2474 String *title = epg->stringForKey(KEY_EPG_TITLE);
\r
2475 if (title != NULL)
\r
2477 contents += title->cString();
\r
2483 Controller::getTimeWithEPG(epg, &start, &end);
\r
2485 if (localtime_s(&tm, &start) == 0)
\r
2487 char date_time[24];
\r
2488 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
2489 contents += date_time;
\r
2493 contents += seq_id;
\r
2496 contents += "</a></li>";
\r
2499 reservations += "<div id=\"";
\r
2500 reservations += "seqid";
\r
2501 reservations += seq_id;
\r
2502 reservations += "\" title=\"";
\r
2503 reservations += "xxxxxx";
\r
2504 reservations += "\" class=\"panel\">";
\r
2506 //reservations += "<h2>Status</h2>";
\r
2507 reservations += "<fieldset>";
\r
2510 reservations += "<div class=\"row\">";
\r
2511 reservations += "<label>Date</label>";
\r
2512 reservations += "<span>";
\r
2513 String *tmp = epg->stringForKey(KEY_EPG_DATE);
\r
2514 reservations += tmp->cString();
\r
2515 reservations += "</span>";
\r
2516 reservations += "</div>";
\r
2518 reservations += "<div class=\"row\">";
\r
2519 reservations += "<label>Start</label>";
\r
2520 reservations += "<span>";
\r
2521 tmp = epg->stringForKey(KEY_EPG_START);
\r
2522 reservations += tmp->cString();
\r
2523 reservations += "</span>";
\r
2524 reservations += "</div>";
\r
2526 reservations += "<div class=\"row\">";
\r
2527 reservations += "<label>End</label>";
\r
2528 reservations += "<span>";
\r
2529 tmp = epg->stringForKey(KEY_EPG_END);
\r
2530 reservations += tmp->cString();
\r
2531 reservations += "</span>";
\r
2532 reservations += "</div>";
\r
2534 reservations += "</fieldset>";
\r
2536 reservations += "<a class=\"whiteButton\" type=\"submit\" href=\"/cancel.cgi?";
\r
2537 reservations += "resv_id=";
\r
2538 reservations += seq_id;
\r
2539 reservations += "\" onclick='return confirm(\"To cancel. Is it ok?\");'>";
\r
2540 reservations += LocalizedString(KEY_I18N_Cancel, NULL)->cString();
\r
2541 reservations += "</a>";
\r
2543 reservations += "</div>";
\r
2546 contents += "</ul>";
\r
2547 contents += reservations;
\r
2555 time_t time1 = time(NULL);
\r
2556 time1 = (time1 + 15 * 60) / (15 * 60);
\r
2557 time1 = time1 * 15 * 60;
\r
2558 time_t time2 = time1 + 15 * 60;
\r
2559 localtime_s(&tm1, &time1);
\r
2560 localtime_s(&tm2, &time2);
\r
2562 contents += "<form name=\"reservation\" id=\"new_reservation\" class=\"panel\" method=\"GET\" action=\"regist.cgi\" target=\"_self\">";
\r
2563 contents += "<fieldset>";
\r
2564 contents += "<div class=\"row\">";
\r
2565 contents += "<label>";
\r
2566 contents += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
2567 contents += " : </label>";
\r
2568 contents += "<span>";
\r
2569 contents += "<select name=\"service_id\" size=\"1\">";
\r
2572 Array *stationInfos = Controller::stationInfos(Tuner::ISDB_T);
\r
2573 if (stationInfos != NULL)
\r
2575 stationInfos->addObjectsFromArray(Controller::stationInfos(Tuner::ISDB_S));
\r
2579 stationInfos = Controller::stationInfos(Tuner::ISDB_S);
\r
2581 for (uint i = 0; (stationInfos != NULL) && (i < stationInfos->count()); ++i)
\r
2583 Array *services = ((Dictionary *)stationInfos->objectAtIndex(i))->arrayForKey(KEY_SERVICES);
\r
2585 // とりえあず、現状は最初のサービスのみ表示
\r
2586 // for (uint j = 0; (services != NULL) && (j < services->count()); ++j)
\r
2587 for (uint j = 0; (services != NULL) && (j < 1); ++j)
\r
2589 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
2592 if ((service->stringForKey(KEY_SERVICE_TYPE) != NULL) && service->stringForKey(KEY_SERVICE_TYPE)->isEqualToString("1"))
\r
2594 String *name = service->stringForKey(KEY_NAME);
\r
2595 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
2596 if ((name != NULL) && (sid != NULL))
\r
2598 String *tmp = String::stringWithFormat("<option value=\"%s\">%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
2599 contents += tmp->cString();
\r
2605 contents += "</select>";
\r
2606 contents += "</span>";
\r
2607 contents += "</div>";
\r
2608 contents += "<div class=\"row\">";
\r
2609 contents += "<label>";
\r
2610 contents += LocalizedString(KEY_I18N_Date, NULL)->cString();
\r
2611 contents += " : </label>";
\r
2612 contents += "<span>";
\r
2613 contents += "<select name=\"year\" size=\"1\">";
\r
2614 for (int year = tm1.tm_year + 1900; year < tm1.tm_year + 1900 + 3; ++year)
\r
2616 char year_buf[64];
\r
2617 sprintf_s(year_buf, "<option value=\"%d\">%d</option>", year, year);
\r
2618 contents += year_buf;
\r
2620 contents += "</select>";
\r
2621 contents += "<select name=\"month\" size=\"1\">";
\r
2622 for (int month = 1; month < 13; ++month)
\r
2624 char month_buf[64];
\r
2625 if (month == tm1.tm_mon + 1)
\r
2627 sprintf_s(month_buf, "<option value=\"%d\" selected>%d</option>", month, month);
\r
2631 sprintf_s(month_buf, "<option value=\"%d\">%d</option>", month, month);
\r
2633 contents += month_buf;
\r
2635 contents += "</select>";
\r
2636 contents += "<select name=\"day\" size=\"1\">";
\r
2637 for (int day = 1; day < 32; ++day)
\r
2640 if (day == tm1.tm_mday)
\r
2642 sprintf_s(day_buf, "<option value=\"%d\" selected>%d</option>", day, day);
\r
2646 sprintf_s(day_buf, "<option value=\"%d\">%d</option>", day, day);
\r
2648 contents += day_buf;
\r
2650 contents += "</select>";
\r
2651 contents += "</span>";
\r
2652 contents += "</div>";
\r
2653 contents += "<div class=\"row\">";
\r
2654 contents += "<label>";
\r
2655 contents += LocalizedString(KEY_I18N_Start_Time, NULL)->cString();
\r
2656 contents += " : </label>";
\r
2657 contents += "<span>";
\r
2658 contents += "<select name=\"start_hour\" size=\"1\">";
\r
2659 for (int sh = 0; sh < 24; ++sh)
\r
2662 if (sh == tm1.tm_hour)
\r
2664 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
2668 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
2670 contents += sh_buf;
\r
2672 contents += "</select>";
\r
2673 contents += "<select name=\"start_min\" size=\"1\">";
\r
2674 for (int sm = 0; sm < 60; ++sm)
\r
2677 if (sm == tm1.tm_min)
\r
2679 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
2683 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
2685 contents += sm_buf;
\r
2687 contents += "</select>";
\r
2688 contents += "</span>";
\r
2689 contents += "</div>";
\r
2690 contents += "<div class=\"row\">";
\r
2691 contents += "<label>";
\r
2692 contents += LocalizedString(KEY_I18N_End_Time, NULL)->cString();
\r
2693 contents += " : </label>";
\r
2694 contents += "<span>";
\r
2695 contents += "<select name=\"end_hour\" size=\"1\">";
\r
2696 for (int eh = 0; eh < 24; ++eh)
\r
2699 if (eh == tm2.tm_hour)
\r
2701 sprintf_s(eh_buf, "<option value=\"%02d\" selected>%02d</option>", eh, eh);
\r
2705 sprintf_s(eh_buf, "<option value=\"%02d\">%02d</option>", eh, eh);
\r
2707 contents += eh_buf;
\r
2709 contents += "</select>";
\r
2710 contents += "<select name=\"end_min\" size=\"1\">";
\r
2711 for (int em = 0; em < 60; ++em)
\r
2714 if (em == tm2.tm_min)
\r
2716 sprintf_s(em_buf, "<option value=\"%02d\" selected>%02d</option>", em, em);
\r
2720 sprintf_s(em_buf, "<option value=\"%02d\">%02d</option>", em, em);
\r
2722 contents += em_buf;
\r
2724 contents += "</select>";
\r
2725 contents += "</span>";
\r
2726 contents += "</div>";
\r
2727 contents += "<div class=\"row\">";
\r
2728 contents += "<label>";
\r
2729 contents += LocalizedString(KEY_I18N_Repeat, NULL)->cString();
\r
2730 contents += " : </label>";
\r
2731 contents += "<span>";
\r
2732 contents += "<select name=\"repeat\" size=\"1\">";
\r
2733 contents += "<option value=\"off\" selected>";
\r
2734 contents += LocalizedString(KEY_I18N_Repeat_off, NULL)->cString();
\r
2735 contents += "</option>";
\r
2736 contents += "<option value=\"everyday\">";
\r
2737 contents += LocalizedString(KEY_I18N_Repeat_everyday, NULL)->cString();
\r
2738 contents += "</option>";
\r
2739 contents += "<option value=\"weekly\">";
\r
2740 contents += LocalizedString(KEY_I18N_Repeat_weekly, NULL)->cString();
\r
2741 contents += "</option>";
\r
2742 contents += "<option value=\"weekday\">";
\r
2743 contents += LocalizedString(KEY_I18N_Repeat_weekday, NULL)->cString();
\r
2744 contents += "</option>";
\r
2745 contents += "</select>";
\r
2746 contents += "</span>";
\r
2747 contents += "</div>";
\r
2748 contents += "</fieldset>";
\r
2750 contents += "<input type=\"submit\" class=\"whiteButton\" value=\"";
\r
2751 contents += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
2752 contents += "\">";
\r
2753 contents += "</form>";
\r
2763 contents += "<ul id=\"tuners\" title=\"";
\r
2764 contents += LocalizedString(KEY_I18N_Tuner, NULL)->cString();
\r
2765 contents += "\">";
\r
2767 std::string controls;
\r
2768 Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);
\r
2769 if (tunerInfos != NULL)
\r
2771 for (int i = 0; i < _tunerCount; ++i)
\r
2773 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name());
\r
2774 if (tunerInfo != NULL)
\r
2776 if (tunerInfo->boolForKey(KEY_INITIALIZED) && tunerInfo->boolForKey(KEY_ENABLED))
\r
2779 sprintf_s(key, "%03d", i);
\r
2782 contents += "<li>";
\r
2783 contents += "<a href=\"#tuner";
\r
2785 contents += "\">";
\r
2788 Dictionary *dict = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
2792 sprintf_s(chkey, "%03d", tunerInfo->integerForKey(KEY_CHANNEL));
\r
2793 dict = dict->dictionaryForKey(chkey);
\r
2794 String *name = dict->stringForKey(KEY_NAME);
\r
2797 contents += name->cString();
\r
2806 contents += _tuners[i]->name();
\r
2808 contents += "</a></li>";
\r
2811 controls += "<form name=\"control\" id=\"tuner";
\r
2813 controls += "\" class=\"panel\" method=\"GET\" action=\"/";
\r
2815 controls += "/recording=on\" target=\"_self\">";
\r
2818 controls += "<fieldset>";
\r
2821 controls += "<div class=\"row\">";
\r
2822 controls += "<label>";
\r
2823 controls += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
2824 controls += " : </label>";
\r
2825 controls += "<span>";
\r
2826 controls += "<select name=\"channel\" size=\"1\">";
\r
2827 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
2828 if (channels != NULL)
\r
2830 for (int ch = 0; ch <= Tuner::MAX_CHANNELS_ISDB_T; ++ch)
\r
2833 sprintf_s(chkey, "%03d", ch);
\r
2834 dict = channels->dictionaryForKey(chkey);
\r
2839 Array *services = (Array *)dict->objectForKey(KEY_SERVICES);
\r
2840 if (services != NULL)
\r
2842 for (uint s = 0; s < services->count(); ++s)
\r
2844 Dictionary *service = (Dictionary *)services->objectAtIndex(s);
\r
2845 if (service != NULL)
\r
2848 sprintf_s(sid, "%d", service->integerForKey(KEY_SERVICE_ID));
\r
2849 controls += "<option value=\"";
\r
2850 controls += chkey;
\r
2854 String *name = service->stringForKey(KEY_NAME);
\r
2857 controls += name->cString();
\r
2861 controls += "]</option>";
\r
2867 controls += "</select>";
\r
2868 controls += "</span>";
\r
2869 controls += "</div>";
\r
2873 controls += "<div class=\"row\">";
\r
2874 controls += "<label>";
\r
2875 controls += LocalizedString(KEY_I18N_Time, NULL)->cString();
\r
2876 controls += " : </label>";
\r
2877 controls += "<span>";
\r
2878 controls += "<select name=\"hour\" size=\"1\">";
\r
2879 for (int sh = 0; sh < 24; ++sh)
\r
2884 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
2888 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
2890 controls += sh_buf;
\r
2892 controls += "</select>";
\r
2893 controls += "<select name=\"min\" size=\"1\">";
\r
2894 for (int sm = 0; sm < 60; ++sm)
\r
2899 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
2903 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
2905 controls += sm_buf;
\r
2907 controls += "</select>";
\r
2908 controls += "</span>";
\r
2909 controls += "</div>";
\r
2912 controls += "</fieldset>";
\r
2915 controls += "<input type=\"submit\" class=\"whiteButton\" value=\"";
\r
2916 controls += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
2917 controls += "\">";
\r
2918 controls += "</form>";
\r
2923 contents += "</ul>";
\r
2924 contents += controls;
\r
2933 contents += "<ul id=\"keywords\" title=\"";
\r
2934 contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2935 contents += "\">";
\r
2937 contents += "<li><a href=\"#dialogForm\">";
\r
2938 contents += "<font color=\"red\">[";
\r
2939 // contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2940 contents += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
2941 contents += "]</font>";
\r
2942 contents += "</a></li>";
\r
2945 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
2946 if (keywords_info != NULL)
\r
2949 Array *keys = keywords_info->allKeys();
\r
2952 for (uint i = 0; i < keys->count(); ++i)
\r
2954 Dictionary *kwd_inf = keywords_info->dictionaryForKey((String *)keys->objectAtIndex(i));
\r
2955 if (kwd_inf == NULL)
\r
2961 sprintf_s(tmp, "%d", i);
\r
2962 contents += "<li><a href=\"#keywords_";
\r
2964 contents += "\">";
\r
2965 contents += ((String *)keys->objectAtIndex(i))->cString();
\r
2966 contents += "</a></li>";
\r
2968 controls += "<form name=\"filter\" id=\"keywords_";
\r
2970 controls += "\" class=\"panel\" method=\"GET\" action=\"mod_keywords.cgi\" target=\"_self\">";
\r
2971 controls += "<input type=\"hidden\" name=\"keywords\" value=\"";
\r
2972 controls += ((String *)keys->objectAtIndex(i))->cString();
\r
2973 controls += "\">";
\r
2974 controls += "<fieldset>";
\r
2976 controls += "<div class=\"row\">";
\r
2977 controls += "<label>";
\r
2978 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2979 controls += " : </label>";
\r
2980 controls += "<span>";
\r
2981 controls += ((String *)keys->objectAtIndex(i))->cString();
\r
2982 controls += "</span>";
\r
2983 controls += "</div>";
\r
2985 controls += "<div class=\"row\">";
\r
2986 controls += "<label>";
\r
2987 controls += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
2988 controls += " : </label>";
\r
2989 controls += "<span>";
\r
2990 controls += "<select name=\"service_id\" size=\"1\">";
\r
2991 controls += "<option value=\"-\">----</option>";
\r
2993 String *service_id = kwd_inf->stringForKey(KEY_EPG_SERVICE_ID);
\r
2996 Array *stationInfos = Controller::stationInfos(Tuner::ISDB_T);
\r
2997 if (stationInfos != NULL)
\r
2999 stationInfos->addObjectsFromArray(Controller::stationInfos(Tuner::ISDB_S));
\r
3003 stationInfos = Controller::stationInfos(Tuner::ISDB_S);
\r
3005 for (uint i = 0; (stationInfos != NULL) && (i < stationInfos->count()); ++i)
\r
3007 Array *services = ((Dictionary *)stationInfos->objectAtIndex(i))->arrayForKey(KEY_SERVICES);
\r
3009 for (uint j = 0; (services != NULL) && (j < 1); ++j)
\r
3011 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
3014 if ((service->stringForKey(KEY_SERVICE_TYPE) != NULL) && service->stringForKey(KEY_SERVICE_TYPE)->isEqualToString("1"))
\r
3016 String *name = service->stringForKey(KEY_NAME);
\r
3017 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
3018 if ((name != NULL) && (sid != NULL))
\r
3020 if ((service_id != NULL) && (service_id->isEqualToString(sid)))
\r
3022 String *tmp = String::stringWithFormat("<option value=\"%s\" selected>%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
3023 controls += tmp->cString();
\r
3027 String *tmp = String::stringWithFormat("<option value=\"%s\">%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
3028 controls += tmp->cString();
\r
3035 controls += "</select>";
\r
3036 controls += "</span>";
\r
3037 controls += "</div>";
\r
3039 controls += "<div class=\"row\">";
\r
3040 controls += "<label>";
\r
3041 controls += LocalizedString(KEY_I18N_Start_Time, NULL)->cString();
\r
3042 controls += " : </label>";
\r
3043 controls += "<span>";
\r
3044 controls += "<select name=\"start_hour\" size=\"1\">";
\r
3045 controls += "<option value=\"-\">--</option>";
\r
3046 String *sh_str = kwd_inf->stringForKey(KEY_EPG_START);
\r
3047 for (int sh = 0; sh < 24; ++sh)
\r
3050 if ((sh_str != NULL) && (sh_str->length() == 5) && (sh_str->substringToIndex(2)->intValue() == sh))
\r
3052 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
3056 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
3058 controls += sh_buf;
\r
3060 controls += "</select>";
\r
3061 controls += "<select name=\"start_min\" size=\"1\">";
\r
3062 controls += "<option value=\"-\">--</option>";
\r
3063 for (int sm = 0; sm < 60; ++sm)
\r
3066 if ((sh_str != NULL) && (sh_str->length() == 5) && (sh_str->substringFromIndex(3)->intValue() == sm))
\r
3068 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
3072 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
3074 controls += sm_buf;
\r
3076 controls += "</select>";
\r
3077 controls += "</span>";
\r
3078 controls += "</div>";
\r
3080 controls += "</fieldset>";
\r
3082 controls += "<input type=\"submit\" class=\"whiteButton\" name=\"req_mod\" value=\"";
\r
3083 controls += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
3084 controls += "\">";
\r
3086 controls += "<input type=\"submit\" class=\"redButton\" name=\"req_del\" value=\"";
\r
3087 controls += LocalizedString(KEY_I18N_Delete, NULL)->cString();
\r
3088 // controls += "\">";
\r
3089 controls += "\" onclick='return confirm(\"To delete. Is it ok?\");'>";
\r
3091 controls += "</form>";
\r
3096 contents += "</ul>";
\r
3097 contents += controls;
\r
3099 controls = "<form id=\"dialogForm\" title=\"";
\r
3100 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3101 controls += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3102 controls += "\" class=\"dialog\" target=\"_self\" action=\"add_keywords.cgi\" method=\"GET\">";
\r
3103 controls += "<fieldset>";
\r
3104 controls += "<h1>";
\r
3105 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3106 controls += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3107 controls += "</h1>";
\r
3108 controls += "<a class=\"button leftButton\" type=\"cancel\">Cancel</a>";
\r
3109 controls += "<a class=\"button blueButton\" type=\"submit\">Submit</a>";
\r
3110 controls += "<label>Parm1:</label>";
\r
3111 controls += "<input type=\"text\" name=\"keywords\" value=\"";
\r
3112 // controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3113 controls += "\"/>";
\r
3114 controls += "</fieldset>";
\r
3115 controls += "<div class=\"spinner\"></div>";
\r
3116 controls += "</form>";
\r
3118 contents += controls;
\r
3123 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
3126 result = responseWithHTML(request, html);
\r
3138 HTTPResponse *Controller::responseForStatus(HTTPRequest *request, SOCKADDR_IN *client)
\r
3140 HTTPResponse *result = NULL;
\r
3141 if ((request != NULL) && (client != NULL))
\r
3143 String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");
\r
3144 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
3147 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Tuner_Status, NULL));
\r
3148 std::string contents;
\r
3149 std::string status;
\r
3150 contents += "<ul id=\"home\" title=\"";
\r
3151 contents += LocalizedString(KEY_I18N_Tuner_Status, NULL)->cString();
\r
3152 contents += "\" selected=\"true\">";
\r
3153 DebugLog2("_tunerCount = %d", _tunerCount);
\r
3154 for (int i = 0; i < _tunerCount; ++i)
\r
3157 sprintf_s(key, sizeof(key), "%03d", i);
\r
3159 if (isTunerInitialized(i))
\r
3161 contents += "<li>";
\r
3162 contents += "<a href=\"#tuner";
\r
3164 contents += "\">";
\r
3167 contents += _tuners[i]->name();
\r
3168 contents += "</a></li>";
\r
3171 status += "<div id=\"";
\r
3172 status += "tuner";
\r
3174 status += "\" title=\"";
\r
3175 status += _tuners[i]->name();
\r
3176 status += "\" class=\"panel\">";
\r
3178 status += "<h2>Status</h2>";
\r
3179 status += "<fieldset>";
\r
3182 status += "<div class=\"row\">";
\r
3183 status += "<label>Type</label>";
\r
3184 status += "<span>";
\r
3185 switch (_tuners[i]->type())
\r
3187 case Tuner::ISDB_S:
\r
3188 status += "ISDB-S";
\r
3190 case Tuner::ISDB_T:
\r
3191 status += "ISDB-T";
\r
3193 case Tuner::TYPE_NA:
\r
3198 status += "</span>";
\r
3199 status += "</div>";
\r
3202 status += "<div class=\"row\">";
\r
3203 status += "<label>LnbPower</label>";
\r
3204 status += "<span>";
\r
3205 switch (_tuners[i]->lnbPower())
\r
3207 case Tuner::LNB_POWER_11V:
\r
3210 case Tuner::LNB_POWER_15V:
\r
3213 case Tuner::LNB_POWER_OFF:
\r
3218 status += "</span>";
\r
3219 status += "</div>";
\r
3223 status += "<div class=\"row\">";
\r
3224 status += "<label>Channel</label>";
\r
3225 status += "<span>";
\r
3226 sprintf_s(tmpstr, sizeof(tmpstr), "%03d", _tuners[i]->channel());
\r
3228 status += "</span>";
\r
3229 status += "</div>";
\r
3231 // C/N[dB] AGC xxx/255
\r
3232 uint32_t cn100 = 0;
\r
3234 uint32_t maxAgc = 0;
\r
3235 _tuners[i]->getCnAgc(&cn100, &agc, &maxAgc);
\r
3237 sprintf_s(tmpstr, sizeof(tmpstr), "%d.%02d[dB]", cn100 / 100, cn100 % 100);
\r
3239 status += "<div class=\"row\">";
\r
3240 status += "<label>C/N</label>";
\r
3241 status += "<span>";
\r
3243 status += "</span>";
\r
3244 status += "</div>";
\r
3246 sprintf_s(tmpstr, sizeof(tmpstr), "%03d/%03d", agc, maxAgc);
\r
3248 status += "<div class=\"row\">";
\r
3249 status += "<label>AGC</label>";
\r
3250 status += "<span>";
\r
3252 status += "</span>";
\r
3253 status += "</div>";
\r
3255 status += "</fieldset>";
\r
3256 status += "</div>";
\r
3261 contents += "<li>";
\r
3262 contents += _tuners[i]->name();
\r
3263 contents += "[uninitialized]";
\r
3264 contents += "</li>";
\r
3267 contents += "</ul>";
\r
3268 contents += status;
\r
3269 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
3270 result = responseWithHTML(request, html);
\r
3274 DebugLog2("responseForStatus() html is null\n");
\r
3280 HTTPResponse *Controller::responseForRegistCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3282 DebugLog2("Controller::responseForRegistCGI()");
\r
3284 HTTPResponse *result = NULL;
\r
3287 Dictionary *cgi = request->parseAsCGI();
\r
3291 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/regist.cgi")))
\r
3294 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3295 if (params != NULL)
\r
3298 if (params->count() == 2)
\r
3301 String *service_id = NULL;
\r
3302 String *event_id = NULL;
\r
3304 for (uint i = 0; i < params->count(); ++i)
\r
3306 Dictionary *param = (Dictionary *)params->objectAtIndex(i);
\r
3307 String *value = param->stringForKey("service_id");
\r
3308 if ((value != NULL) && value->isMatch("^\\d+$"))
\r
3310 service_id = value;
\r
3312 value = param->stringForKey("event_id");
\r
3313 if ((value != NULL) && value->isMatch("^\\d+$"))
\r
3320 if ((service_id != NULL) && (event_id != NULL))
\r
3322 DebugLog2("valid request");
\r
3324 result = responseByResultAndReferer(request, reserve(service_id->intValue(), event_id->intValue()), URI_PROGRAMS_HTML);
\r
3329 else if (params->count() == 9)
\r
3332 String *service_id = NULL;
\r
3333 String *year = NULL;
\r
3334 String *month = NULL;
\r
3335 String *day = NULL;
\r
3336 String *start_hour = NULL;
\r
3337 String *start_min = NULL;
\r
3338 String *end_hour = NULL;
\r
3339 String *end_min = NULL;
\r
3340 String *repeat = NULL;
\r
3344 String **variable;
\r
3345 const char *regex;
\r
3349 {"service_id", &service_id, "^\\d+$"},
\r
3350 {"year", &year, "^\\d{4}$"},
\r
3351 {"month", &month, "^([1-9]|1[0-2])$"},
\r
3352 {"day", &day, "^([1-9]|[12][0-9]|3[01])$"},
\r
3353 {"start_hour", &start_hour, "^\\d{2}$"},
\r
3354 {"start_min", &start_min, "^\\d{2}$"},
\r
3355 {"end_hour", &end_hour, "^\\d{2}$"},
\r
3356 {"end_min", &end_min, "^\\d{2}$"},
\r
3357 {"repeat", &repeat, "^(off|everyday|weekly|weekday)$"},
\r
3358 {NULL, NULL, NULL}
\r
3361 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
3363 for (uint j = 0; j < params->count(); ++j)
\r
3365 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
3366 String *value = param->stringForKey(cgi[i].name);
\r
3367 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
3369 *(cgi[i].variable) = value;
\r
3376 if ((service_id != NULL) && (year != NULL) && (month != NULL) && (day != NULL) &&
\r
3377 (start_hour != NULL) && (start_min != NULL) && (end_hour != NULL) && (end_min != NULL) && (repeat != NULL))
\r
3380 DebugLog1("valid param");
\r
3382 Dictionary *epg = Dictionary::dictionaryWithCapacity(0);
\r
3385 epg->setString(String::stringWithFormat("%s/%02d/%02d", year->cString(), month->intValue(), day->intValue()), KEY_EPG_DATE);
\r
3388 epg->setString(String::stringWithFormat("%s:%s:00", start_hour->cString(), start_min->cString()), KEY_EPG_START);
\r
3391 epg->setString(String::stringWithFormat("%s:%s:00", end_hour->cString(), end_min->cString()), KEY_EPG_END);
\r
3394 epg->setString(repeat, KEY_EPG_REPEAT);
\r
3397 epg->setString(service_id, KEY_EPG_SERVICE_ID);
\r
3400 epg->setString("ready", KEY_EPG_STATUS);
\r
3402 result = responseByResultAndReferer(request, reserve(epg), URI_RESERVATION_HTML);
\r
3412 HTTPResponse *Controller::responseForCancelCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3414 DebugLog2("Controller::responseForCancelCGI()");
\r
3416 HTTPResponse *result = NULL;
\r
3419 Dictionary *cgi = request->parseAsCGI();
\r
3423 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/cancel.cgi")))
\r
3426 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3427 if (params != NULL)
\r
3430 if (params->count() == 1)
\r
3432 Dictionary *param = (Dictionary *)params->objectAtIndex(0);
\r
3433 String *value = param->stringForKey("resv_id");
\r
3434 if ((value != NULL) && value->isMatch("^\\d{6}$"))
\r
3436 result = responseByResultAndReferer(request, cancel(-1, value->intValue()), URI_RESERVATION_HTML);
\r
3445 HTTPResponse *Controller::responseForAddKeywordsCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3447 DebugLog2("Controller::responseForAddKeywordsCGI()");
\r
3449 HTTPResponse *result = NULL;
\r
3452 Dictionary *cgi = request->parseAsCGI();
\r
3456 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/add_keywords.cgi")))
\r
3459 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3460 if (params != NULL)
\r
3463 if (params->count() == 1)
\r
3465 Dictionary *param = (Dictionary *)params->objectAtIndex(0);
\r
3466 String *value = param->stringForKey("keywords");
\r
3467 if (value != NULL)
\r
3469 value = value->stringByReplacingOccurrencesOfString("+", " ");
\r
3470 if (value != NULL)
\r
3472 value = value->stringByRemovingPercentEncoding();
\r
3475 if (value != NULL)
\r
3480 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3481 if (keywords_info == NULL)
\r
3483 keywords_info = Dictionary::dictionaryWithCapacity(0);
\r
3484 _reservations->setObject(keywords_info, KEY_EPG_KEYWORDS);
\r
3487 if (keywords_info->dictionaryForKey(value) == NULL)
\r
3490 keywords_info->setObject(Dictionary::dictionaryWithCapacity(0), value);
\r
3493 updateKeywordsReservation();
\r
3499 _reservations->writeToFile(_reservations_path, true);
\r
3504 result = responseForReloadURI(request, client, "/reservation.html#_keywords");
\r
3513 HTTPResponse *Controller::responseForModKeywordsCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3515 DebugLog2("Controller::responseForModKeywordsCGI()");
\r
3517 HTTPResponse *result = NULL;
\r
3520 Dictionary *cgi = request->parseAsCGI();
\r
3523 DebugLog3("cgi != NULL");
\r
3526 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/mod_keywords.cgi")))
\r
3528 DebugLog3("CGI path OK.");
\r
3531 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3532 if (params != NULL)
\r
3534 DebugLog3("params != NULL");
\r
3537 String *keywords = NULL;
\r
3538 String *service_id = NULL;
\r
3539 String *start_hour = NULL;
\r
3540 String *start_min = NULL;
\r
3541 String *req_mod = NULL;
\r
3542 String *req_del = NULL;
\r
3546 String **variable;
\r
3547 const char *regex;
\r
3551 {"keywords", &keywords, ".*"},
\r
3552 {"service_id", &service_id, "^(\\d+|-)$"},
\r
3553 {"start_hour", &start_hour, "^(\\d{2}|-)$"},
\r
3554 {"start_min", &start_min, "^(\\d{2}|-)$"},
\r
3555 {"req_mod", &req_mod, ".*"},
\r
3556 {"req_del", &req_del, ".*"},
\r
3557 {NULL, NULL, NULL}
\r
3560 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
3562 for (uint j = 0; j < params->count(); ++j)
\r
3564 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
3565 String *value = param->stringForKey(cgi[i].name);
\r
3566 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
3568 *(cgi[i].variable) = value;
\r
3574 if (keywords != NULL)
\r
3576 keywords = keywords->stringByReplacingOccurrencesOfString("+", " ");
\r
3577 if (keywords != NULL)
\r
3579 keywords = keywords->stringByRemovingPercentEncoding();
\r
3583 if ((keywords != NULL) && (service_id != NULL) && (start_hour != NULL) && (start_min != NULL) &&
\r
3584 ((req_mod != NULL) && (req_del == NULL)) || ((req_mod == NULL) && (req_del != NULL)))
\r
3590 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3591 if (keywords_info != NULL)
\r
3593 if (req_mod != NULL)
\r
3595 DebugLog0("keywords: %s", keywords->cString());
\r
3596 DebugLog0("service_id: %s", service_id->cString());
\r
3597 DebugLog0("start_hour: %s", start_hour->cString());
\r
3598 DebugLog0("start_min: %s", start_min->cString());
\r
3599 Dictionary *kwd_inf = keywords_info->dictionaryForKey(keywords);
\r
3600 if (kwd_inf != NULL)
\r
3602 if (!service_id->isEqualToString("-"))
\r
3604 kwd_inf->setString(service_id, KEY_EPG_SERVICE_ID);
\r
3608 kwd_inf->removeObjectForKey(KEY_EPG_SERVICE_ID);
\r
3610 if (!start_hour->isEqualToString("-") && !start_min->isEqualToString("-"))
\r
3612 kwd_inf->setString(String::stringWithFormat("%s:%s", start_hour->cString(), start_min->cString()), KEY_EPG_START);
\r
3616 kwd_inf->removeObjectForKey(KEY_EPG_START);
\r
3620 else if (req_del != NULL)
\r
3622 DebugLog0("keywords: %s", keywords->cString());
\r
3623 keywords_info->removeObjectForKey(keywords);
\r
3627 updateKeywordsReservation();
\r
3633 _reservations->writeToFile(_reservations_path, true);
\r
3639 result = responseForReloadURI(request, client, "/reservation.html#_keywords");
\r
3647 HTTPResponse *Controller::responseForReloadURI(NET::HTTPRequest *request, SOCKADDR_IN *client, const char *uri, int sec)
\r
3649 HTTPResponse *result = NULL;
\r
3653 std::string contents;
\r
3654 contents = "<html>";
\r
3655 contents += "<head>";
\r
3657 contents += "<meta http-equiv=\"refresh\" content=\"0;URL=";
\r
3659 contents += "<meta http-equiv=\"refresh\" content=\"";
\r
3661 contents += ";URL=";
\r
3664 contents += "\">";
\r
3665 contents += "</head>";
\r
3666 contents += "</html>";
\r
3667 String *html = String::stringWithUTF8String(contents.c_str());
\r
3670 result = responseWithHTML(request, html);
\r
3677 HTTPResponse *Controller::responseForPlaylist(HTTPRequest *request, SOCKADDR_IN *client)
\r
3679 HTTPResponse *result = NULL;
\r
3680 // http://bit.ly/iptv_feb2015
\r
3686 #EXTINF:-1, [COLOR yellow]Updated 15/04/2015 @ 03:45 [/COLOR]
\r
3687 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3688 #EXTINF:-1, [COLOR green] --Uk Live Tv--[/COLOR]
\r
3689 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3690 #EXTINF:-1, [COLOR green] --Free Collection of IPTV sports links--[/COLOR]
\r
3691 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3692 #EXTINF:-1, [COLOR red] --Links will go down. Please note that it will take time to update--[/COLOR]
\r
3693 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3694 #EXTINF:-1, [COLOR red] --Please contact me at the husham.com website--[/COLOR]
\r
3695 plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM
\r
3697 #EXTINF:-1, Sky sports news
\r
3698 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
3699 #EXTINF:-1,Bt sports 1
\r
3700 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
3705 std::string contents;
\r
3706 contents = "#EXTM3U\r\n";
\r
3707 contents += "\r\n";
\r
3709 Dictionary *tuner_channel_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
3710 if (tuner_channel_to_udp != NULL)
\r
3712 Tuner::Type types[] = {Tuner::ISDB_T, Tuner::ISDB_S};
\r
3713 for (int t = 0; t < sizeof(types) / sizeof(Tuner::Type); ++t)
\r
3715 for (int i = 0; i < _tunerCount; ++i)
\r
3717 if (isTunerInitialized(i) && (_tuners[i]->type() == types[t]))
\r
3719 uint ch_max = ((types[t] == Tuner::ISDB_T) ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S);
\r
3720 for (uint ch = 0; ch <= ch_max; ++ch)
\r
3722 if (isChannelEnabled(i, ch))
\r
3724 char tuner_and_channel[10];
\r
3725 sprintf_s(tuner_and_channel, "%d,%d", i, ch);
\r
3726 char *chstr = strchr(tuner_and_channel, ',');
\r
3727 if (chstr != NULL)
\r
3732 String *udp_str = tuner_channel_to_udp->stringForKey(tuner_and_channel);
\r
3733 if (udp_str != NULL)
\r
3735 contents += "#EXTINF:-1 tvg-id=\"";
\r
3736 contents += tuner_and_channel;
\r
3737 contents += "\" tvg-logo=\"";
\r
3738 contents += ((types[t] == Tuner::ISDB_T) ? "t_" : "s_");
\r
3739 if (chstr != NULL)
\r
3741 contents += chstr;
\r
3745 contents += "ffff";
\r
3747 contents += "\" group-title=\"";
\r
3748 contents += _tuners[i]->name();
\r
3749 contents += "\", ";
\r
3750 String *station_name = stationName(types[t], ch);
\r
3751 if (station_name != NULL)
\r
3753 contents += station_name->cString();
\r
3757 contents += tuner_and_channel;
\r
3759 contents += "\r\n";
\r
3760 contents += "udp://0.0.0.0:";
\r
3761 contents += udp_str->cString();
\r
3762 contents += "\r\n";
\r
3772 String *text = String::stringWithUTF8String(contents.c_str());
\r
3775 result = responseWithUTF8Text(request, text);
\r
3782 * @brief HTTP Live Streaming制御
\r
3784 * http://hogehoge/チューナ番号/チャンネル番号/streaming[-プリセット名].m3u8 がリクエスト(プリセットはオプション)され、
\r
3785 * チューナ番号/チャンネル番号/プリセット名(ある場合)が有効値の場合にコールされる
\r
3787 * @param [in] request HTTPリクエスト
\r
3788 * @param [in] client リクエストしたクライアントのアドレス
\r
3789 * @param [in] tuner チューナ番号
\r
3790 * @param [in] channel チャンネル番号
\r
3791 * @param [in] preset プリセット(URLで省略された場合 "default" )
\r
3793 HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner, int channel, String *preset)
\r
3795 DebugLog0("Controller::responseForHLSControl()");
\r
3797 HTTPResponse *result = NULL;
\r
3799 // client からホスト名を取得
\r
3800 char hostname[NI_MAXHOST];
\r
3801 if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
\r
3804 DebugLog0("host: %s", hostname);
\r
3806 // ストリーミング制御情報からHLS情報を取得
\r
3807 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
3808 if (hls_info == NULL)
\r
3810 DebugLog0("hls_info == NULL");
\r
3811 hls_info = Dictionary::dictionaryWithCapacity(0);
\r
3812 _streaming_ctrls->setObject(hls_info, KEY_HLS_INFO);
\r
3815 // HLS情報から指定チューナの情報を取得
\r
3816 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[tuner]->name());
\r
3817 if (hls_info_tuner == NULL)
\r
3819 DebugLog0("hls_info_tuner == NULL");
\r
3820 hls_info_tuner = Dictionary::dictionaryWithCapacity(0);
\r
3821 hls_info->setObject(hls_info_tuner, _tuners[tuner]->name());
\r
3824 // 指定チューナの情報からホスト名を確認
\r
3825 if ((hls_info_tuner->stringForKey(KEY_HOSTNAME) == NULL) || hls_info_tuner->stringForKey(KEY_HOSTNAME)->isEqualToString(hostname))
\r
3827 DebugLog0("new host or reconnect");
\r
3829 hls_info_tuner->setString(hostname, KEY_HOSTNAME);
\r
3832 HTTPLiveStreaming *hls = (HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE);
\r
3835 DebugLog0("hls == NULL");
\r
3837 hls = HTTPLiveStreaming::alloc()->init()->autorelease();
\r
3838 hls_info_tuner->setObject(hls, KEY_HLS_INSTANCE);
\r
3841 // 異チャンネルへのリクエスト、または、プリセット変更の場合
\r
3842 if (((hls_info_tuner->integerForKey(KEY_CHANNEL) != 0) && (hls_info_tuner->integerForKey(KEY_CHANNEL) != channel)) ||
\r
3843 ((hls_info_tuner->stringForKey(KEY_PRESET) != NULL) && !hls_info_tuner->stringForKey(KEY_PRESET)->isEqualToString(preset)))
\r
3845 DebugLog0("hls->stop()");
\r
3850 // チャンネルとプリセットは一旦削除
\r
3851 hls_info_tuner->removeObjectForKey(KEY_CHANNEL);
\r
3852 hls_info_tuner->removeObjectForKey(KEY_PRESET);
\r
3855 DebugLog0("start ?");
\r
3857 // 初回リクエスト or チャンネル/プリセット変更 か?
\r
3858 if ((hls_info_tuner->integerForKey(KEY_CHANNEL) == 0) && (hls_info_tuner->stringForKey(KEY_PRESET) == NULL))
\r
3860 DebugLog0("start or restart");
\r
3863 Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
3864 if (mapping != NULL)
\r
3866 Array *ports = mapping->allKeys();
\r
3867 if (ports != NULL)
\r
3869 char tuner_and_channel[10];
\r
3870 sprintf_s(tuner_and_channel, "%d,%d", tuner, channel);
\r
3872 for (uint i = 0; i < ports->count(); ++i)
\r
3874 String *port = (String *)ports->objectAtIndex(i);
\r
3875 String *tmp = mapping->stringForKey(port);
\r
3876 if (tmp->isEqualToString(tuner_and_channel))
\r
3878 DebugLog0("udp mapping %d -> %d,%d", port->intValue(), tuner, channel);
\r
3881 hls->setSource(String::stringWithFormat("udp://@:%d", port->intValue()));
\r
3884 // hls->setTranscode(_props->dictionaryForKey(KEY_PRESETS)->dictionaryForKey(preset));
\r
3887 hls->setOutputPath(_props->stringForKey(KEY_CACHE_PATH));
\r
3890 hls->setIndexName(String::stringWithFormat("live_%03d_%03d", tuner, channel));
\r
3895 DebugLog0("hls->start() success");
\r
3898 hls_info_tuner->setInteger(0, KEY_CHANNEL);
\r
3901 hls_info_tuner->setString(preset, KEY_PRESET);
\r
3912 String *index_path = hls->indexPath();
\r
3913 FileManager *fm = FileManager::defaultManager();
\r
3914 bool isDirectory = false;
\r
3915 if (fm->fileExistsAtPath(index_path, &isDirectory))
\r
3919 DebugLog0("file exists");
\r
3920 result = _httpd->responseWithPath(index_path, request);
\r
3923 if (result == NULL)
\r
3925 DebugLog0("file no exists");
\r
3926 result = responseForReloadURI(request, client, request->URI()->cString(), 10);
\r
3929 // result = responseForFailed(request);
\r
3940 HTTPResponse *Controller::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner)
\r
3942 DebugLog0("%s\n", __FUNCTION__);
\r
3944 HTTPResponse *result = NULL;
\r
3950 String *uri = request->URI();
\r
3951 while (uri != NULL)
\r
3954 Dictionary *cgi = request->parseAsCGI();
\r
3957 uri = cgi->stringForKey(HTTPRequest::KEY_CGI);
\r
3967 if (uri->isMatch("^/[0-9]{3}/info.xml$") && (cgi == NULL))
\r
3973 // /ttt/channel=nnn
\r
3975 else if (uri->isMatch("^/[0-9]{3}/channel=[0-9]{1,3}$") && (cgi == NULL))
\r
3977 DebugLog0("ch set");
\r
3978 String *ch = uri->substringFromIndex(13);
\r
3983 int channel = ch->intValue();
\r
3984 DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
\r
3985 DebugLog2("set channel:%d(%s)\n", channel, ch->cString());
\r
3986 if (setChannel(tuner, channel))
\r
3989 DebugLog2("success.\n");
\r
3990 result = responseForSuccess(request);
\r
3995 DebugLog2("failed.\n");
\r
3996 result = responseForFailed(request);
\r
4001 // 録画開始(最大23:59まで)
\r
4002 // /ttt/recording=on?hour=hh&min=mm[&channel=nnn]
\r
4004 else if (uri->isMatch("^/[0-9]{3}/recording=on$") && (cgi != NULL))
\r
4007 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4008 if (params == NULL)
\r
4014 if ((params->count() != 2) && (params->count() != 3))
\r
4020 String *p_hour = NULL;
\r
4021 String *p_min = NULL;
\r
4022 String *p_channel = NULL;
\r
4026 String **variable;
\r
4027 const char *regex;
\r
4031 {"hour", &p_hour, "^[0-2][0-9]$"},
\r
4032 {"min", &p_min, "^[0-5][0-9]$"},
\r
4033 {"channel", &p_channel, "^[0-9]{3}$"},
\r
4034 {NULL, NULL, NULL}
\r
4037 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4039 *(cgi[i].variable) = NULL;
\r
4040 for (uint j = 0; j < params->count(); ++j)
\r
4042 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4043 String *value = param->stringForKey(cgi[i].name);
\r
4044 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4046 *(cgi[i].variable) = value;
\r
4052 if ((p_hour == NULL) || (p_min == NULL))
\r
4059 if (p_channel != NULL)
\r
4061 channel = p_channel->intValue();
\r
4065 channel = _tuners[tuner]->channel();
\r
4071 int hour = p_hour->intValue();
\r
4072 int min = p_min->intValue();
\r
4076 Dictionary *epg = Dictionary::dictionaryWithCapacity(0);
\r
4081 now += 1; // margin
\r
4083 if (localtime_s(&tm, &now) != 0)
\r
4090 end.tm_hour += hour;
\r
4091 end.tm_min += min;
\r
4092 end.tm_sec += 1; // margin
\r
4093 if (mktime(&end) == -1)
\r
4102 sprintf_s(tmp, sizeof(tmp), "%04d/%02d/%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
\r
4103 epg->setString(tmp, KEY_EPG_DATE);
\r
4106 sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
\r
4107 epg->setString(tmp, KEY_EPG_START);
\r
4110 sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", end.tm_hour, end.tm_min, end.tm_sec);
\r
4111 epg->setString(tmp, KEY_EPG_END);
\r
4114 sprintf_s(tmp, sizeof(tmp), "%d", channel);
\r
4115 epg->setString(tmp, KEY_EPG_CHANNEL);
\r
4118 epg->setString("off", KEY_EPG_REPEAT);
\r
4121 epg->setString("ready", KEY_EPG_STATUS);
\r
4129 result = responseByResultAndReferer(request, reserve(tuner, epg), URI_RESERVATION_HTML);
\r
4137 // /ttt/recording=off
\r
4139 else if (uri->isMatch("^/[0-9]{3}/recording=off$") && (cgi == NULL))
\r
4142 DebugLog2("recording off: %s\n", uri->cString());
\r
4143 if (cancel(tuner, -1))
\r
4146 DebugLog2("success.\n");
\r
4147 result = responseForSuccess(request);
\r
4152 DebugLog2("failed.\n");
\r
4153 result = responseForFailed(request);
\r
4159 // /ttt/streaming=on?udp=nnnnn(&host=aaaaaa)
\r
4161 else if (uri->isMatch("^/[0-9]{3}/streaming=on$") && (cgi != NULL))
\r
4164 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4165 if (params == NULL)
\r
4171 if ((params->count() != 1) && (params->count() != 2))
\r
4177 String *p_udp = NULL;
\r
4178 String *p_host = NULL;
\r
4182 String **variable;
\r
4183 const char *regex;
\r
4187 {"udp", &p_udp, "^[0-9]{1,5}$"},
\r
4188 {"host", &p_host, "^.+$"},
\r
4189 {NULL, NULL, NULL}
\r
4192 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4194 *(cgi[i].variable) = NULL;
\r
4195 for (uint j = 0; j < params->count(); ++j)
\r
4197 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4198 String *value = param->stringForKey(cgi[i].name);
\r
4199 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4201 *(cgi[i].variable) = value;
\r
4207 if (p_udp == NULL)
\r
4212 SOCKADDR_IN dst_addr;
\r
4214 if (p_host != NULL)
\r
4217 std::string host = udpstr.substr(idx + 5);
\r
4218 udpstr = udpstr.substr(0, idx - 1);
\r
4219 DebugLog2("udp: %s\n", udpstr.c_str());
\r
4220 DebugLog2("host: %s\n", host.c_str());
\r
4221 struct hostent *ent = gethostbyname(host.c_str());
\r
4226 memcpy(&dst_addr, client, sizeof(SOCKADDR_IN));
\r
4228 dst_addr.sin_port = htons(p_udp->intValue());
\r
4230 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
4233 DebugLog2("success.\n");
\r
4234 result = responseForSuccess(request);
\r
4239 DebugLog2("failed.\n");
\r
4240 result = responseForFailed(request);
\r
4246 // /ttt/streaming=off(?host=aaaa)
\r
4248 else if (uri->isMatch("^/[0-9]{3}/streaming=off$"))
\r
4251 String *p_host = NULL;
\r
4256 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4257 if (params == NULL)
\r
4263 if ((params->count() != 0) && (params->count() != 1))
\r
4270 String **variable;
\r
4271 const char *regex;
\r
4275 {"host", &p_host, "^.+$"},
\r
4276 {NULL, NULL, NULL}
\r
4279 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4281 *(cgi[i].variable) = NULL;
\r
4282 for (uint j = 0; j < params->count(); ++j)
\r
4284 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4285 String *value = param->stringForKey(cgi[i].name);
\r
4286 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4288 *(cgi[i].variable) = value;
\r
4294 SOCKADDR_IN dst_addr;
\r
4295 if (p_host != NULL)
\r
4302 _tuners[tuner]->stopStreaming();
\r
4305 DebugLog2("success.\n");
\r
4306 result = responseForSuccess(request);
\r
4312 else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming(-[^\\.]+)?.m3u8$") && (cgi == NULL))
\r
4314 DebugLog0("uri: %s", uri->cString());
\r
4316 // URIからチャンネル番号を抽出
\r
4318 int ch = uri->substringFromIndex(5)->substringToIndex(3)->intValue();
\r
4319 DebugLog0("ch: %d", ch);
\r
4321 // presetが指定されている場合、presetを抽出
\r
4322 String *preset = NULL;
\r
4323 if (uri->isMatch("streaming-"))
\r
4325 preset = uri->substringFromIndex(19);
\r
4326 preset = preset->substringToIndex(preset->length() - 5);
\r
4327 DebugLog0("opt: preset: %s", preset->cString());
\r
4332 preset = String::stringWithUTF8String(KEY_DEFAULT);
\r
4335 // チャンネル/presetが有効か確認
\r
4336 if (isChannelEnabled(tuner, ch) &&
\r
4337 (_props->dictionaryForKey(KEY_PRESETS) != NULL) &&
\r
4338 (_props->dictionaryForKey(KEY_PRESETS)->objectForKey(preset) != NULL))
\r
4341 result = responseForHLSControl(request, client, tuner, ch, preset);
\r
4345 result = responseForFailed(request);
\r
4347 DebugLog0("hls req. done");
\r
4349 else if (uri->isMatch("^/[0-9]{3}/[0-9]{3}/streaming-[0-9]+.ts$") && (cgi == NULL))
\r
4352 DebugLog0("uri: %s", uri->cString());
\r
4364 HTTPResponse *Controller::request(HTTPRequest *request, SOCKADDR_IN *client)
\r
4366 DebugLog2("%s\n", __FUNCTION__);
\r
4369 bool flag = false;
\r
4371 flag = _initialized;
\r
4378 HTTPResponse *response = NULL;
\r
4380 if (request->method()->isEqualToString("GET") ||
\r
4381 request->method()->isEqualToString("HEAD"))
\r
4384 String *uri = request->URI();
\r
4385 DebugLog0("request: %s\n", uri->cString());
\r
4390 if (uri->isMatch("^(/|/index\\.(htm|html))$"))
\r
4392 response = responseForMain(request, client);
\r
4395 else if (uri->isMatch("^/status.html$"))
\r
4397 response = responseForStatus(request, client);
\r
4401 else if (uri->isMatch("^/info.xml$"))
\r
4404 else if (uri->isMatch("^/video.xml$"))
\r
4409 else if (uri->isMatch("^/suspend.xml$"))
\r
4413 // response = responseForSuccess(request);
\r
4414 // delaySuspend();
\r
4418 // response = responseForFailed(request);
\r
4423 else if (uri->isMatch("^/exec_vlc.html$"))
\r
4425 // _vlc->execute();
\r
4426 // return responseForRefreshMain(request, client);
\r
4432 else if (uri->isMatch("^/[0-9]{3}/"))
\r
4434 DebugLog0("tuner control");
\r
4435 // String::substringWithRange() を実装するのを後回しにするので。。
\r
4436 std::string s = uri->cString();
\r
4437 int tuner = atoi(s.substr(1, 3).c_str());
\r
4438 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4440 response = requestTunerControl(request, client, tuner);
\r
4441 DebugLog0("tuner control done");
\r
4446 // reservation control
\r
4448 else if (uri->isMatch("^/reservation.html$"))
\r
4450 response = responseForReservation(request, client);
\r
4452 else if (uri->isMatch("^/regist.cgi"))
\r
4454 response = responseForRegistCGI(request, client);
\r
4456 else if (uri->isMatch("^/cancel.cgi"))
\r
4458 response = responseForCancelCGI(request, client);
\r
4460 else if (uri->isMatch("^/add_keywords.cgi"))
\r
4462 response = responseForAddKeywordsCGI(request, client);
\r
4464 else if (uri->isMatch("^/mod_keywords.cgi"))
\r
4466 response = responseForModKeywordsCGI(request, client);
\r
4468 else if (uri->isMatch("^/reservation.xml$"))
\r
4471 else if (uri->isMatch("^/[0-9]{6}/"))
\r
4473 // DebugLog2("reservation: %s\n", uri.c_str());
\r
4479 else if (uri->isMatch("^/[0-9]{9}/"))
\r
4481 // DebugLog2("video: %s\n", uri.c_str());
\r
4487 // else if (match(uri.c_str(), "^/programs.html$"))
\r
4488 else if (uri->isMatch("^/" URI_PROGRAMS_HTML "$"))
\r
4490 response = responseForPrograms(request, client);
\r
4492 else if (uri->isMatch("^/programs.xml$"))
\r
4495 // return responseWithDictionary(request, _programs);
\r
4500 else if (uri->isMatch("^/tv.html$"))
\r
4502 // return responseForTV(request, client);
\r
4506 else if (uri->isMatch("^/iptv.m3u8$"))
\r
4508 return responseForPlaylist(request, client);
\r
4512 else if (uri->isMatch("^/iptd.log$"))
\r
4514 String *path = _system_path->stringByAppendingPathComponent("log");
\r
4517 path = path->stringByAppendingPathComponent("iptd.log");
\r
4520 response = _httpd->responseWithPath(path, request);
\r
4521 if (response != NULL)
\r
4523 if (response->message() != NULL)
\r
4525 if (response->message()->header() != NULL)
\r
4527 response->message()->header()->setFieldBodyWithName("text/plane; charset=UTF-8", "Content-Type");
\r
4535 else if (request->method()->isEqualToString("POST"))
\r
4538 String *uri = request->URI();
\r
4539 DebugLog1("POST: %s\n", uri->cString());
\r
4540 InternetTextMessage *message = request->message();
\r
4541 if (message != NULL)
\r
4543 DebugLog3("message: ");
\r
4544 InternetTextMessageHeader *header = message->header();
\r
4545 if (header != NULL)
\r
4547 DebugLog3("header: ");
\r
4549 InternetTextMessageBody *body = message->body();
\r
4552 DebugLog3("body: ");
\r
4562 #pragma mark ------- プロパティ取得 -------
\r
4565 bool Controller::isTunerInitialized(int tuner)
\r
4567 DebugLog2("Controller::isTunerInitialized()");
\r
4569 bool result = false;
\r
4571 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4576 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4577 if (tunersInfo != NULL)
\r
4579 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
4580 if (tunerInfo != NULL)
\r
4582 result = tunerInfo->boolForKey(KEY_INITIALIZED);
\r
4593 bool Controller::isTunerEnabled(int tuner)
\r
4595 DebugLog2("Controller::isTunerEnabled()");
\r
4597 bool result = false;
\r
4599 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4604 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4605 if (tunersInfo != NULL)
\r
4607 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
4608 if (tunerInfo != NULL)
\r
4610 result = tunerInfo->boolForKey(KEY_ENABLED);
\r
4621 bool Controller::isChannelEnabled(int tuner, int channel)
\r
4623 DebugLog2("Controller::isChannelEnabled()");
\r
4625 bool result = false;
\r
4627 if ((0 <= tuner) && (tuner < _tunerCount) && (0 <= channel) && (channel <= Tuner::MAX_CHANNELS_ISDB_T))
\r
4632 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4633 if (tunersInfo != NULL)
\r
4635 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
4636 if (tunerInfo != NULL)
\r
4638 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4639 if (channels != NULL)
\r
4642 sprintf_s(key, "%03d", channel);
\r
4643 Dictionary *chInfo = channels->dictionaryForKey(key);
\r
4644 if (chInfo != NULL)
\r
4646 result = chInfo->boolForKey(KEY_ENABLED);
\r
4659 Array *Controller::stationInfos(Tuner::Type type)
\r
4661 DebugLog2("Controller::stationInfosForISDB_T()");
\r
4663 Array *result = Array::arrayWithCapacity(0);
\r
4668 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4669 if (tunersInfo != NULL)
\r
4671 for (int i = 0; i < _tunerCount; ++i)
\r
4673 if (_tuners[i]->type() == type)
\r
4675 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[i]->name());
\r
4676 if (tunerInfo != NULL)
\r
4678 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4679 if (channels != NULL)
\r
4681 for (uint ch = 0; ch <= (type == Tuner::ISDB_T ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S); ++ch)
\r
4684 sprintf_s(chkey, "%03d", ch);
\r
4685 Dictionary *channel = channels->dictionaryForKey(chkey);
\r
4686 if ((channel != NULL) && channel->boolForKey(KEY_ENABLED))
\r
4688 result->addObject(channel);
\r
4704 String *Controller::stationName(Tuner::Type type, int channel)
\r
4706 DebugLog2("Controller::stationName()");
\r
4708 String *result = NULL;
\r
4713 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4714 if (tunersInfo != NULL)
\r
4716 for (int i = 0; i < _tunerCount; ++i)
\r
4718 if (_tuners[i]->type() == type)
\r
4720 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[i]->name());
\r
4721 if (tunerInfo != NULL)
\r
4723 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4724 if (channels != NULL)
\r
4727 sprintf_s(chkey, "%03d", channel);
\r
4728 Dictionary *channel = channels->dictionaryForKey(chkey);
\r
4729 if ((channel != NULL) && channel->boolForKey(KEY_ENABLED))
\r
4731 result = channel->stringForKey(KEY_NAME);
\r
4746 // epgの開始時刻でソートする為の比較関数
\r
4747 Integer compareFunction(Object *obj1, Object *obj2, void *context)
\r
4749 if (isKindOfClass(Dictionary, obj1) && isKindOfClass(Dictionary, obj2))
\r
4753 Controller::getTimeWithEPG((Dictionary *)obj1, &st1, &ed1);
\r
4757 Controller::getTimeWithEPG((Dictionary *)obj2, &st2, &ed2);
\r
4761 return OrderedAscending;
\r
4763 else if (st1 > st2)
\r
4765 return OrderedDescending;
\r
4771 return OrderedAscending;
\r
4773 else if (ed1 > ed2)
\r
4775 return OrderedDescending;
\r
4779 return OrderedSame;
\r
4782 Array *Controller::programsForServices(Array *services)
\r
4784 DebugLog2("Controller::programsForServices()");
\r
4786 Array *result = Array::arrayWithCapacity(0);
\r
4791 for (uint i = 0; i < services->count(); ++i)
\r
4793 Dictionary *service = (Dictionary *)services->objectAtIndex(i);
\r
4794 Dictionary *events = _epgs->dictionaryForKey(service->stringForKey(KEY_SERVICE_ID));
\r
4795 if (events != NULL)
\r
4797 Array *keys = events->allKeys();
\r
4798 for (uint j = 0; j < keys->count(); ++j)
\r
4800 result->addObject(events->objectForKey((String *)keys->objectAtIndex(j)));
\r
4806 result = result->sortedArrayUsingFunction(compareFunction, this);
\r
4815 String *Controller::stationNameForServiceID(String *service_id)
\r
4817 DebugLog2("Controller::stationNameForServiceID()");
\r
4819 String *result = NULL;
\r
4821 if (service_id != NULL)
\r
4826 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
4827 if (tunersInfo != NULL)
\r
4829 Array *tuners_key = tunersInfo->allKeys();
\r
4831 for (uint i = 0; (result == NULL) && (i < tuners_key->count()); ++i)
\r
4833 Dictionary *tunerInfo = tunersInfo->dictionaryForKey((String *)tuners_key->objectAtIndex(i));
\r
4834 if (tunerInfo != NULL)
\r
4836 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
4837 if (channels != NULL)
\r
4839 Array *chkey = channels->allKeys();
\r
4840 for (uint ch = 0; (result == NULL) && (ch < chkey->count()); ++ch)
\r
4842 Dictionary *channel = channels->dictionaryForKey((String *)chkey->objectAtIndex(ch));
\r
4843 if (channel != NULL)
\r
4845 Array *services = channel->arrayForKey(KEY_SERVICES);
\r
4846 if (services != NULL)
\r
4848 for (uint j = 0; j < services->count(); ++j)
\r
4850 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
4851 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
4854 if (sid->isEqualToString(service_id))
\r
4856 result = service->stringForKey(KEY_NAME);
\r
4878 #pragma mark ------- タイマディスパッチャ -------
\r
4881 void Controller::timerExpired(Timer *timer, void *userInfo)
\r
4883 DebugLog2("Controller::timerExpired()");
\r
4887 switch ((long long)userInfo)
\r
4890 if (restart() > 0)
\r
4893 DebugLog2("tuner initialize success.");
\r
4895 // EPG収集用タイマ起動(ISDB-S)
\r
4896 _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);
\r
4897 if (_timer_epg_s != NULL)
\r
4899 _timer_epg_s->fire();
\r
4902 // EPG収集用タイマ起動(ISDB-T)
\r
4903 _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);
\r
4904 if (_timer_epg_t != NULL)
\r
4906 _timer_epg_t->fire();
\r
4912 DebugLog0("tuner initialize failed.");
\r
4923 case CMD_PERIODIC: // 周期処理
\r
4927 case CMD_PERIODIC_2: // 周期処理2
\r
4931 case CMD_COLLECT_EPG_ISDB_S: // EPG収集(ISDB-S)
\r
4933 if (collectEPGs(Tuner::ISDB_S))
\r
4936 _timer_epg_s->setRepeats(false);
\r
4941 _timer_epg_s->setTimeInterval(DEF_COLLECT_EPG_RETRY);
\r
4945 case CMD_COLLECT_EPG_ISDB_T: // 番組情報収集(ISDB-T)
\r
4946 if (collectEPGs(Tuner::ISDB_T))
\r
4949 _timer_epg_t->setRepeats(false);
\r
4954 _timer_epg_t->setTimeInterval(DEF_COLLECT_EPG_RETRY);
\r
4962 #pragma mark ------- 起動/停止関連 -------
\r
4965 // システム状態をチェックしてサスペンド可能かを返す
\r
4966 bool Controller::canSuspend()
\r
4968 return isIdleState(true);
\r
4971 bool Controller::canTerminate()
\r
4973 return isIdleState(false);
\r
4976 bool Controller::isIdleState(bool suspend)
\r
4978 DebugLog2("Controller::isIdleState() start.");
\r
4980 bool result = false;
\r
4986 while (_initialized)
\r
4988 // EPG(ISDB-S)収集中か
\r
4989 if (suspend && (_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
4995 // EPG(ISDB-T)収集中か
\r
4996 if (suspend && (_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5006 // 10分後以内に開始の予約があったらサスペンド不可
\r
5009 time_t now = time(NULL);
\r
5011 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
5013 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
5014 if ((array == NULL) || (array->count() == 0))
\r
5021 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
5024 getTimeWithEPG(epg, &start, &end);
\r
5026 if (start + OFFSET_OF_SUPPRESSION_TIME <= now)
\r
5040 DebugLog2("Controller::isIdleState() end.");
\r
5046 * TrayApp::WndProc() からコールされる
\r
5048 * スレッドコンテキスト:メインスレッド
\r
5050 void Controller::systemWillSuspend()
\r
5052 DebugLog2("Controller::systemWillSuspend() start");
\r
5055 _cancel_epg_collect = true;
\r
5059 if ((_timer_restart != NULL) && _timer_restart->valid())
\r
5061 _timer_restart->invalidate();
\r
5063 if ((_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
5065 _timer_epg_s->invalidate();
\r
5067 if ((_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5069 _timer_epg_t->invalidate();
\r
5071 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
5073 _timer_periodic->invalidate();
\r
5075 if ((_timer_periodic_2 != NULL) && _timer_periodic_2->valid())
\r
5077 _timer_periodic_2->invalidate();
\r
5084 RELEASE(_timer_restart);
\r
5085 RELEASE(_timer_epg_s);
\r
5086 RELEASE(_timer_epg_t);
\r
5087 RELEASE(_timer_periodic);
\r
5088 RELEASE(_timer_periodic_2);
\r
5094 _initialized = false;
\r
5097 for (int i = 0; i < _tunerCount; ++i)
\r
5099 if (_tuners[i] != NULL)
\r
5101 delete _tuners[i];
\r
5102 _tuners[i] = NULL;
\r
5106 _cancel_epg_collect = false;
\r
5108 DebugLog0("system will suspend...");
\r
5113 #ifdef OBJC_MEMORY_CHECK
\r
5114 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
5117 DebugLog2("Controller::systemWillSuspend() end");
\r
5121 * TrayApp::WndProc() からコールされる
\r
5123 * スレッドコンテキスト:メインスレッド
\r
5125 void Controller::systemResumed()
\r
5127 DebugLog2("Controller::systemResumed() start");
\r
5129 DebugLog0("system resumed.");
\r
5131 if (_timer_restart == NULL)
\r
5134 _timer_restart = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_RESTART, false);
\r
5135 _timer_restart->fire();
\r
5138 DebugLog2("Controller::systemResumed()");
\r
5142 * TrayApp::WndProc() からコールされる
\r
5144 * スレッドコンテキスト:メインスレッド
\r
5146 void Controller::detectIdle()
\r
5148 DebugLog2("Controller::detectIdle()");
\r
5150 // ここはメインスレッドなのでARPを用意する
\r
5151 AutoreleasePool *pool = AutoreleasePool::alloc()->init();
\r
5159 if (_idle_count == 0)
\r
5161 DebugLog0("detect idle...");
\r
5167 // 起動中アプリと休止状態抑止アプリのチェック
\r
5168 bool found = false;
\r
5170 Array *dont_in_suspend = _props->arrayForKey(KEY_DO_NOT_IN_SUSPEND);
\r
5171 Array *running_apps = Workspace::sharedWorkspace()->runningApplications();
\r
5172 for (uint i = 0; (i < running_apps->count()) && !found; ++i)
\r
5174 RunningApplication *ra = (RunningApplication *)running_apps->objectAtIndex(i);
\r
5177 if (!ra->isRunning())
\r
5183 String *path = ra->executePath();
\r
5184 if ((path == NULL) || (path->length() == 0))
\r
5188 DebugLog3("exec path: %s", path->cString());
\r
5190 // 休止状態抑止アプリリストのチェック
\r
5191 for (uint j = 0; (j < dont_in_suspend->count()) && !found; ++j)
\r
5193 found = path->isMatch((String *)dont_in_suspend->objectAtIndex(j));
\r
5197 // 抑止有効なら KEY_FORCED_SUSPEND_TIME、無効なら KEY_SUSPEND_TIME で取得
\r
5198 int limit = _props->integerForKey(found ? KEY_FORCED_SUSPEND_TIME : KEY_SUSPEND_TIME);
\r
5199 DebugLog3("found: %d, _idle_count: %d, limit: %d", found, _idle_count, limit);
\r
5200 if (_idle_count >= limit)
\r
5205 // サスペンド前にARPを解放しておく
\r
5208 // 下記の TrayApp::suspend() を使用する場合、自アプリへsuspendメッセージが
\r
5209 // ブロードキャストされないため、自分でコールしておく
\r
5210 systemWillSuspend();
\r
5216 pool = AutoreleasePool::alloc()->init();
\r
5238 void Controller::detectNonIdle()
\r
5240 DebugLog2("Controller::detectNonIdle()");
\r
5245 if (_idle_count > 0)
\r
5247 DebugLog0("detect non idle...");
\r
5255 int Controller::restart()
\r
5261 _initialized = false;
\r
5264 for (int i = 0; i < _tunerCount; ++i)
\r
5266 if (_tuners[i] != NULL)
\r
5268 delete _tuners[i];
\r
5269 _tuners[i] = NULL;
\r
5277 _tunerCount = ry0::device::TunerFactory::scan(_tuners, _multi2_dll);
\r
5283 for (int i = 0; i < _tunerCount; ++i)
\r
5286 if (!isTunerInitialized(i))
\r
5292 if (isTunerEnabled(i))
\r
5295 setChannel(i, getChannel(i));
\r
5300 DebugLog0(" UDP Port Mapping :");
\r
5301 DebugLog0(" tuner, ch -> port");
\r
5302 int udpport = _props->integerForKey(KEY_BEGIN_UDP_PORT);
\r
5303 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
5305 uint max_channel = (_tuners[tuner]->type() == Tuner::ISDB_S ? Tuner::MAX_CHANNELS_ISDB_S : Tuner::MAX_CHANNELS_ISDB_T);
\r
5306 for (uint ch = 0; ch <= max_channel; ++ch)
\r
5308 if (isChannelEnabled(tuner, ch))
\r
5310 DebugLog0(" %5d,%3d -> %5d", tuner, ch, udpport);
\r
5312 Dictionary *udp_to_tuner_channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
5313 if (udp_to_tuner_channel == NULL)
\r
5315 udp_to_tuner_channel = Dictionary::dictionaryWithCapacity(0);
\r
5316 _streaming_ctrls->setObject(udp_to_tuner_channel, KEY_MAPPING_UDP_TO_TUNER_CHANNEL);
\r
5319 Dictionary *tuner_channel_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
5320 if (tuner_channel_to_udp == NULL)
\r
5322 tuner_channel_to_udp = Dictionary::dictionaryWithCapacity(0);
\r
5323 _streaming_ctrls->setObject(tuner_channel_to_udp, KEY_MAPPING_TUNER_CHANNEL_TO_UDP);
\r
5326 char port_str[10];
\r
5327 sprintf_s(port_str, "%d", udpport);
\r
5328 char tuner_and_channel[10];
\r
5329 sprintf_s(tuner_and_channel, "%d,%d", tuner, ch);
\r
5331 udp_to_tuner_channel->setString(tuner_and_channel, port_str);
\r
5332 tuner_channel_to_udp->setString(port_str, tuner_and_channel);
\r
5340 _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC, true);
\r
5341 _timer_periodic->fire();
\r
5344 _timer_periodic_2 = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC_2, true);
\r
5345 _timer_periodic_2->fire();
\r
5351 _initialized = true;
\r
5356 return (_tunerCount > 0);
\r
5359 int Controller::start()
\r
5363 Raym::LOG_NUM_MAX = 8;
\r
5365 #ifdef RAYM_MEMORY_CHECK
\r
5367 DebugLog0("global_raym_count_ = %d", Raym::global_raym_count_);
\r
5371 AutoreleasePool *pool = AutoreleasePool::alloc()->init();
\r
5374 _system_path = NULL;
\r
5375 _props_path = NULL;
\r
5377 _status_path = NULL;
\r
5379 _epgs_path = NULL;
\r
5381 _store_path = NULL;
\r
5382 _reservations = NULL;
\r
5383 _reservations_path = NULL;
\r
5384 _timer_restart = NULL;
\r
5385 _timer_periodic = NULL;
\r
5386 _timer_periodic_2 = NULL;
\r
5387 _timer_epg_s = NULL;
\r
5388 _timer_epg_t = NULL;
\r
5389 _multi2_dll = NULL;
\r
5390 _streaming_ctrls = NULL;
\r
5393 _initialized = false;
\r
5394 _reservation_seq_id = 0;
\r
5395 _cancel_epg_collect = false;
\r
5398 for (int i = 0; i < ry0::device::MAX_TUNERS; ++i)
\r
5400 _tuners[i] = NULL;
\r
5404 DebugLog0("------------------------------------------------------------------------");
\r
5405 DebugLog0("iPTd ver %s (rev.%d)", VERSION, REVISION);
\r
5406 DebugLog0("initialize...");
\r
5413 bool updated = false;
\r
5416 _system_path = String::stringWithFormat("%s", GetExecutePath());
\r
5417 if (_system_path == NULL)
\r
5419 DebugLog0("error: GetExecutePath()");
\r
5423 _system_path = _system_path->stringByReplacingOccurrencesOfString("iPTd.exe", "");
\r
5424 _system_path->retain();
\r
5425 DebugLog2("_system_path: %s", _system_path->cString());
\r
5428 _props_path = String::alloc()->initWithFormat("%s%s.iptd.plist", _system_path->cString(), PLIST_PREFIX);
\r
5429 if (_props_path == NULL)
\r
5431 DebugLog0("error: set property file path.");
\r
5437 _props = Dictionary::alloc()->initWithContentsOfFile(_props_path);
\r
5438 if (_props == NULL)
\r
5440 DebugLog1("property file: %s (created)", _props_path->cString());
\r
5441 _props = Dictionary::alloc()->initWithCapacity(0);
\r
5445 DebugLog1("property file: %s", _props_path->cString());
\r
5449 _status_path = String::alloc()->initWithFormat("%s%s.iptd.status.plist", _system_path->cString(), PLIST_PREFIX);
\r
5450 if (_status_path == NULL)
\r
5452 DebugLog0("error: set status file path.");
\r
5458 _status = Dictionary::alloc()->initWithContentsOfFile(_status_path);
\r
5459 if (_status == NULL)
\r
5461 DebugLog1("status file: %s (created)", _status_path->cString());
\r
5462 _status = Dictionary::alloc()->initWithCapacity(0);
\r
5466 DebugLog1("status file: %s", _status_path->cString());
\r
5470 if (_props->stringForKey(KEY_NAME) == NULL)
\r
5472 _props->setString(DEF_NAME, KEY_NAME);
\r
5477 if (_props->stringForKey(KEY_HOSTNAME) == NULL)
\r
5479 _props->setString(DEF_HOSTNAME, KEY_HOSTNAME);
\r
5483 // multi2デコード可否判定: multi2.dll が使えるか確認する
\r
5484 _multi2_dll = ::LoadLibrary(L"multi2.dll");
\r
5485 while (_multi2_dll != NULL)
\r
5488 ARIB_STD_B25 *(*func_b25)();
\r
5489 func_b25 = reinterpret_cast<ARIB_STD_B25 *(*)()>(::GetProcAddress(_multi2_dll, "create_arib_std_b25"));
\r
5490 if (func_b25 == NULL)
\r
5493 FreeLibrary(_multi2_dll);
\r
5494 _multi2_dll = NULL;
\r
5499 ARIB_STD_B25 * _b25;
\r
5500 _b25 = func_b25();
\r
5504 FreeLibrary(_multi2_dll);
\r
5505 _multi2_dll = NULL;
\r
5508 _b25->release(_b25);
\r
5511 B_CAS_CARD *(*func_bcas)();
\r
5512 func_bcas = reinterpret_cast<B_CAS_CARD *(*)()>(::GetProcAddress(_multi2_dll, "create_b_cas_card"));
\r
5513 if (func_bcas == NULL)
\r
5516 FreeLibrary(_multi2_dll);
\r
5517 _multi2_dll = NULL;
\r
5522 B_CAS_CARD * _bcas;
\r
5523 _bcas = func_bcas();
\r
5524 if (_bcas == NULL)
\r
5527 FreeLibrary(_multi2_dll);
\r
5528 _multi2_dll = NULL;
\r
5531 if (_bcas->init(_bcas) != 0)
\r
5534 FreeLibrary(_multi2_dll);
\r
5535 _multi2_dll = NULL;
\r
5538 _bcas->release(_bcas);
\r
5545 if (_props->integerForKey(KEY_HTTP_PORT) == 0)
\r
5547 _props->setInteger(DEF_HTTP_PORT, KEY_HTTP_PORT);
\r
5552 if ((_props->integerForKey(KEY_SUSPEND_TIME) < DEF_SUSPEND_TIME) ||
\r
5553 (_props->integerForKey(KEY_SUSPEND_TIME) >= _props->integerForKey(KEY_FORCED_SUSPEND_TIME)))
\r
5555 _props->setInteger(DEF_SUSPEND_TIME, KEY_SUSPEND_TIME);
\r
5560 if ((_props->integerForKey(KEY_FORCED_SUSPEND_TIME) == 0) ||
\r
5561 (_props->integerForKey(KEY_FORCED_SUSPEND_TIME) <= _props->integerForKey(KEY_SUSPEND_TIME)))
\r
5563 _props->setInteger(DEF_FORCED_SUSPEND_TIME, KEY_FORCED_SUSPEND_TIME);
\r
5568 if (_props->integerForKey(KEY_BEGIN_UDP_PORT) == 0)
\r
5570 _props->setInteger(DEF_BEGIN_UDP_PORT, KEY_BEGIN_UDP_PORT);
\r
5575 if ((_props->stringForKey(KEY_COLLECT_EPG_TIME) == NULL) ||
\r
5576 !_props->stringForKey(KEY_COLLECT_EPG_TIME)->isMatch(String::stringWithUTF8String("^\\d\\d:\\d\\d:\\d\\d$")))
\r
5578 _props->setString(DEF_COLLECT_EPG_TIME, KEY_COLLECT_EPG_TIME);
\r
5583 if (_props->arrayForKey(KEY_DO_NOT_IN_SUSPEND) == NULL)
\r
5585 Array *apps = Array::arrayWithCapacity(0);
\r
5586 apps->addObject(String::stringWithUTF8String("PIXELACORPORATION.*DtvView\\.exe$"));
\r
5587 apps->addObject(String::stringWithUTF8String("Common7\\\\IDE\\\\devenv\\.exe$"));
\r
5588 apps->addObject(String::stringWithUTF8String("Kodi\\\\Kodi\\.exe$"));
\r
5589 _props->setObject(apps, KEY_DO_NOT_IN_SUSPEND);
\r
5594 _store_path = _props->stringForKey(KEY_STORE_PATH);
\r
5595 if (_store_path == NULL)
\r
5598 // <Public Directory>/Videos を設定
\r
5599 const char *public_dir = GetPublicDirectory();
\r
5600 if (public_dir == NULL)
\r
5602 DebugLog0("error: GetPublicDirectory().");
\r
5606 _store_path = String::alloc()->initWithFormat("%s\\Videos", public_dir);
\r
5607 _props->setString(_store_path, KEY_STORE_PATH);
\r
5614 _store_path->retain();
\r
5617 // 実際にディレクトリが存在しているか確認
\r
5618 FileManager *fm = FileManager::defaultManager();
\r
5619 bool isDir = false;
\r
5620 if (!fm->fileExistsAtPath(_store_path, &isDir))
\r
5626 DebugLog0("error: \"%s\" is not exists.", _store_path->cString());
\r
5632 if (_props->dictionaryForKey(KEY_PRESETS) == NULL)
\r
5634 Dictionary *presets = Dictionary::dictionaryWithCapacity(0);
\r
5635 _props->setObject(presets, KEY_PRESETS);
\r
5638 // プリセットは、あとで実装。。。
\r
5642 preset = STR_ARRAY("-vcodec", "libx264",
\r
5645 "-acodec", "libfaac",
\r
5648 "-flags", "+loop-global_header",
\r
5650 "-bsf", "h264_mp4toannexb",
\r
5652 "-segment_format", "mpegts",
\r
5653 "-segment_time", "10",
\r
5655 presets->setObject(preset, KEY_DEFAULT);
\r
5660 // キャッシュ(HLSの一時ファイル格納先)パス
\r
5661 if (_props->stringForKey(KEY_CACHE_PATH) == NULL)
\r
5663 _props->setString(_store_path, KEY_CACHE_PATH);
\r
5670 DebugLog0("props updated.");
\r
5671 if (!_props->writeToFile(_props_path, false))
\r
5673 DebugLog0("Can't write property file.");
\r
5680 DebugLog0(" Name : %s", _props->stringForKey(KEY_NAME)->cString());
\r
5681 DebugLog0(" Decode Enabled : %s", (_multi2_dll != NULL) ? "true" : "false");
\r
5682 DebugLog0(" HTTP Port : %d", _props->integerForKey(KEY_HTTP_PORT));
\r
5683 DebugLog0(" Suspend Time : %d min", _props->integerForKey(KEY_SUSPEND_TIME));
\r
5684 DebugLog0(" Forced Suspend Time : %d min", _props->integerForKey(KEY_FORCED_SUSPEND_TIME));
\r
5685 Array *apps = _props->arrayForKey(KEY_DO_NOT_IN_SUSPEND);
\r
5688 DebugLog1(" Do not in suspend :");
\r
5689 for (uint i = 0; i < apps->count(); ++i)
\r
5691 DebugLog1(" RegExp[%02d] : %s", i, ((String *)apps->objectAtIndex(i))->cString());
\r
5696 _epgs_path = String::alloc()->initWithFormat("%s%s.iptd.epgs.plist", _system_path->cString(), PLIST_PREFIX);
\r
5697 if (_epgs_path == NULL)
\r
5699 DebugLog0("error: set epgs file path.");
\r
5705 _epgs = Dictionary::alloc()->initWithContentsOfFile(_epgs_path);
\r
5706 if (_epgs == NULL)
\r
5708 DebugLog1("epgs file: %s (created)", _epgs_path->cString());
\r
5709 _epgs = Dictionary::alloc()->initWithCapacity(0);
\r
5713 DebugLog1("epgs file: %s", _epgs_path->cString());
\r
5720 _reservations_path = String::alloc()->initWithFormat("%s%s.iptd.reservations.plist", _system_path->cString(), PLIST_PREFIX);
\r
5721 if (_reservations_path == NULL)
\r
5723 DebugLog0("error: set reservations file path.");
\r
5729 _reservations = Dictionary::alloc()->initWithContentsOfFile(_reservations_path);
\r
5730 if (_reservations == NULL)
\r
5732 DebugLog1("reservations file: %s (created)", _reservations_path->cString());
\r
5733 _reservations = Dictionary::alloc()->initWithCapacity(0);
\r
5737 DebugLog1("reservations file: %s", _reservations_path->cString());
\r
5740 _reservation_seq_id = _reservations->integerForKey(KEY_EPG_LAST_RESV_ID);
\r
5744 _streaming_ctrls = Dictionary::alloc()->initWithCapacity(0);
\r
5747 String *rootPath = _system_path->stringByAppendingPathComponent("iptd_html");
\r
5748 if (!fm->fileExistsAtPath(rootPath, &isDir))
\r
5754 DebugLog0("error: \"%s\" is not exists.", rootPath->cString());
\r
5760 int port = _props->integerForKey(KEY_HTTP_PORT);
\r
5761 _httpd = NET::HTTPDaemon::alloc()->initWithPort(port, 10);
\r
5762 _httpd->setRootPath(rootPath);
\r
5763 _httpd->setDelegate(this);
\r
5764 if (!_httpd->start())
\r
5766 DebugLog0("Can't start httpd.");
\r
5772 _timer_restart = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_RESTART, false);
\r
5773 _timer_restart->fire();
\r
5778 // 初期化エラーがなければイベント待ちへ
\r
5781 result = Application::start();
\r
5788 _cancel_epg_collect = true;
\r
5792 if ((_timer_restart != NULL) && _timer_restart->valid())
\r
5794 _timer_restart->invalidate();
\r
5796 if ((_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
5798 _timer_epg_s->invalidate();
\r
5800 if ((_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5802 _timer_epg_t->invalidate();
\r
5804 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
5806 _timer_periodic->invalidate();
\r
5808 if ((_timer_periodic_2 != NULL) && _timer_periodic_2->valid())
\r
5810 _timer_periodic_2->invalidate();
\r
5814 for (int i = 0; i < _tunerCount; ++i)
\r
5816 if (_tuners[i] != NULL)
\r
5818 delete _tuners[i];
\r
5819 _tuners[i] = NULL;
\r
5824 resetWakeSchedule();
\r
5827 RELEASE(_timer_restart);
\r
5828 RELEASE(_timer_epg_s);
\r
5829 RELEASE(_timer_epg_t);
\r
5830 RELEASE(_timer_periodic);
\r
5831 RELEASE(_timer_periodic_2);
\r
5832 RELEASE(_streaming_ctrls);
\r
5834 RELEASE(_system_path);
\r
5835 RELEASE(_props_path);
\r
5837 RELEASE(_status_path);
\r
5839 RELEASE(_epgs_path);
\r
5841 RELEASE(_store_path);
\r
5842 RELEASE(_reservations_path);
\r
5843 RELEASE(_reservations);
\r
5845 if (_multi2_dll != NULL)
\r
5847 FreeLibrary(_multi2_dll);
\r
5853 DebugLog0("finished.");
\r
5855 #ifdef RAYM_MEMORY_CHECK
\r
5856 DebugLog0("global_raym_count_ = %d", Raym::global_raym_count_);
\r
5864 #pragma mark ------- コンストラクタ/デストラクタ -------
\r
5867 Controller::Controller()
\r
5871 Controller::~Controller()
\r
5875 Controller *Controller::alloc()
\r
5877 return new Controller();
\r
5882 #pragma mark ------- その他 -------
\r
5886 // HH:MM:SS 形式の文字列から time_t に変換
\r
5887 // 現在時刻が指定文字列の時刻以前の場合、当日の時刻。指定文字列の時刻よりも過ぎている場合、翌日の時刻を返す。
\r
5889 void Controller::getTimeWithString(String *str, time_t *time_var)
\r
5891 if ((str != NULL) && str->isMatch(String::stringWithUTF8String("^\\d\\d:\\d\\d:\\d\\d$")) && (time_var != NULL))
\r
5893 // 時:分:秒 を int型に分解
\r
5894 std::string time_str = str->cString();
\r
5895 int hour = atoi(time_str.substr(0, 2).c_str());
\r
5896 int min = atoi(time_str.substr(3, 2).c_str());
\r
5897 int sec = atoi(time_str.substr(6, 2).c_str());
\r
5898 DebugLog2("%02d:%02d:%02d", hour, min, sec);
\r
5901 time_t now = time(NULL);
\r
5903 if (localtime_s(&now_tm, &now) == 0)
\r
5905 int now_sec = now_tm.tm_hour * 3600 + now_tm.tm_min * 60 + now_tm.tm_sec;
\r
5906 int col_sec = hour * 3600 + min * 3600 + sec;
\r
5907 if (now_sec > col_sec)
\r
5911 now_tm.tm_hour = hour;
\r
5912 now_tm.tm_min = min;
\r
5913 now_tm.tm_sec = sec;
\r
5915 *time_var = mktime(&now_tm);
\r
5920 void Controller::getTimeWithEPG(Dictionary *epg, time_t *start, time_t *end)
\r
5922 if ((epg == NULL) || (start == NULL) || (end == NULL))
\r
5926 String *date = epg->stringForKey(KEY_EPG_DATE);
\r
5927 String *st = epg->stringForKey(KEY_EPG_START);
\r
5928 String *ed = epg->stringForKey(KEY_EPG_END);
\r
5929 if ((date == NULL) || (st == NULL) || (ed == NULL))
\r
5934 std::string dateStr = date->cString();
\r
5935 std::string stStr = st->cString();
\r
5936 std::string edStr = ed->cString();
\r
5938 tm_start.tm_year = atoi(dateStr.substr(0, 4).c_str()) - 1900;
\r
5939 tm_start.tm_mon = atoi(dateStr.substr(5, 2).c_str()) - 1;
\r
5940 tm_start.tm_mday = atoi(dateStr.substr(8, 2).c_str());
\r
5941 tm_start.tm_hour = atoi(stStr.substr(0, 2).c_str());
\r
5942 tm_start.tm_min = atoi(stStr.substr(3, 2).c_str());
\r
5943 tm_start.tm_sec = atoi(stStr.substr(6, 2).c_str());
\r
5946 tm_end.tm_year = atoi(dateStr.substr(0, 4).c_str()) - 1900;
\r
5947 tm_end.tm_mon = atoi(dateStr.substr(5, 2).c_str()) - 1;
\r
5948 tm_end.tm_mday = atoi(dateStr.substr(8, 2).c_str());
\r
5949 tm_end.tm_hour = atoi(edStr.substr(0, 2).c_str());
\r
5950 tm_end.tm_min = atoi(edStr.substr(3, 2).c_str());
\r
5951 tm_end.tm_sec = atoi(edStr.substr(6, 2).c_str());
\r
5952 if (stStr > edStr)
\r
5954 tm_end.tm_mday += 1;
\r
5956 *start = mktime(&tm_start);
\r
5957 *end = mktime(&tm_end);
\r