6 #include <Raym/Log.h>
\r
10 #include <sys/types.h>
\r
11 #include <sys/stat.h>
\r
16 #include <winsock2.h>
\r
17 #include <ws2tcpip.h>
\r
18 #include <Iphlpapi.h>
\r
20 #include "b25/aribstr.h"
\r
21 #include "b25/arib_std_b25.h"
\r
22 #include "b25/b_cas_card.h"
\r
24 #include "net/RTSPRequest.h"
\r
26 #include "ry0/iPTd/Controller.h"
\r
27 #include "ry0/iPTd/HTTPLiveStreaming.h"
\r
28 #include "ry0/iPTd/Extractor.h"
\r
31 using namespace Raym;
\r
32 using namespace NET;
\r
33 using namespace ry0::device;
\r
40 static const char *PLIST_PREFIX = "com.gmail.tim.and.pom";
\r
43 static const char * DEF_NAME = "iPTd_R3";
\r
44 static const char * DEF_HOSTNAME = "localhost";
\r
45 static const int DEF_HTTP_PORT = 50080; // HTTPポート
\r
46 static const int DEF_BEGIN_UDP_PORT = 51000; // UDPポートの開始位置
\r
47 static const char * DEF_COLLECT_EPG_TIME = "02:00:00"; // EPG収集する時刻 HH:MM::SS
\r
48 static const int DEF_SHUTDOWN_TIME_INIT = 15; // シャットダウンするまでの時間(分単位):起動後
\r
49 static const int DEF_SHUTDOWN_TIME = 5; // シャットダウンするまでの時間(分単位):録画後
\r
50 static const int DEF_FORCED_SHUTDOWN = 120; // 強制シャットダウンするまでの時間(分単位)
\r
51 static const int DEF_DISK_REMAIN = 10; //
\r
54 static const long long CMD_RESTART = 0x0001; // 再開処理
\r
55 static const long long CMD_PERIODIC = 0x0003; // 周期処理
\r
56 static const long long CMD_PERIODIC_2 = 0x0004; // 周期処理2
\r
57 static const long long CMD_COLLECT_EPG_ISDB_S = 0x0005; // 番組情報取得(ISDB-S)
\r
58 static const long long CMD_COLLECT_EPG_ISDB_T = 0x0006; // 番組情報取得(ISDB-T)
\r
61 static const TimeInterval DEF_COLLECT_EPG_DELAY = 1.0;
\r
62 static const TimeInterval DEF_COLLECT_EPG_RETRY = 60.0;
\r
64 static const time_t DEF_COLLECT_EPG_LIMIT_S = 10;
\r
65 static const time_t DEF_COLLECT_EPG_LIMIT_T = 20;
\r
67 static const time_t OFFSET_OF_START_TIME = -2; // 録画開始時刻の補正(秒単位)
\r
68 static const time_t OFFSET_OF_END_TIME = -3; // 録画停止時刻の補正(秒単位)
\r
69 static const time_t OFFSET_OF_WAKEUP = -600; // 起動スケジュールの補正(秒単位) 注:休止するまでの時間(DEF_SUSPEND_TIME)よりも短くすること
\r
70 static const time_t OFFSET_OF_SUPPRESSION_TIME = -720; // 録画開始前に休止の抑制を開始する時間(秒単位)
\r
73 std::string Controller::createVideoPath(int tuner)
\r
75 DebugLog2("Controller::createVideoPath()");
\r
77 std::string result = "";
\r
84 if (localtime_s(&tm, &now) != 0)
\r
89 result = _store_path->cString();
\r
90 DebugLog2("result: %s\n", result.c_str());
\r
93 if (sprintf_s(tmp, sizeof(tmp), "\\%04d", tm.tm_year + 1900) < 0)
\r
95 DebugLog0("sprintf_s() error: year\n");
\r
100 DebugLog2("result: %s\n", result.c_str());
\r
103 if (_stat(result.c_str(), &stat) != 0)
\r
105 if (_mkdir(result.c_str()) != 0)
\r
107 DebugLog0("_mkdir() error: year\n");
\r
111 _stat(result.c_str(), &stat);
\r
113 if ((stat.st_mode & _S_IFDIR) != _S_IFDIR)
\r
115 DebugLog0("%s is not directory.\n", result.c_str());
\r
120 if (sprintf_s(tmp, sizeof(tmp), "\\%02d", tm.tm_mon + 1) < 0)
\r
122 DebugLog0("sprintf_s() error: month\n");
\r
127 DebugLog2("result: %s\n", result.c_str());
\r
129 if (_stat(result.c_str(), &stat) != 0)
\r
131 if (_mkdir(result.c_str()) != 0)
\r
133 DebugLog0("_mkdir() error: month\n");
\r
137 _stat(result.c_str(), &stat);
\r
139 if ((stat.st_mode & _S_IFDIR) != _S_IFDIR)
\r
141 DebugLog0("%s is not directory.", result.c_str());
\r
146 if (sprintf_s(tmp, sizeof(tmp),
\r
147 "\\%04d%02d%02d_%02d%02d%02d_%03d_%s.ts",
\r
148 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
\r
149 _tuners[tuner]->channel(), _tuners[tuner]->name()) < 0)
\r
151 DebugLog0("sprintf_s() error: filename");
\r
156 DebugLog2("result: %s\n", result.c_str());
\r
164 // epgの開始時刻でソートする為の比較関数
\r
165 Integer compareFunction(Object *obj1, Object *obj2, void *context)
\r
167 if (isKindOfClass(Dictionary, obj1) && isKindOfClass(Dictionary, obj2))
\r
171 Controller::getTimeWithEPG((Dictionary *)obj1, &st1, &ed1);
\r
175 Controller::getTimeWithEPG((Dictionary *)obj2, &st2, &ed2);
\r
179 return OrderedAscending;
\r
181 else if (st1 > st2)
\r
183 return OrderedDescending;
\r
189 return OrderedAscending;
\r
191 else if (ed1 > ed2)
\r
193 return OrderedDescending;
\r
197 return OrderedSame;
\r
202 #pragma mark ------- EPG関連 -------
\r
205 void Controller::removePastEPGs()
\r
207 DebugLog2("Controller::removePastEPGs()");
\r
209 time_t now = time(NULL);
\r
213 Dictionary *temp_data = _epgs->dictionaryForKey(KEY_TEMP_DATA);
\r
214 if (temp_data != NULL)
\r
216 temp_data->retain();
\r
217 _epgs->removeObjectForKey(KEY_TEMP_DATA);
\r
221 temp_data = Dictionary::alloc()->initWithCapacity(0);
\r
224 Dictionary *services = _epgs->dictionaryForKey(KEY_SERVICES);
\r
225 if (services != NULL)
\r
227 Array *keys = services->allKeys();
\r
228 for (uint i = 0; i < keys->count(); ++i)
\r
230 String *key = (String *)keys->objectAtIndex(i);
\r
232 std::string xmltv_programs;
\r
233 Dictionary *temp_service = temp_data->dictionaryForKey(key);
\r
234 if (temp_service == NULL)
\r
236 temp_service = Dictionary::dictionaryWithCapacity(0);
\r
237 temp_data->setObject(temp_service, key);
\r
240 Array *old_epgs = services->arrayForKey(key);
\r
241 Array *new_epgs = Array::arrayWithCapacity(0);
\r
242 for (uint j = 0; j < old_epgs->count(); ++j)
\r
244 Dictionary *epg = (Dictionary *)old_epgs->objectAtIndex(j);
\r
247 getTimeWithEPG(epg, &start, &end);
\r
250 new_epgs->addObject(epg);
\r
252 Array *ch_list = temp_service->arrayForKey(KEY_CHANNELS);
\r
253 if (ch_list != NULL)
\r
255 std::string epg_date = epg->stringForKey(KEY_EPG_DATE)->stringByReplacingOccurrencesOfString("/", "")->cString();
\r
256 std::string epg_start = epg->stringForKey(KEY_EPG_START)->stringByReplacingOccurrencesOfString(":", "")->cString();
\r
257 std::string epg_end = epg->stringForKey(KEY_EPG_END)->stringByReplacingOccurrencesOfString(":", "")->cString();
\r
258 std::string epg_event_id = epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
259 std::string epg_duration = epg->stringForKey(KEY_EPG_DURATION)->cString();
\r
260 std::string epg_title = epg->stringForKey(KEY_EPG_TITLE)->cString();
\r
262 for (uint ch_idx = 0; ch_idx < ch_list->count(); ++ch_idx)
\r
264 xmltv_programs += " <programme start=\"" + epg_date + epg_start + " +0900\" stop=\"";
\r
265 xmltv_programs += epg_date + epg_end + " +0900\" channel=\"";
\r
266 xmltv_programs += ((String *)ch_list->objectAtIndex(ch_idx))->cString();
\r
267 xmltv_programs += "\" event_id=\"" + epg_event_id + "\" duration=\"" + epg_duration + "\">\r\n";
\r
269 xmltv_programs += " <title lang=\"ja_JP\">" + epg_title + "</title>\r\n";
\r
271 xmltv_programs += " </programme>\r\n";
\r
276 services->setObject(new_epgs, key);
\r
278 if (xmltv_programs.length() > 0)
\r
280 temp_service->setObject(String::stringWithUTF8String(xmltv_programs.c_str()), KEY_PROGRAMS);
\r
285 _epgs->writeToFile(_epgs_path, true);
\r
287 _epgs->setObject(temp_data, KEY_TEMP_DATA);
\r
288 temp_data->release();
\r
293 void Controller::collectEPGsForTuner(Tuner::Type type, int tuner, time_t limit)
\r
295 DebugLog2("Controller::collectEPGsForTuner(%d) start.", tuner);
\r
297 // 既にロックされた状態でコールされる前提
\r
298 bool locked = false;
\r
300 if ((0 <= tuner) && (tuner < _tunerCount))
\r
302 locked = _tuners[tuner]->isLocked();
\r
307 DebugLog2("Controller::collectEPGsForTuner(%d) end(no locked).", tuner);
\r
311 for (uint cnt = 0; cnt * 5 < limit; ++cnt)
\r
313 Extractor *extractor = Extractor::alloc()->init();
\r
316 _tuners[tuner]->setListener(extractor);
\r
319 Array *collected = extractor->collectEPGs(5);
\r
322 _tuners[tuner]->setListener(NULL);
\r
325 extractor->release();
\r
329 for (uint j = 0; j < collected->count(); ++j)
\r
331 Dictionary *epg = (Dictionary *)collected->objectAtIndex(j);
\r
333 if (epg->stringForKey(KEY_EPG_TITLE) == NULL)
\r
339 // Service ID を Primary Key
\r
340 String *key = epg->stringForKey(KEY_EPG_SERVICE_ID);
\r
343 Dictionary *services = _epgs->dictionaryForKey(KEY_SERVICES);
\r
344 if (services == NULL)
\r
346 services = Dictionary::dictionaryWithCapacity(0);
\r
347 _epgs->setObject(services, KEY_SERVICES);
\r
349 Array *epgs = services->arrayForKey(key);
\r
352 epgs = Array::arrayWithCapacity(0);
\r
353 services->setObject(epgs, key);
\r
355 bool inserted = false;
\r
356 for (uint idx = 0; idx < epgs->count(); ++idx)
\r
358 Dictionary *epg2 = (Dictionary *)epgs->objectAtIndex(idx);
\r
359 if (epg->stringForKey(KEY_EPG_EVENT_ID)->isEqualToString(epg2->stringForKey(KEY_EPG_EVENT_ID)))
\r
364 if (compareFunction(epg, epgs->objectAtIndex(idx), NULL) == OrderedAscending)
\r
366 epgs->insertObject(epg, idx);
\r
373 epgs->addObject(epg);
\r
381 if (((type == Tuner::ISDB_S) && _cancel_epg_collect_s) ||
\r
382 ((type == Tuner::ISDB_T) && _cancel_epg_collect_t))
\r
391 DebugLog2("Controller::collectEPGsForTuner(%d) end.", tuner);
\r
394 bool Controller::collectEPGs(Tuner::Type type)
\r
398 bool locked = false;
\r
400 for (int i = _tunerCount - 1; i >= 0; --i)
\r
402 if (isTunerEnabled(i))
\r
404 if ((!_tuners[i]->isLocked()) && (_tuners[i]->type() == type))
\r
406 if (_tuners[i]->lock())
\r
420 DebugLog3("Controller::collectEPGs(%s) end(Can't locled).", type == Tuner::ISDB_S ? "ISDB-S" : "ISDB-T");
\r
425 bool canceled = false;
\r
426 DebugLog0("Collect EPG of \"%s(#%d)\" is started.", _tuners[tuner]->name(), tuner);
\r
429 int channel = _tuners[tuner]->channel();
\r
431 // チャンネルを変更しつつEPGを取得
\r
432 int max_channel = (type == Tuner::ISDB_S ? Tuner::MAX_CHANNELS_ISDB_S : Tuner::MAX_CHANNELS_ISDB_T);
\r
433 for (int ch = 0; ch <= max_channel; ++ch)
\r
436 if (isChannelEnabled(tuner, ch))
\r
439 if (_tuners[tuner]->setChannel(ch))
\r
441 // DebugLog0("Collect EPG of \"%s(#%d)\" ch %d", _tuners[tuner]->name(), tuner, ch);
\r
442 time_t limit = (time_t)_epgs->integerForKey(stationName(type, ch));
\r
445 limit = ((type == Tuner::ISDB_S) ? DEF_COLLECT_EPG_LIMIT_S : DEF_COLLECT_EPG_LIMIT_T);
\r
446 _epgs->setInteger((int)limit, stationName(type, ch));
\r
449 collectEPGsForTuner(type, tuner, limit);
\r
452 if (((type == Tuner::ISDB_S) && _cancel_epg_collect_s) ||
\r
453 ((type == Tuner::ISDB_T) && _cancel_epg_collect_t))
\r
455 ch = Tuner::MAX_CHANNELS_ISDB_T + 1;
\r
464 _tuners[tuner]->setChannel(channel);
\r
470 _tuners[tuner]->unlock();
\r
472 if (type == Tuner::ISDB_S)
\r
474 _cancel_epg_collect_s = false;
\r
478 _cancel_epg_collect_t = false;
\r
482 updateKeywordsReservation();
\r
487 DebugLog0("Collect EPG of \"%s(#%d)\" was %s.", _tuners[tuner]->name(), tuner, canceled ? "canceled" : "finished");
\r
494 #pragma mark ------- 予約録画関連 -------
\r
498 // 録画予約:サービスID/イベントID指定
\r
499 // EPGデータから指定のサービスID/イベントIDのEPGを取り出し、EPG指定の録画予約をコール
\r
501 bool Controller::reserve(int service_id, int event_id)
\r
503 DebugLog0("Controller::reserve(service_id, event_id)");
\r
504 DebugLog0("event_id: %d, service_id: %d", event_id, service_id);
\r
506 bool result = false;
\r
511 if ((_epgs != NULL) && (_epgs->dictionaryForKey(KEY_SERVICES) != NULL))
\r
513 Array *events = _epgs->dictionaryForKey(KEY_SERVICES)->arrayForKey(String::stringWithFormat("%d", service_id));
\r
514 if (events != NULL)
\r
516 DebugLog0("count: %d, event_id: %d, service_id: %d", events->count(), event_id, service_id);
\r
517 for (uint i = 0; i < events->count(); ++i)
\r
519 Dictionary *epg = (Dictionary *)events->objectAtIndex(i);
\r
520 DebugLog0("epg event_id: %s", epg->stringForKey(KEY_EPG_EVENT_ID)->cString());
\r
521 if (epg->stringForKey(KEY_EPG_EVENT_ID)->isEqualToString(String::stringWithFormat("%d", event_id)))
\r
523 result = reserve(epg);
\r
529 DebugLog0("events is NULL");
\r
534 DebugLog0("_epgs is NULL");
\r
545 // EPGからサービスIDを取り出し、チューナ情報を検索して一致するサービスIDがあったらチューナ/EPG指定の録画予約を試行
\r
547 bool Controller::reserve(Dictionary *in_epg)
\r
549 DebugLog0("Controller::reserve(epg)");
\r
551 bool result = false;
\r
556 while (in_epg != NULL)
\r
559 Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg);
\r
562 DebugLog3("Dictionary::dictionaryWithDictionary() ng.");
\r
567 String *service_id = epg->stringForKey(KEY_EPG_SERVICE_ID);
\r
568 if (service_id == NULL)
\r
570 DebugLog3("epg->stringForKey(KEY_EPG_SERVICE_ID) ng.");
\r
573 DebugLog3("service_id: %s\n", service_id->cString());
\r
576 Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);
\r
577 if (tunerInfos == NULL)
\r
579 DebugLog3("_props->dictionaryForKey(KEY_TUNERS) ng.");
\r
584 for (int i = 0; (!result) && (i < _tunerCount); ++i)
\r
587 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name());
\r
588 if (tunerInfo == NULL)
\r
590 DebugLog3("tunerInfos->dictionaryForKey(_tuners[%d]->name()) ng.", i);
\r
595 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
596 if (channels == NULL)
\r
598 DebugLog3("tunerInfo->dictionaryForKey(KEY_CHANNELS) ng.");
\r
603 Array *chkeys = channels->allKeys();
\r
604 for (uint ch = 0; ch < chkeys->count(); ++ch)
\r
607 Dictionary *channel = channels->dictionaryForKey((String *)chkeys->objectAtIndex(ch));
\r
608 if (channel == NULL)
\r
610 DebugLog3("channels->dictionaryForKey() ng.");
\r
615 Array *services = (Array *)channel->objectForKey(KEY_SERVICES);
\r
616 if (services == NULL)
\r
618 DebugLog3("channel->objectForKey() ng.");
\r
622 for (uint s = 0; s < services->count(); ++s)
\r
625 Dictionary *service = (Dictionary *)services->objectAtIndex(s);
\r
626 if (service == NULL)
\r
628 DebugLog3("service->objectAtIndex() ng.");
\r
633 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
634 if ((sid != NULL) && sid->isEqualToString(service_id))
\r
637 epg->setString((String *)chkeys->objectAtIndex(ch), KEY_EPG_CHANNEL);
\r
640 result = reserve(i, epg);
\r
642 // チャンネルループのカウンタを更新(=ループを終了させる)
\r
643 ch = chkeys->count();
\r
662 bool Controller::reserve(int tuner, Dictionary *in_epg)
\r
664 DebugLog0("Controller::reserve(tuner, epg)");
\r
666 bool result = false;
\r
671 while ((0 <= tuner) && (tuner < _tunerCount) && (in_epg != NULL))
\r
673 Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg);
\r
676 DebugLog3("Dictionary::dictionaryWithDictionary() ng.");
\r
680 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
683 array = Array::arrayWithCapacity(0);
\r
684 _reservations->setObject(array, _tuners[tuner]->name());
\r
689 getTimeWithEPG(epg, &epg_start, &epg_end);
\r
690 DebugLog2("epg start: %ld, end: %ld\n", epg_start, epg_end);
\r
692 time_t pre_start = 0;
\r
693 time_t pre_end = 0;
\r
694 pre_end = time(NULL);
\r
695 DebugLog2("pre_end: %ld", pre_end);
\r
697 for (uint i = 0; i < array->count(); ++i)
\r
699 Dictionary *cur = (Dictionary *)array->objectAtIndex(i);
\r
702 getTimeWithEPG(cur, &cur_start, &cur_end);
\r
703 DebugLog2("cur start: %ld, end: %ld\n", cur_start, cur_end);
\r
704 if ((pre_end <= epg_start) && (epg_end <= cur_start))
\r
706 DebugLog2("insert: %d\n", i);
\r
707 array->insertObject(epg, i);
\r
711 pre_start = cur_start;
\r
717 if (pre_end <= epg_start)
\r
719 DebugLog2("add\n");
\r
720 array->addObject(epg);
\r
725 DebugLog2("no add\n");
\r
730 epg->setInteger(_reservation_seq_id, KEY_EPG_RESV_ID);
\r
731 _reservation_seq_id = (_reservation_seq_id + 1) % 1000000;
\r
732 _reservations->setInteger(_reservation_seq_id, KEY_EPG_LAST_RESV_ID);
\r
735 _reservations->writeToFile(_reservations_path, true);
\r
748 // tuner: 0 - (_tunerCount - 1) cancel current
\r
749 // tuner: -1 cancel reserve_id
\r
751 bool Controller::cancel(int tuner, int reserve_id)
\r
753 bool result = false;
\r
759 if ((0 <= tuner) && (tuner < _tunerCount))
\r
761 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
764 if (array->count() > 0)
\r
766 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
767 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
768 if (status != NULL)
\r
770 if (status->isEqualToString("running"))
\r
772 epg->setString("stop", KEY_EPG_STATUS);
\r
781 else if ((tuner < 0) && (0 <= reserve_id) && (reserve_id < 1000000))
\r
783 for (int i = 0; i < _tunerCount; ++i)
\r
785 Array *array = _reservations->arrayForKey(_tuners[i]->name());
\r
788 for (uint j = 0; j < array->count(); ++j)
\r
790 Dictionary *epg = (Dictionary *)array->objectAtIndex(j);
\r
791 if (reserve_id == epg->integerForKey(KEY_EPG_RESV_ID))
\r
793 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
794 if ((status != NULL) && status->isEqualToString("running"))
\r
796 epg->setString("stop", KEY_EPG_STATUS);
\r
800 array->removeObjectAtIndex(j);
\r
816 _reservations->writeToFile(_reservations_path, true);
\r
828 void Controller::periodic(void)
\r
830 bool need_update = false;
\r
832 #ifdef OBJC_MEMORY_CHECK
\r
833 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
840 time_t now = time(NULL);
\r
842 DebugLog2("periodic: %d", now);
\r
845 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
847 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
848 if ((array == NULL) || (array->count() == 0))
\r
855 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
858 getTimeWithEPG(epg, &start, &end);
\r
863 bool stop_need = false;
\r
866 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
867 if (status != NULL)
\r
869 if (status->isEqualToString("stop"))
\r
874 if (!status->isEqualToString("running"))
\r
878 else if (_store_remain <= DEF_DISK_REMAIN)
\r
884 if (end + OFFSET_OF_END_TIME <= now)
\r
892 DebugLog2("I try stop\n");
\r
893 int fd =_tuners[tuner]->stopRecording();
\r
896 DebugLog1("stopRecording() error.\n");
\r
900 DebugLog2("stopRecording() ok\n");
\r
901 DebugLog0("stop recording of \"%s\"", _tuners[tuner]->name());
\r
904 if (_shutdown_time == 0)
\r
906 _shutdown_time = DEF_SHUTDOWN_TIME;
\r
909 array->removeObject(epg);
\r
911 if (array->count() > 0)
\r
913 epg = (Dictionary *)array->objectAtIndex(0);
\r
919 need_update = true;
\r
931 bool start_need = false;
\r
933 getTimeWithEPG(epg, &start, &end);
\r
934 if ((start != 0) && (end != 0))
\r
936 String *status = epg->stringForKey(KEY_EPG_STATUS);
\r
937 if ((status == NULL) || !(status->isEqualToString("running")))
\r
939 if (end + OFFSET_OF_END_TIME <= now)
\r
941 // 既に終了時間が経過しているので削除する
\r
942 array->removeObject(epg);
\r
944 else if (start + OFFSET_OF_START_TIME <= now)
\r
953 DebugLog2("I need start.\n");
\r
954 String *ch = epg->stringForKey(KEY_EPG_CHANNEL);
\r
957 int channel = atoi(ch->cString());
\r
958 DebugLog2("channel: %d\n", channel);
\r
959 std::string videopath = createVideoPath(tuner);
\r
960 if (videopath != "")
\r
962 DebugLog2("videopath: %s\n", videopath.c_str());
\r
964 if (_sopen_s(&fd, videopath.c_str(),
\r
965 (_O_CREAT | _O_EXCL | _O_WRONLY | _O_BINARY | _O_TRUNC), _SH_DENYRW, (_S_IREAD | _S_IWRITE)) == 0)
\r
967 DebugLog2("open ok.\n");
\r
968 bool startResult = true;
\r
969 if (_tuners[tuner]->channel() != channel)
\r
971 if (!setChannel(tuner, channel))
\r
973 DebugLog3("setChannel() ng.");
\r
974 startResult = false;
\r
980 if (_tuners[tuner]->startRecording(fd))
\r
982 DebugLog2("startRecording() ok.");
\r
983 DebugLog0("start recording of \"%s\" to %s.", _tuners[tuner]->name(), videopath.c_str());
\r
987 DebugLog3("Tuner::startRecording() failed.");
\r
988 startResult = false;
\r
994 epg->setString("running", KEY_EPG_STATUS);
\r
1003 DebugLog0("open ng. 0x%08x\n", errno);
\r
1008 DebugLog0("Can't create videopath.\n");
\r
1013 DebugLog0("error.\n");
\r
1021 _reservations->writeToFile(_reservations_path, true);
\r
1026 String *collect_str = _props->stringForKey(KEY_COLLECT_EPG_TIME);
\r
1027 if (collect_str != NULL)
\r
1030 time_t collect_time = 0;
\r
1031 getTimeWithString(collect_str, &collect_time);
\r
1034 if ((collect_time <= now) && (now < collect_time + 1))
\r
1037 if ((_timer_epg_s == NULL) || !_timer_epg_s->valid())
\r
1039 // EPG収集用タイマ起動(ISDB-S)
\r
1040 RELEASE(_timer_epg_s);
\r
1041 _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);
\r
1042 if (_timer_epg_s != NULL)
\r
1044 _timer_epg_s->fire();
\r
1049 if ((_timer_epg_t == NULL) || !_timer_epg_t->valid())
\r
1051 // EPG収集用タイマ起動(ISDB-T)
\r
1052 RELEASE(_timer_epg_t);
\r
1053 _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);
\r
1054 if (_timer_epg_t != NULL)
\r
1056 _timer_epg_t->fire();
\r
1067 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
1068 // ただし、windowsは精度が低いので期待しないことw
\r
1071 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
1072 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
1074 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
1078 GetSystemTimeAsFileTime(&ft);
\r
1081 __time64_t now_sec;
\r
1082 __time64_t now_usec;
\r
1083 now_sec = ft.dwHighDateTime;
\r
1085 now_sec |= ft.dwLowDateTime;
\r
1086 now_sec /= 10; /*convert into microseconds*/
\r
1087 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
1088 now_usec = (now_sec % 1000000UL);
\r
1089 now_sec = now_sec / 1000000UL;
\r
1091 TimeInterval interval = (TimeInterval)now_usec;
\r
1092 interval = interval / 1000000;
\r
1093 _timer_periodic->setTimeInterval(1.005 - interval);
\r
1095 #ifdef OBJC_MEMORY_CHECK
\r
1096 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
1100 void Controller::updateKeywordsReservation()
\r
1102 DebugLog2("Controller::updateKeywordsReservation()");
\r
1107 // 予約情報からキーワード予約フラグが設定されているものを削除
\r
1108 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
1110 Array *epgs = _reservations->arrayForKey(_tuners[tuner]->name());
\r
1113 for (uint epgs_idx_offset = epgs->count(); epgs_idx_offset > 0; --epgs_idx_offset)
\r
1115 Dictionary *epg = (Dictionary *)epgs->objectAtIndex(epgs_idx_offset - 1);
\r
1116 if (epg->boolForKey(KEY_EPG_RESERVED_BY_KEYWORDS))
\r
1118 epgs->removeObject(epg);
\r
1125 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
1127 if ((keywords_info != NULL) && (_epgs != NULL) && (_epgs->dictionaryForKey(KEY_SERVICES) != NULL))
\r
1131 // _epgs からキー(サービスID)を取得
\r
1132 Array *service_id_keys = _epgs->dictionaryForKey(KEY_SERVICES)->allKeys();
\r
1135 for (uint service_id_keys_idx = 0; service_id_keys_idx < service_id_keys->count(); ++service_id_keys_idx)
\r
1138 String *service_id = (String *)service_id_keys->objectAtIndex(service_id_keys_idx);
\r
1141 String *stationName = stationNameForServiceID(service_id);
\r
1142 if (stationName == NULL)
\r
1144 // 局名が取得できなかったら次のサービスIDへ
\r
1148 // 指定サービスIDのEPGを取得
\r
1149 Array *events = _epgs->dictionaryForKey(KEY_SERVICES)->arrayForKey(service_id);
\r
1152 for (uint events_idx = 0; events_idx < events->count(); ++events_idx)
\r
1154 // 指定イベントIDのEPGを取得
\r
1155 Dictionary *epg = (Dictionary *)events->objectAtIndex(events_idx);
\r
1157 // 取得したEPGがキーワードの条件にマッチするか
\r
1158 // DebugLog0("sid: %s, eid: %s", service_id->cString(), epg->stringForKey(KEY_EPG_EVENT_ID)->cString());
\r
1161 getTimeWithString(epg->stringForKey(KEY_EPG_START), &start);
\r
1164 Array *keywords = keywords_info->allKeys();
\r
1165 for (uint keywords_idx = 0; keywords_idx < keywords->count(); ++keywords_idx)
\r
1168 String *kwd = (String *)keywords->objectAtIndex(keywords_idx);
\r
1169 // DebugLog0("kwd: %s", kwd->cString());
\r
1172 Array *kwds = kwd->componentsSeparatedByString(",");
\r
1177 // DebugLog0("check 01");
\r
1180 Dictionary *kwdinf = keywords_info->dictionaryForKey(kwd);
\r
1183 String *kwdinf_service_id = kwdinf->stringForKey(KEY_EPG_SERVICE_ID);
\r
1184 if (kwdinf_service_id != NULL)
\r
1187 String *sname = stationNameForServiceID(kwdinf_service_id);
\r
1188 if (sname != NULL)
\r
1190 if (!stationName->isEqualToString(sname))
\r
1192 // 局名が異なる場合は次のキーワードへ
\r
1197 // DebugLog0("check 02");
\r
1200 String *kwdinf_start = kwdinf->stringForKey(KEY_EPG_START);
\r
1201 if (kwdinf_start != NULL)
\r
1204 String *st = kwdinf_start->stringByAppendingString(":00");
\r
1205 time_t kwd_st, kwd_ed;
\r
1206 getTimeWithString(st, &kwd_st);
\r
1207 kwd_ed = kwd_st + 3600;
\r
1209 // 開始時刻フィルタの時刻 <= EPGの開始時刻 <= 開始時刻フィルタの時刻+60min ならOK
\r
1210 if ((kwd_st > start) || (start > kwd_ed))
\r
1216 // DebugLog0("check 03");
\r
1219 String *title = epg->stringForKey(KEY_EPG_TITLE);
\r
1220 bool title_flag = (title != NULL);
\r
1223 String *desc = epg->stringForKey(KEY_EPG_DESCRIPTION);
\r
1224 bool desc_flag = (desc != NULL);
\r
1226 // キーワード(分割)がタイトル/概要のどちらかに、全て(AND)含まれていたら予約対象とする
\r
1227 for (uint kwds_idx = 0; kwds_idx < kwds->count(); ++kwds_idx)
\r
1229 String *kw = ((String *)kwds->objectAtIndex(kwds_idx))->stringByTrimming();
\r
1232 if (title != NULL)
\r
1234 Range r = title->rangeOfString(kw);
\r
1235 if (r.location == NotFound)
\r
1237 title_flag = false;
\r
1244 Range r = desc->rangeOfString(kw);
\r
1245 if (r.location == NotFound)
\r
1247 desc_flag = false;
\r
1252 if (title_flag || desc_flag)
\r
1254 // タイトル/概要のどちらかに、キーワード(分割)が全て含まれていたので
\r
1255 // この EPG を予約対象とする
\r
1256 Dictionary *epg2 = Dictionary::dictionaryWithDictionary(epg);
\r
1259 // DebugLog0("matched kwd: %s", kwd->cString());
\r
1260 if (title != NULL)
\r
1262 // DebugLog0("title: %s", title->cString());
\r
1266 // DebugLog0("desc: %s", desc->cString());
\r
1268 epg2->setBool(true, KEY_EPG_RESERVED_BY_KEYWORDS);
\r
1269 //DebugLog0("epg2: %s", epg2->toString().c_str());
\r
1274 //DebugLog0("epg copy failed");
\r
1286 void Controller::updateSchedule()
\r
1288 DebugLog2("Controller::updateSchedule()");
\r
1294 time_t resume_time = 0;
\r
1297 String *collect_epg_time = _props->stringForKey(KEY_COLLECT_EPG_TIME);
\r
1298 if (collect_epg_time != NULL)
\r
1300 getTimeWithString(collect_epg_time, &resume_time);
\r
1304 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
1306 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
1307 if ((array == NULL) || (array->count() == 0))
\r
1313 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
1316 getTimeWithEPG(epg, &start, &end);
\r
1317 if ((start != 0) && (end != 0))
\r
1319 if (start < resume_time)
\r
1321 resume_time = start;
\r
1328 resume_time += OFFSET_OF_WAKEUP; // 起動時刻を調整
\r
1329 if (localtime_s(&resume_tm, &resume_time) == 0)
\r
1331 if (_props->stringForKey(KEY_POWER_MANAGER) != NULL)
\r
1333 char http_req[256];
\r
1334 sprintf_s(http_req, "http://%s/iptv.pl?wakeup=%04d/%02d/%02d_%02d:%02d:00",
\r
1335 _props->stringForKey(KEY_POWER_MANAGER)->cString(),
\r
1336 resume_tm.tm_year + 1900, resume_tm.tm_mon + 1,
\r
1337 resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);
\r
1338 URL *url = URL::URLWithString(http_req);
\r
1339 URLRequest *req = URLRequest::requestWithURL(url);
\r
1340 URLResponse *resp = NULL;
\r
1341 Error *error = NULL;
\r
1342 Data *data = URLConnection::sendSynchronousRequest(req, &resp, &error);
\r
1345 String *html = String::stringWithUTF8String((const char *)data->bytes());
\r
1346 if ((html != NULL) && (html->rangeOfString("<body>OK</body>").location != NotFound))
\r
1348 DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",
\r
1349 resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);
\r
1355 resetWakeSchedule();
\r
1356 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
1358 DebugLog0("set wake schedule to \"%04d/%02d/%02d %02d:%02d:00\".",
\r
1359 resume_tm.tm_year + 1900, resume_tm.tm_mon + 1, resume_tm.tm_mday, resume_tm.tm_hour, resume_tm.tm_min);
\r
1370 #pragma mark ------- チューナ制御 -------
\r
1373 void Controller::scanChannel(int tuner)
\r
1375 DebugLog2("Controller::scanChannel(%d)", tuner);
\r
1377 if ((tuner < 0) || (_tunerCount <= tuner))
\r
1379 DebugLog3("Invalid tuner: %d", tuner);
\r
1383 DebugLog0("start channel scan of \"%s\".", _tuners[tuner]->name());
\r
1388 // 設定ファイルから全チューナ情報取得
\r
1389 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
1390 if (tunersInfo == NULL)
\r
1393 tunersInfo = Dictionary::dictionaryWithCapacity(0);
\r
1394 _props->setObject(tunersInfo, KEY_TUNERS);
\r
1397 // 全チューナ情報から指定のチューナ情報を取得
\r
1398 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1399 if (tunerInfo == NULL)
\r
1402 tunerInfo = Dictionary::dictionaryWithCapacity(0);
\r
1403 tunersInfo->setObject(tunerInfo, _tuners[tuner]->name());
\r
1407 tunerInfo->setBool(false, KEY_INITIALIZED);
\r
1413 Dictionary *channels = Dictionary::dictionaryWithCapacity(0);
\r
1414 tunerInfo->setObject(channels, KEY_CHANNELS);
\r
1416 // チューナタイプにより最大チャンネル数を設定
\r
1418 Tuner::Type type = _tuners[tuner]->type();
\r
1419 if (type == Tuner::ISDB_S)
\r
1421 max_channel = Tuner::MAX_CHANNELS_ISDB_S;
\r
1425 max_channel = Tuner::MAX_CHANNELS_ISDB_T;
\r
1428 // 最終設定成功チャンネル保持用変数
\r
1429 int lastChannel = -1;
\r
1432 for (int ch = 0; ch <= max_channel; ++ch)
\r
1435 Dictionary *channelInfo = Dictionary::dictionaryWithCapacity(0);
\r
1437 // チャンネルキー(10進数:PTに対するチャンネル番号)
\r
1439 sprintf_s(chkey, sizeof(chkey), "%03d", ch);
\r
1440 channels->setObject(channelInfo, chkey);
\r
1442 // チャンネルID(論理チャンネル番号)
\r
1443 char channelID[8];
\r
1444 if (type == Tuner::ISDB_S)
\r
1448 sprintf_s(channelID, sizeof(channelID), "BS%02d", 1 + 2 * ch);
\r
1452 sprintf_s(channelID, sizeof(channelID), "ND%02d", 2 + 2 * (ch - 12));
\r
1456 sprintf_s(channelID, sizeof(channelID), "ND%02d", 1 + 2 * (ch -24));
\r
1461 static int TABLE[][3] =
\r
1471 for (i = 0; i < sizeof(TABLE)/sizeof(*TABLE); ++i)
\r
1473 if (ch <= TABLE[i][0])
\r
1475 sprintf_s(channelID, sizeof(channelID), "%s%d", TABLE[i][1] ? "C" : "", ch + TABLE[i][2] - TABLE[i][0]);
\r
1482 channelInfo->setString(channelID, KEY_CHANNEL_ID);
\r
1488 if (_tuners[tuner]->setChannel(ch))
\r
1491 DebugLog0(" CH %s: OK", chkey);
\r
1494 channelInfo->setBool(true, KEY_ENABLED);
\r
1497 Extractor *extractor = Extractor::alloc()->init();
\r
1498 _tuners[tuner]->setListener(extractor);
\r
1500 Dictionary *stationInfo = extractor->stationInfo();
\r
1501 if (stationInfo != NULL)
\r
1503 if (stationInfo->stringForKey(KEY_NAME) != NULL)
\r
1505 channelInfo->setString(stationInfo->stringForKey(KEY_NAME), KEY_NAME);
\r
1507 if (stationInfo->objectForKey(KEY_SERVICES) != NULL)
\r
1509 channelInfo->setObject(stationInfo->objectForKey(KEY_SERVICES), KEY_SERVICES);
\r
1511 if (channelInfo->stringForKey(KEY_NAME) != NULL)
\r
1513 DebugLog0(" Name: %s", channelInfo->stringForKey(KEY_NAME)->cString());
\r
1517 _tuners[tuner]->setListener(NULL);
\r
1518 extractor->release();
\r
1525 DebugLog0(" CH %s: NG", chkey);
\r
1534 tunerInfo->setBool(true, KEY_INITIALIZED);
\r
1536 // 設定が成功したチャンネルが有るか
\r
1537 if (lastChannel >= 0)
\r
1540 tunerInfo->setBool(true, KEY_ENABLED);
\r
1542 // 最終チャンネルをステータスファイルに設定
\r
1543 Dictionary *tunersInfo = _status->dictionaryForKey(KEY_TUNERS);
\r
1544 if (tunersInfo == NULL)
\r
1546 tunersInfo = Dictionary::dictionaryWithCapacity(0);
\r
1547 _status->setObject(tunersInfo, KEY_TUNERS);
\r
1550 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1551 if (tunerInfo == NULL)
\r
1553 tunerInfo = Dictionary::dictionaryWithCapacity(0);
\r
1554 tunersInfo->setObject(tunerInfo, _tuners[tuner]->name());
\r
1557 tunerInfo->setInteger(lastChannel, KEY_CHANNEL);
\r
1559 _status->writeToFile(_status_path, true);
\r
1563 _props->writeToFile(_props_path, true);
\r
1569 int Controller::getChannel(int tuner)
\r
1571 DebugLog2("Controller::getChannel()");
\r
1575 if ((0 <= tuner) && (tuner < _tunerCount))
\r
1580 Dictionary *tunersInfo = _status->dictionaryForKey(KEY_TUNERS);
\r
1581 if (tunersInfo != NULL)
\r
1583 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1584 if (tunerInfo != NULL)
\r
1586 channel = tunerInfo->integerForKey(KEY_CHANNEL);
\r
1597 bool Controller::setChannel(int tuner, int channel)
\r
1599 DebugLog2("Controller::setChannel()");
\r
1601 bool result = false;
\r
1603 if ((0 <= tuner) && (tuner < _tunerCount))
\r
1608 if (!_tuners[tuner]->isLocked())
\r
1610 Dictionary *tunersInfo = _status->dictionaryForKey(KEY_TUNERS);
\r
1611 if (tunersInfo == NULL)
\r
1613 tunersInfo = Dictionary::dictionaryWithCapacity(0);
\r
1614 _status->setObject(tunersInfo, KEY_TUNERS);
\r
1617 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
1618 if (tunerInfo == NULL)
\r
1620 tunerInfo = Dictionary::dictionaryWithCapacity(0);
\r
1621 tunersInfo->setObject(tunerInfo, _tuners[tuner]->name());
\r
1624 if (channel != _tuners[tuner]->channel())
\r
1626 if (_tuners[tuner]->setChannel(channel))
\r
1628 tunerInfo->setInteger(channel, KEY_CHANNEL);
\r
1630 _status->writeToFile(_status_path, true);
\r
1636 DebugLog0("set channel failed. %d, %d", tuner, channel);
\r
1650 #pragma mark ------- システム関連 周期処理 -------
\r
1654 // チューナ(streaming)制御/システム関連 周期処理
\r
1656 void Controller::periodic_2(void)
\r
1658 time_t now = time(NULL);
\r
1664 // マッピング(UDPPort:tuner,ch)情報取得
\r
1665 Dictionary *mapping = NULL;
\r
1666 if ((_streaming_ctrls != NULL) && ((mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID)) != NULL))
\r
1671 // どれだけ使用中なのか不明なので、まずは必要サイズを調べる
\r
1673 if (GetExtendedUdpTable(NULL, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == ERROR_INSUFFICIENT_BUFFER)
\r
1675 // ERROR_INSUFFICIENT_BUFFER の場合、必要なバッファサイズが size に格納される
\r
1678 PMIB_UDPTABLE_OWNER_PID udptable = (PMIB_UDPTABLE_OWNER_PID)malloc(size);
\r
1679 if (udptable != NULL)
\r
1684 if (GetExtendedUdpTable(udptable, &size, true, AF_INET, UDP_TABLE_OWNER_PID, 0) == NO_ERROR)
\r
1687 DebugLog3("udptable->dwNumEntries: %d", udptable->dwNumEntries);
\r
1690 Dictionary *using_port = _streaming_ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
1691 if (using_port != NULL)
\r
1694 Array *using_ports = using_port->allKeys();
\r
1695 if (using_ports != NULL)
\r
1698 for (uint i = 0; i < using_ports->count(); ++i)
\r
1701 bool stop_need = true;
\r
1704 for (uint j = 0; j < udptable->dwNumEntries; ++j)
\r
1706 if (((String *)using_ports->objectAtIndex(i))->intValue() == ntohs((WORD)udptable->table[j].dwLocalPort))
\r
1709 stop_need = false;
\r
1718 String *tuner_and_service_id = mapping->stringForKey((String *)using_ports->objectAtIndex(i));
\r
1719 if (tuner_and_service_id != NULL)
\r
1722 Range r = tuner_and_service_id->rangeOfString("_");
\r
1723 if (r.location != NotFound)
\r
1725 int tuner = tuner_and_service_id->substringToIndex(r.location)->intValue();
\r
1726 int service_id = tuner_and_service_id->substringFromIndex(r.location + 1)->intValue();
\r
1727 DebugLog3("tuner: %d, service_id: %d", tuner, service_id);
\r
1729 DebugLog0("auto streaming stop: %s", ((String *)using_ports->objectAtIndex(i))->cString());
\r
1731 _tuners[tuner]->stopStreaming();
\r
1732 using_port->removeObjectForKey((String *)using_ports->objectAtIndex(i));
\r
1742 for (uint i = 0; i < udptable->dwNumEntries; ++i)
\r
1746 sprintf_s(port, "%d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
1747 DebugLog3("port = %s", port);
\r
1750 String *tuner_and_service_id = mapping->stringForKey(port);
\r
1751 if (tuner_and_service_id != NULL)
\r
1753 // 取得OK: 監視対象ポートが使用されている
\r
1756 bool auto_streaming = false;
\r
1757 char exec_path[MAX_PATH];
\r
1758 memset(exec_path, 0, sizeof(exec_path));
\r
1761 size_t returnValue;
\r
1762 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, udptable->table[i].dwOwningPid);
\r
1763 if (hProcess != NULL)
\r
1765 TCHAR exec[MAX_PATH];
\r
1766 memset(exec, 0, sizeof(exec));
\r
1767 DWORD len = sizeof(exec) - 1;
\r
1770 if (QueryFullProcessImageName(hProcess, 0, exec, &len))
\r
1773 if (wcstombs_s(&returnValue, exec_path, sizeof(exec_path), exec, _TRUNCATE) == 0)
\r
1777 // とりあえず、、、現状は "ffmpeg.exe" / "vlc.exe" / "Kodi.exe" があったら auto_streaming を true にする
\r
1778 if ((strstr(exec_path, "ffmpeg.exe") != NULL) ||
\r
1779 (strstr(exec_path, "vlc.exe") != NULL) ||
\r
1780 (strstr(exec_path, "Kodi.exe") != NULL))
\r
1782 auto_streaming = true;
\r
1788 CloseHandle(hProcess);
\r
1791 if (auto_streaming)
\r
1794 Range r = tuner_and_service_id->rangeOfString("_");
\r
1795 if (r.location != NotFound)
\r
1797 int tuner = tuner_and_service_id->substringToIndex(r.location)->intValue();
\r
1798 int service_id = tuner_and_service_id->substringFromIndex(r.location + 1)->intValue();
\r
1799 DebugLog3("tuner: %d, service_id: %d", tuner, service_id);
\r
1803 if (_streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL) != NULL)
\r
1805 channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL)->integerForKey(tuner_and_service_id);
\r
1812 if (!_tuners[tuner]->isLocked())
\r
1816 if (_tuners[tuner]->channel() != channel)
\r
1818 setChannel(tuner, channel);
\r
1821 SOCKADDR_IN dst_addr;
\r
1822 dst_addr.sin_family = AF_INET;
\r
1823 dst_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
\r
1824 dst_addr.sin_port = (WORD)udptable->table[i].dwLocalPort;
\r
1826 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
1829 DebugLog0("auto streaming start: %d", ntohs((WORD)udptable->table[i].dwLocalPort));
\r
1832 using_port = _streaming_ctrls->dictionaryForKey(KEY_UDP_IN_USE);
\r
1833 if (using_port == NULL)
\r
1835 using_port = Dictionary::dictionaryWithCapacity(0);
\r
1836 _streaming_ctrls->setObject(using_port, KEY_UDP_IN_USE);
\r
1838 using_port->setBool(true, port);
\r
1859 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
1860 if (hls_info != NULL)
\r
1862 for (int i = 0; i < _tunerCount; ++i)
\r
1865 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[i]->name());
\r
1866 if (hls_info_tuner != NULL)
\r
1868 int counter = hls_info_tuner->integerForKey(KEY_COUNTER);
\r
1871 hls_info_tuner->setInteger(counter + 1, KEY_COUNTER);
\r
1875 hls_info->removeObjectForKey(_tuners[i]->name());
\r
1882 if ((now % 60) == 10)
\r
1884 if (isIdleState())
\r
1887 if (((_timer_epg_s != NULL) && _timer_epg_s->valid()) ||
\r
1888 ((_timer_epg_t != NULL) && _timer_epg_t->valid()))
\r
1896 DebugLog0("_idle_count: %d, _shutdown_time: %d", _idle_count, ((_shutdown_time == 0) ? DEF_SHUTDOWN_TIME_INIT : _shutdown_time));
\r
1897 if (_idle_count >= ((_shutdown_time == 0) ? DEF_SHUTDOWN_TIME_INIT : _shutdown_time))
\r
1901 bool shutdown = (_props->stringForKey(KEY_POWER_MANAGER) != NULL);
\r
1906 Service::shutdown();
\r
1927 if ((now % 60) == 20)
\r
1930 _store_remain = FileManager::freeSpaceForPath(_store_path);
\r
1936 // 1/100秒単位が 0 に近くなるように次回T.O.を微調整
\r
1939 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
\r
1940 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000Ui64;
\r
1942 static const __time64_t DELTA_EPOCH_IN_MICROSECS = 11644473600000000ULL;
\r
1946 GetSystemTimeAsFileTime(&ft);
\r
1949 __time64_t now_sec;
\r
1950 __time64_t now_usec;
\r
1951 now_sec = ft.dwHighDateTime;
\r
1953 now_sec |= ft.dwLowDateTime;
\r
1954 now_sec /= 10; /*convert into microseconds*/
\r
1955 now_sec -= DELTA_EPOCH_IN_MICROSECS;
\r
1956 now_usec = (now_sec % 1000000UL);
\r
1957 now_sec = now_sec / 1000000UL;
\r
1959 TimeInterval interval = (TimeInterval)now_usec;
\r
1960 interval = interval / 1000000;
\r
1961 _timer_periodic_2->setTimeInterval(1.005 - interval);
\r
1966 #pragma mark ------- HTTP制御 -------
\r
1969 static std::string epg_regist_form(Dictionary *epg)
\r
1971 DebugLog3("epg_regist_form() start.");
\r
1975 if ((epg != NULL) &&
\r
1976 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
1977 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
1978 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
1979 (epg->stringForKey(KEY_EPG_END) != NULL) &&
\r
1980 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
1981 (epg->stringForKey(KEY_EPG_TITLE) != NULL))
\r
1983 epgs += "<form id=\"";
\r
1985 epgs += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
1987 epgs += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
1988 epgs += "\" title=\"";
\r
1989 epgs += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
1991 epgs += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
1992 epgs += "\" class=\"panel\" action=\"regist.cgi\" method=\"GET\" target=\"_self\" onclick='return confirm(\"Is it ok?\");'>";
\r
1996 epgs += LocalizedString(KEY_I18N_Broadcasting_Time, NULL)->cString();
\r
1998 epgs += "<fieldset>";
\r
1999 epgs += "<p class=\"normalText\"> ";
\r
2000 epgs += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2002 epgs += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2004 epgs += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2006 epgs += "</fieldset>";
\r
2010 epgs += LocalizedString(KEY_I18N_Program_Title, NULL)->cString();
\r
2012 epgs += "<fieldset>";
\r
2013 epgs += "<p class=\"normalText\"> ";
\r
2014 epgs += epg->stringForKey(KEY_EPG_TITLE)->cString();
\r
2016 epgs += "</fieldset>";
\r
2019 if (epg->stringForKey(KEY_EPG_DESCRIPTION) != NULL)
\r
2022 epgs += LocalizedString(KEY_I18N_Description, NULL)->cString();
\r
2024 epgs += "<fieldset>";
\r
2025 epgs += "<p class=\"normalText\"> ";
\r
2026 epgs += epg->stringForKey(KEY_EPG_DESCRIPTION)->cString();
\r
2028 epgs += "</fieldset>";
\r
2032 epgs += "<input type=\"hidden\" name=\"service_id\" value=\"";
\r
2033 epgs += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2035 epgs += "<input type=\"hidden\" name=\"event_id\" value=\"";
\r
2036 epgs += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2038 epgs += "<input class=\"redButton\" type=\"submit\" value=\"";
\r
2039 epgs += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
2041 // epgs += "<a class=\"redButton\" type=\"submit\">";
\r
2042 // epgs += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
2043 // epgs += "</a>";
\r
2044 epgs += "</form>";
\r
2050 HTTPResponse *responseWithDictionary(HTTPRequest *request, Dictionary *dictionary)
\r
2052 HTTPResponse *result = NULL;
\r
2053 if ((request != NULL) && (dictionary != NULL))
\r
2055 std::string xml = dictionary->toString();
\r
2058 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
2061 // Content-Encoding
\r
2064 header->setFieldBodyWithName("application/xml", "Content-Type");
\r
2066 // Tranfer-Encoding
\r
2068 header->setFieldBodyWithName(String::stringWithFormat("%I64u", xml.length()), "Content-Length");
\r
2071 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(xml.c_str()));
\r
2074 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
2077 if (message != NULL)
\r
2079 result = HTTPResponse::alloc()->init();
\r
2080 result->autorelease();
\r
2081 result->setVersion(request->version());
\r
2082 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
2083 result->setStatus(200);
\r
2084 result->setMessage(message);
\r
2091 // positive response by XML
\r
2092 HTTPResponse *responseForSuccess(HTTPRequest *request)
\r
2094 Dictionary *dict = Dictionary::dictionaryWithCapacity(0);
\r
2095 dict->setString("Success", KEY_RESULT);
\r
2096 return responseWithDictionary(request, dict);
\r
2099 // negative response by XML
\r
2100 HTTPResponse *responseForFailed(HTTPRequest *request)
\r
2102 Dictionary *dict = Dictionary::dictionaryWithCapacity(0);
\r
2103 dict->setString("Failed", KEY_RESULT);
\r
2104 return responseWithDictionary(request, dict);
\r
2107 HTTPResponse *Controller::responseWithHTML(HTTPRequest *request, String *html)
\r
2109 HTTPResponse *result = NULL;
\r
2110 if ((html != NULL) && (request != NULL))
\r
2113 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
2116 // Content-Encoding
\r
2119 header->setFieldBodyWithName("text/html", "Content-Type");
\r
2121 // Tranfer-Encoding
\r
2123 header->setFieldBodyWithName(String::stringWithFormat("%I64u", html->length()), "Content-Length");
\r
2126 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(html);
\r
2129 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
2132 if (message != NULL)
\r
2134 // result = HTTPResponse::response();
\r
2135 result = HTTPResponse::alloc()->init();
\r
2136 result->setVersion(request->version());
\r
2137 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
2138 result->setStatus(200);
\r
2139 result->setMessage(message);
\r
2140 result->autorelease();
\r
2147 HTTPResponse *Controller::responseWithUTF8Text(HTTPRequest *request, String *text)
\r
2149 HTTPResponse *result = NULL;
\r
2150 if ((text != NULL) && (request != NULL))
\r
2153 InternetTextMessageHeader *header = InternetTextMessageHeader::alloc()->init();
\r
2156 // Content-Encoding
\r
2159 header->setFieldBodyWithName("text/plane; charset=UTF-8", "Content-Type");
\r
2161 // Tranfer-Encoding
\r
2163 header->setFieldBodyWithName(String::stringWithFormat("%I64u", text->length()), "Content-Length");
\r
2166 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(text);
\r
2169 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
2172 if (message != NULL)
\r
2174 // result = HTTPResponse::response();
\r
2175 result = HTTPResponse::alloc()->init();
\r
2176 result->setVersion(request->version());
\r
2177 result->setReason(NET::HTTPDaemon::reasonForStatus(200));
\r
2178 result->setStatus(200);
\r
2179 result->setMessage(message);
\r
2180 result->autorelease();
\r
2187 HTTPResponse *Controller::responseByResult(HTTPRequest *request, bool result)
\r
2189 HTTPResponse *retval = NULL;
\r
2193 String *ref = NULL;
\r
2194 InternetTextMessage *msg = request->message();
\r
2197 InternetTextMessageHeader *header = msg->header();
\r
2198 if (header != NULL)
\r
2200 String *field_referer = header->fieldBodyForName("Referer");
\r
2201 if (field_referer != NULL)
\r
2203 String *field_host = header->fieldBodyForName("Host");
\r
2204 if (field_host != NULL)
\r
2206 std::string tmp = "^http://";
\r
2207 tmp += field_host->cString();
\r
2208 tmp += "/(programs_(t|s)_\\d+|reservation)\\.html$";
\r
2209 iui = field_referer->isMatch(tmp.c_str());
\r
2210 DebugLog0("tmp: %s", tmp.c_str());
\r
2211 DebugLog0("ref: %s", field_referer->cString());
\r
2219 String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");
\r
2220 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2223 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", "Result");
\r
2224 std::string contents;
\r
2225 std::string reservations;
\r
2226 contents += "<div id=\"home\" class=\"panel\" title=\"Result\" selected=\"true\">";
\r
2229 contents += "<h2>Success</h2>";
\r
2233 contents += "<h2>Failed</h2>";
\r
2235 contents += "</div>";
\r
2237 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2238 retval = responseWithHTML(request, html);
\r
2245 retval = responseForSuccess(request);
\r
2249 retval = responseForFailed(request);
\r
2256 HTTPResponse *Controller::responseForMain(HTTPRequest *request, SOCKADDR_IN *client)
\r
2258 DebugLog2("Controller::responseForMain()");
\r
2260 HTTPResponse *result = NULL;
\r
2261 while ((request != NULL) && (client != NULL))
\r
2263 String *path = _httpd->rootPath();
\r
2266 DebugLog3("_httpd->rootPath() ng.");
\r
2270 path = path->stringByAppendingPathComponent("template1.html");
\r
2273 DebugLog3("path->stringByAppendingPathComponent() ng.");
\r
2277 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2280 DebugLog3("String::stringWithContentsOfFile() ng.");
\r
2284 String *server_name = _props->stringForKey(KEY_NAME);
\r
2285 if (server_name == NULL)
\r
2287 DebugLog3("_props->stringForKey(KEY_NAME) ng.");
\r
2291 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", server_name);
\r
2294 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2298 html = html->stringByReplacingOccurrencesOfString("%%PAGE_TITLE%%", LocalizedString(KEY_I18N_Main_Menu, NULL));
\r
2301 DebugLog3("html->stringByReplacingOccurrencesOfString() ng.");
\r
2304 std::string contents;
\r
2305 contents += "<div id=\"home\" class=\"panel\" selected=\"true\">";
\r
2306 contents += "<ul>";
\r
2307 contents += "<li><a target=\"_self\" href=\"/programs.html\">";
\r
2308 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2309 contents += "</a></li>";
\r
2310 contents += "<li><a target=\"_self\" href=\"/tv.html\">";
\r
2311 contents += LocalizedString(KEY_I18N_TV, NULL)->cString();
\r
2312 contents += "</a></li>";
\r
2313 contents += "<li><a target=\"_self\" href=\"/video.html\">";
\r
2314 contents += LocalizedString(KEY_I18N_Video, NULL)->cString();
\r
2315 contents += "</a></li>";
\r
2316 contents += "<li><a target=\"_self\" href=\"/reservation.html\">";
\r
2317 contents += LocalizedString(KEY_I18N_Reservation, NULL)->cString();
\r
2318 contents += "</a></li>";
\r
2319 contents += "</ul>";
\r
2321 contents += "<ul>";
\r
2322 contents += "<li><a target=\"_self\" href=\"/exec_vlc.html\">VLC media player";
\r
2323 contents += "</ul>";
\r
2325 contents += "<ul>";
\r
2326 contents += "<li><a target=\"_self\" href=\"/status.html\">";
\r
2327 contents += LocalizedString(KEY_I18N_Tuner_Status, NULL)->cString();
\r
2328 contents += "</a></li>";
\r
2329 contents += "</ul>";
\r
2330 contents += "<center><a target=\"_self\" href=\"/iptd.log\">Ver. ";
\r
2331 contents += VERSION;
\r
2332 contents += "</a></center>";
\r
2333 contents += "</div>";
\r
2335 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2338 result = responseWithHTML(request, html);
\r
2347 HTTPResponse *Controller::responseForPrograms(HTTPRequest *request, SOCKADDR_IN *client)
\r
2349 DebugLog2("Controller::responseForPrograms() start.");
\r
2351 HTTPResponse *result = NULL;
\r
2352 while ((request != NULL) && (client != NULL))
\r
2354 String *path = _httpd->rootPath();
\r
2357 DebugLog3("_httpd->rootPath() ng.");
\r
2361 path = path->stringByAppendingPathComponent("template2.html");
\r
2364 DebugLog0("path->stringByAppendingPathComponent() ng.");
\r
2368 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2371 DebugLog0("String::stringWithContentsOfFile() ng.");
\r
2375 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Programs, NULL));
\r
2378 DebugLog0("html->stringByReplacingOccurrencesOfString() ng.");
\r
2382 std::string contents;
\r
2384 String *uri = request->URI();
\r
2385 if (uri->isMatch("^/programs\\.html$"))
\r
2387 contents += "<ul id=\"home\" title=\"";
\r
2388 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2389 contents += "\" selected=\"true\">";
\r
2392 contents += "<li>";
\r
2393 contents += "<a target=\"_self\" href=\"/programs_t.html\">";
\r
2394 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2395 contents += "</a></li>";
\r
2397 contents += "<li>";
\r
2398 contents += "<a target=\"_self\" href=\"/programs_s.html\">";
\r
2399 contents += "BS/CS";
\r
2400 contents += "</a></li>";
\r
2402 contents += "</ul>";
\r
2404 else if (uri->isMatch("^/programs_t\\.html$"))
\r
2406 contents += "<ul id=\"home\" title=\"";
\r
2407 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2408 contents += "\" selected=\"true\">";
\r
2411 Array *stations = stationInfos(Tuner::ISDB_T);
\r
2412 for (uint i = 0; i < stations->count(); ++i)
\r
2414 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2415 if ((station != NULL) &&
\r
2416 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2417 (station->stringForKey(KEY_NAME) != NULL))
\r
2419 contents += "<li>";
\r
2420 contents += "<a target=\"_self\" href=\"/programs_t_";
\r
2421 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2422 contents += ".html\">";
\r
2423 contents += station->stringForKey(KEY_NAME)->cString();
\r
2424 contents += "</a></li>";
\r
2428 contents += "</ul>";
\r
2430 else if (uri->isMatch("^/programs_s\\.html$"))
\r
2432 contents += "<ul id=\"home\" title=\"";
\r
2433 contents += "BS/CS";
\r
2434 contents += "\" selected=\"true\">";
\r
2436 Array *stations = stationInfos(Tuner::ISDB_S);
\r
2437 for (uint i = 0; i < stations->count(); ++i)
\r
2439 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2440 if ((station != NULL) &&
\r
2441 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2442 (station->stringForKey(KEY_NAME) != NULL))
\r
2444 contents += "<li>";
\r
2445 contents += "<a target=\"_self\" href=\"/programs_s_";
\r
2446 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2447 contents += ".html\">";
\r
2448 contents += station->stringForKey(KEY_NAME)->cString();
\r
2449 contents += "</a></li>";
\r
2453 contents += "</ul>";
\r
2455 else if (uri->isMatch("^/programs_(t|s)_.+\\.html$"))
\r
2457 Array *stations = NULL;
\r
2458 String *ch_id = NULL;
\r
2459 if (uri->isMatch("programs_t_"))
\r
2461 stations = stationInfos(Tuner::ISDB_T);
\r
2462 ch_id = uri->stringByReplacingOccurrencesOfString("/programs_t_", "");
\r
2463 ch_id = ch_id->stringByReplacingOccurrencesOfString(".html", "");
\r
2467 stations = stationInfos(Tuner::ISDB_S);
\r
2468 ch_id = uri->stringByReplacingOccurrencesOfString("/programs_s_", "");
\r
2469 ch_id = ch_id->stringByReplacingOccurrencesOfString(".html", "");
\r
2472 for (uint i = 0; i < stations->count(); ++i)
\r
2474 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2475 if ((station != NULL) &&
\r
2476 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2477 station->stringForKey(KEY_CHANNEL_ID)->isEqualToString(ch_id))
\r
2481 contents += "<ul id=\"home\" title=\"";
\r
2482 contents += station->stringForKey(KEY_NAME)->cString();
\r
2483 contents += "\" selected=\"true\">";
\r
2485 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2486 for (uint i = 0; i < programs->count(); ++i)
\r
2488 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2489 if ((epg != NULL) &&
\r
2490 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2491 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2492 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2493 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2494 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2496 contents += "<li>";
\r
2497 contents += "<a href=\"#epg_";
\r
2498 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2500 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2501 contents += "\">";
\r
2502 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2503 contents += " ";
\r
2504 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2506 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2507 contents += "</a></li>";
\r
2509 epgs += epg_regist_form(epg);
\r
2513 contents += "</ul>";
\r
2522 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2525 result = responseWithHTML(request, html);
\r
2535 HTTPResponse *result = NULL;
\r
2536 while ((request != NULL) && (client != NULL))
\r
2538 String *path = _httpd->rootPath();
\r
2541 DebugLog0("_httpd->rootPath() ng.");
\r
2545 path = path->stringByAppendingPathComponent("template2.html");
\r
2548 DebugLog0("path->stringByAppendingPathComponent() ng.");
\r
2552 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2555 DebugLog0("String::stringWithContentsOfFile() ng.");
\r
2559 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Programs, NULL));
\r
2562 DebugLog0("html->stringByReplacingOccurrencesOfString() ng.");
\r
2566 std::string contents;
\r
2569 contents += "<ul id=\"home\" title=\"";
\r
2570 contents += LocalizedString(KEY_I18N_Programs, NULL)->cString();
\r
2571 contents += "\" selected=\"true\">";
\r
2573 contents += "<li>";
\r
2574 contents += "<a href=\"#isdb_t\">";
\r
2575 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2576 contents += "</a></li>";
\r
2578 contents += "<li>";
\r
2579 contents += "<a href=\"#isdb_s\">";
\r
2580 contents += "BS/CS";
\r
2581 contents += "</a></li>";
\r
2583 contents += "</ul>";
\r
2586 contents += "<ul id=\"isdb_t\" title=\"";
\r
2587 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2588 contents += "\">";
\r
2589 Array *stations = stationInfos(Tuner::ISDB_T);
\r
2590 for (uint i = 0; i < stations->count(); ++i)
\r
2592 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2593 if ((station != NULL) &&
\r
2594 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2595 (station->stringForKey(KEY_NAME) != NULL))
\r
2597 contents += "<li>";
\r
2598 contents += "<a href=\"#isdb_t_";
\r
2599 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2600 contents += "\">";
\r
2601 contents += station->stringForKey(KEY_NAME)->cString();
\r
2602 contents += "</a></li>";
\r
2605 contents += "</ul>";
\r
2608 for (uint i = 0; i < stations->count(); ++i)
\r
2610 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2611 if ((station != NULL) &&
\r
2612 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2613 (station->stringForKey(KEY_NAME) != NULL))
\r
2616 contents += "<ul id=\"isdb_t_";
\r
2617 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2618 contents += "\" title=\"";
\r
2619 contents += station->stringForKey(KEY_NAME)->cString();
\r
2620 contents += "\">";
\r
2622 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2623 for (uint i = 0; i < programs->count(); ++i)
\r
2625 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2626 if ((epg != NULL) &&
\r
2627 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2628 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2629 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2630 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2631 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2633 contents += "<li>";
\r
2634 contents += "<a href=\"#epg_";
\r
2635 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2637 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2638 contents += "\">";
\r
2639 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2640 contents += " ";
\r
2641 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2643 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2644 contents += "</a></li>";
\r
2646 epgs += epg_regist_form(epg);
\r
2649 contents += "</ul>";
\r
2654 contents += "<ul id=\"isdb_s\" title=\"";
\r
2655 contents += LocalizedString(KEY_I18N_Digital_Terrestrial_Television_Broadcasting, NULL)->cString();
\r
2656 contents += "\">";
\r
2657 stations = stationInfos(Tuner::ISDB_S);
\r
2658 for (uint i = 0; i < stations->count(); ++i)
\r
2660 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2661 if ((station != NULL) &&
\r
2662 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2663 (station->stringForKey(KEY_NAME) != NULL))
\r
2665 contents += "<li>";
\r
2666 contents += "<a href=\"#isdb_s_";
\r
2667 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2668 contents += "\">";
\r
2669 contents += station->stringForKey(KEY_NAME)->cString();
\r
2670 contents += "</a></li>";
\r
2673 contents += "</ul>";
\r
2676 for (uint i = 0; i < stations->count(); ++i)
\r
2678 Dictionary *station = (Dictionary *)stations->objectAtIndex(i);
\r
2679 if ((station != NULL) &&
\r
2680 (station->stringForKey(KEY_CHANNEL_ID) != NULL) &&
\r
2681 (station->stringForKey(KEY_NAME) != NULL))
\r
2683 contents += "<ul id=\"isdb_s_";
\r
2684 contents += station->stringForKey(KEY_CHANNEL_ID)->cString();
\r
2685 contents += "\" title=\"";
\r
2686 contents += station->stringForKey(KEY_NAME)->cString();
\r
2687 contents += "\">";
\r
2689 Array *programs = programsForServices(station->arrayForKey(KEY_SERVICES));
\r
2690 for (uint i = 0; i < programs->count(); ++i)
\r
2692 Dictionary *epg = (Dictionary *)programs->objectAtIndex(i);
\r
2693 if ((epg != NULL) &&
\r
2694 (epg->stringForKey(KEY_EPG_SERVICE_ID) != NULL) &&
\r
2695 (epg->stringForKey(KEY_EPG_EVENT_ID) != NULL) &&
\r
2696 (epg->stringForKey(KEY_EPG_DATE) != NULL) &&
\r
2697 (epg->stringForKey(KEY_EPG_START) != NULL) &&
\r
2698 (epg->stringForKey(KEY_EPG_END) != NULL))
\r
2700 contents += "<li>";
\r
2701 contents += "<a href=\"#epg_";
\r
2702 contents += epg->stringForKey(KEY_EPG_SERVICE_ID)->cString();
\r
2704 contents += epg->stringForKey(KEY_EPG_EVENT_ID)->cString();
\r
2705 contents += "\">";
\r
2706 contents += epg->stringForKey(KEY_EPG_DATE)->substringFromIndex(5)->cString();
\r
2707 contents += " ";
\r
2708 contents += epg->stringForKey(KEY_EPG_START)->substringToIndex(5)->cString();
\r
2710 contents += epg->stringForKey(KEY_EPG_END)->substringToIndex(5)->cString();
\r
2711 contents += "</a></li>";
\r
2713 epgs += epg_regist_form(epg);
\r
2716 contents += "</ul>";
\r
2721 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
2724 result = responseWithHTML(request, html);
\r
2733 HTTPResponse *Controller::responseForReservation(HTTPRequest *request, SOCKADDR_IN *client)
\r
2735 DebugLog2("Controller::responseForReservation() start.");
\r
2740 HTTPResponse *result = NULL;
\r
2741 while ((request != NULL) && (client != NULL))
\r
2743 // create array of reservations sorted by seq_id.
\r
2744 Array *array = Array::arrayWithCapacity(0);
\r
2745 for (int i = 0; i < _tunerCount; ++i)
\r
2747 Array *tmp = _reservations->arrayForKey(_tuners[i]->name());
\r
2752 for (uint idx = 0; idx < tmp->count(); ++idx)
\r
2754 Dictionary *epg = (Dictionary *)tmp->objectAtIndex(idx);
\r
2762 getTimeWithEPG(epg, &epg_start, &tmp_end);
\r
2764 bool inserted = false;
\r
2765 for (uint j = 0; j < array->count(); ++j)
\r
2767 Dictionary *epg2 = (Dictionary *)array->objectAtIndex(j);
\r
2773 time_t epg2_start;
\r
2774 getTimeWithEPG(epg2, &epg2_start, &tmp_end);
\r
2776 if (epg_start <= epg2_start)
\r
2778 array->insertObject(epg, j);
\r
2786 array->addObject(epg);
\r
2791 String *path = _httpd->rootPath();
\r
2797 path = path->stringByAppendingPathComponent("template2.html");
\r
2803 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
2809 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Reservation, NULL));
\r
2815 std::string contents;
\r
2816 std::string reservations;
\r
2817 contents += "<ul id=\"home\" title=\"";
\r
2818 contents += LocalizedString(KEY_I18N_Reservation, NULL)->cString();
\r
2819 contents += "\" selected=\"true\">";
\r
2822 contents += "<li><a href=\"#tuners\">";
\r
2823 contents += "<font color=\"blue\">[";
\r
2824 contents += LocalizedString(KEY_I18N_Tuner, NULL)->cString();
\r
2825 contents += "]</font>";
\r
2826 contents += "</a></li>";
\r
2832 contents += "<li><a href=\"#new_reservation\">";
\r
2833 contents += "<font color=\"red\">[";
\r
2834 contents += LocalizedString(KEY_I18N_New_Reservation, NULL)->cString();
\r
2835 contents += "]</font>";
\r
2836 contents += "</a></li>";
\r
2841 contents += "<li><a href=\"#keywords\">";
\r
2842 contents += "<font color=\"blue\">[";
\r
2843 contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
2844 contents += "]</font>";
\r
2845 contents += "</a></li>";
\r
2850 for (uint i = 0; i < array->count(); ++i)
\r
2852 Dictionary *epg = (Dictionary *)array->objectAtIndex(i);
\r
2854 sprintf_s(seq_id, "%06d", epg->integerForKey(KEY_EPG_RESV_ID) % 1000000);
\r
2855 contents += "<li>";
\r
2856 contents += "<a href=\"#seqid";
\r
2857 contents += seq_id;
\r
2858 contents += "\">";
\r
2859 String *title = epg->stringForKey(KEY_EPG_TITLE);
\r
2860 if (title != NULL)
\r
2862 contents += title->cString();
\r
2868 Controller::getTimeWithEPG(epg, &start, &end);
\r
2870 if (localtime_s(&tm, &start) == 0)
\r
2872 char date_time[24];
\r
2873 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
2874 contents += date_time;
\r
2878 contents += seq_id;
\r
2881 contents += "</a></li>";
\r
2884 reservations += "<div id=\"";
\r
2885 reservations += "seqid";
\r
2886 reservations += seq_id;
\r
2887 reservations += "\" title=\"";
\r
2888 reservations += "xxxxxx";
\r
2889 reservations += "\" class=\"panel\">";
\r
2891 //reservations += "<h2>Status</h2>";
\r
2892 reservations += "<fieldset>";
\r
2895 reservations += "<div class=\"row\">";
\r
2896 reservations += "<label>Date</label>";
\r
2897 reservations += "<span>";
\r
2898 String *tmp = epg->stringForKey(KEY_EPG_DATE);
\r
2899 reservations += tmp->cString();
\r
2900 reservations += "</span>";
\r
2901 reservations += "</div>";
\r
2903 reservations += "<div class=\"row\">";
\r
2904 reservations += "<label>Start</label>";
\r
2905 reservations += "<span>";
\r
2906 tmp = epg->stringForKey(KEY_EPG_START);
\r
2907 reservations += tmp->cString();
\r
2908 reservations += "</span>";
\r
2909 reservations += "</div>";
\r
2911 reservations += "<div class=\"row\">";
\r
2912 reservations += "<label>End</label>";
\r
2913 reservations += "<span>";
\r
2914 tmp = epg->stringForKey(KEY_EPG_END);
\r
2915 reservations += tmp->cString();
\r
2916 reservations += "</span>";
\r
2917 reservations += "</div>";
\r
2919 reservations += "</fieldset>";
\r
2921 reservations += "<a class=\"whiteButton\" type=\"submit\" href=\"/cancel.cgi?";
\r
2922 reservations += "resv_id=";
\r
2923 reservations += seq_id;
\r
2924 reservations += "\" onclick='return confirm(\"To cancel. Is it ok?\");'>";
\r
2925 reservations += LocalizedString(KEY_I18N_Cancel, NULL)->cString();
\r
2926 reservations += "</a>";
\r
2928 reservations += "</div>";
\r
2931 contents += "</ul>";
\r
2932 contents += reservations;
\r
2940 time_t time1 = time(NULL);
\r
2941 time1 = (time1 + 15 * 60) / (15 * 60);
\r
2942 time1 = time1 * 15 * 60;
\r
2943 time_t time2 = time1 + 15 * 60;
\r
2944 localtime_s(&tm1, &time1);
\r
2945 localtime_s(&tm2, &time2);
\r
2947 contents += "<form name=\"reservation\" id=\"new_reservation\" class=\"panel\" method=\"GET\" action=\"regist.cgi\" target=\"_self\">";
\r
2948 contents += "<fieldset>";
\r
2949 contents += "<div class=\"row\">";
\r
2950 contents += "<label>";
\r
2951 contents += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
2952 contents += " : </label>";
\r
2953 contents += "<span>";
\r
2954 contents += "<select name=\"service_id\" size=\"1\">";
\r
2957 Array *stationInfos = Controller::stationInfos(Tuner::ISDB_T);
\r
2958 if (stationInfos != NULL)
\r
2960 stationInfos->addObjectsFromArray(Controller::stationInfos(Tuner::ISDB_S));
\r
2964 stationInfos = Controller::stationInfos(Tuner::ISDB_S);
\r
2966 for (uint i = 0; (stationInfos != NULL) && (i < stationInfos->count()); ++i)
\r
2968 Array *services = ((Dictionary *)stationInfos->objectAtIndex(i))->arrayForKey(KEY_SERVICES);
\r
2970 // とりえあず、現状は最初のサービスのみ表示
\r
2971 // for (uint j = 0; (services != NULL) && (j < services->count()); ++j)
\r
2972 for (uint j = 0; (services != NULL) && (j < 1); ++j)
\r
2974 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
2977 if ((service->stringForKey(KEY_SERVICE_TYPE) != NULL) && service->stringForKey(KEY_SERVICE_TYPE)->isEqualToString("1"))
\r
2979 String *name = service->stringForKey(KEY_NAME);
\r
2980 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
2981 if ((name != NULL) && (sid != NULL))
\r
2983 String *tmp = String::stringWithFormat("<option value=\"%s\">%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
2984 contents += tmp->cString();
\r
2990 contents += "</select>";
\r
2991 contents += "</span>";
\r
2992 contents += "</div>";
\r
2993 contents += "<div class=\"row\">";
\r
2994 contents += "<label>";
\r
2995 contents += LocalizedString(KEY_I18N_Date, NULL)->cString();
\r
2996 contents += " : </label>";
\r
2997 contents += "<span>";
\r
2998 contents += "<select name=\"year\" size=\"1\">";
\r
2999 for (int year = tm1.tm_year + 1900; year < tm1.tm_year + 1900 + 3; ++year)
\r
3001 char year_buf[64];
\r
3002 sprintf_s(year_buf, "<option value=\"%d\">%d</option>", year, year);
\r
3003 contents += year_buf;
\r
3005 contents += "</select>";
\r
3006 contents += "<select name=\"month\" size=\"1\">";
\r
3007 for (int month = 1; month < 13; ++month)
\r
3009 char month_buf[64];
\r
3010 if (month == tm1.tm_mon + 1)
\r
3012 sprintf_s(month_buf, "<option value=\"%d\" selected>%d</option>", month, month);
\r
3016 sprintf_s(month_buf, "<option value=\"%d\">%d</option>", month, month);
\r
3018 contents += month_buf;
\r
3020 contents += "</select>";
\r
3021 contents += "<select name=\"day\" size=\"1\">";
\r
3022 for (int day = 1; day < 32; ++day)
\r
3025 if (day == tm1.tm_mday)
\r
3027 sprintf_s(day_buf, "<option value=\"%d\" selected>%d</option>", day, day);
\r
3031 sprintf_s(day_buf, "<option value=\"%d\">%d</option>", day, day);
\r
3033 contents += day_buf;
\r
3035 contents += "</select>";
\r
3036 contents += "</span>";
\r
3037 contents += "</div>";
\r
3038 contents += "<div class=\"row\">";
\r
3039 contents += "<label>";
\r
3040 contents += LocalizedString(KEY_I18N_Start_Time, NULL)->cString();
\r
3041 contents += " : </label>";
\r
3042 contents += "<span>";
\r
3043 contents += "<select name=\"start_hour\" size=\"1\">";
\r
3044 for (int sh = 0; sh < 24; ++sh)
\r
3047 if (sh == tm1.tm_hour)
\r
3049 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
3053 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
3055 contents += sh_buf;
\r
3057 contents += "</select>";
\r
3058 contents += "<select name=\"start_min\" size=\"1\">";
\r
3059 for (int sm = 0; sm < 60; ++sm)
\r
3062 if (sm == tm1.tm_min)
\r
3064 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
3068 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
3070 contents += sm_buf;
\r
3072 contents += "</select>";
\r
3073 contents += "</span>";
\r
3074 contents += "</div>";
\r
3075 contents += "<div class=\"row\">";
\r
3076 contents += "<label>";
\r
3077 contents += LocalizedString(KEY_I18N_End_Time, NULL)->cString();
\r
3078 contents += " : </label>";
\r
3079 contents += "<span>";
\r
3080 contents += "<select name=\"end_hour\" size=\"1\">";
\r
3081 for (int eh = 0; eh < 24; ++eh)
\r
3084 if (eh == tm2.tm_hour)
\r
3086 sprintf_s(eh_buf, "<option value=\"%02d\" selected>%02d</option>", eh, eh);
\r
3090 sprintf_s(eh_buf, "<option value=\"%02d\">%02d</option>", eh, eh);
\r
3092 contents += eh_buf;
\r
3094 contents += "</select>";
\r
3095 contents += "<select name=\"end_min\" size=\"1\">";
\r
3096 for (int em = 0; em < 60; ++em)
\r
3099 if (em == tm2.tm_min)
\r
3101 sprintf_s(em_buf, "<option value=\"%02d\" selected>%02d</option>", em, em);
\r
3105 sprintf_s(em_buf, "<option value=\"%02d\">%02d</option>", em, em);
\r
3107 contents += em_buf;
\r
3109 contents += "</select>";
\r
3110 contents += "</span>";
\r
3111 contents += "</div>";
\r
3112 contents += "<div class=\"row\">";
\r
3113 contents += "<label>";
\r
3114 contents += LocalizedString(KEY_I18N_Repeat, NULL)->cString();
\r
3115 contents += " : </label>";
\r
3116 contents += "<span>";
\r
3117 contents += "<select name=\"repeat\" size=\"1\">";
\r
3118 contents += "<option value=\"off\" selected>";
\r
3119 contents += LocalizedString(KEY_I18N_Repeat_off, NULL)->cString();
\r
3120 contents += "</option>";
\r
3121 contents += "<option value=\"everyday\">";
\r
3122 contents += LocalizedString(KEY_I18N_Repeat_everyday, NULL)->cString();
\r
3123 contents += "</option>";
\r
3124 contents += "<option value=\"weekly\">";
\r
3125 contents += LocalizedString(KEY_I18N_Repeat_weekly, NULL)->cString();
\r
3126 contents += "</option>";
\r
3127 contents += "<option value=\"weekday\">";
\r
3128 contents += LocalizedString(KEY_I18N_Repeat_weekday, NULL)->cString();
\r
3129 contents += "</option>";
\r
3130 contents += "</select>";
\r
3131 contents += "</span>";
\r
3132 contents += "</div>";
\r
3133 contents += "</fieldset>";
\r
3135 contents += "<input type=\"submit\" class=\"whiteButton\" value=\"";
\r
3136 contents += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
3137 contents += "\">";
\r
3138 contents += "</form>";
\r
3148 contents += "<ul id=\"tuners\" title=\"";
\r
3149 contents += LocalizedString(KEY_I18N_Tuner, NULL)->cString();
\r
3150 contents += "\">";
\r
3152 std::string controls;
\r
3153 Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);
\r
3154 if (tunerInfos != NULL)
\r
3156 for (int i = 0; i < _tunerCount; ++i)
\r
3158 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name());
\r
3159 if (tunerInfo != NULL)
\r
3161 if (tunerInfo->boolForKey(KEY_INITIALIZED) && tunerInfo->boolForKey(KEY_ENABLED))
\r
3164 sprintf_s(key, "%03d", i);
\r
3167 contents += "<li>";
\r
3168 contents += "<a href=\"#tuner";
\r
3170 contents += "\">";
\r
3173 Dictionary *dict = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
3177 sprintf_s(chkey, "%03d", tunerInfo->integerForKey(KEY_CHANNEL));
\r
3178 dict = dict->dictionaryForKey(chkey);
\r
3179 String *name = dict->stringForKey(KEY_NAME);
\r
3182 contents += name->cString();
\r
3191 contents += _tuners[i]->name();
\r
3193 contents += "</a></li>";
\r
3196 controls += "<form name=\"control\" id=\"tuner";
\r
3198 controls += "\" class=\"panel\" method=\"GET\" action=\"/";
\r
3200 controls += "/recording=on\" target=\"_self\">";
\r
3203 controls += "<fieldset>";
\r
3206 controls += "<div class=\"row\">";
\r
3207 controls += "<label>";
\r
3208 controls += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
3209 controls += " : </label>";
\r
3210 controls += "<span>";
\r
3211 controls += "<select name=\"channel\" size=\"1\">";
\r
3212 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
3213 if (channels != NULL)
\r
3215 for (int ch = 0; ch <= Tuner::MAX_CHANNELS_ISDB_T; ++ch)
\r
3218 sprintf_s(chkey, "%03d", ch);
\r
3219 dict = channels->dictionaryForKey(chkey);
\r
3224 Array *services = (Array *)dict->objectForKey(KEY_SERVICES);
\r
3225 if (services != NULL)
\r
3227 for (uint s = 0; s < services->count(); ++s)
\r
3229 Dictionary *service = (Dictionary *)services->objectAtIndex(s);
\r
3230 if (service != NULL)
\r
3233 sprintf_s(sid, "%d", service->integerForKey(KEY_SERVICE_ID));
\r
3234 controls += "<option value=\"";
\r
3235 controls += chkey;
\r
3239 String *name = service->stringForKey(KEY_NAME);
\r
3242 controls += name->cString();
\r
3246 controls += "]</option>";
\r
3252 controls += "</select>";
\r
3253 controls += "</span>";
\r
3254 controls += "</div>";
\r
3258 controls += "<div class=\"row\">";
\r
3259 controls += "<label>";
\r
3260 controls += LocalizedString(KEY_I18N_Time, NULL)->cString();
\r
3261 controls += " : </label>";
\r
3262 controls += "<span>";
\r
3263 controls += "<select name=\"hour\" size=\"1\">";
\r
3264 for (int sh = 0; sh < 24; ++sh)
\r
3269 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
3273 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
3275 controls += sh_buf;
\r
3277 controls += "</select>";
\r
3278 controls += "<select name=\"min\" size=\"1\">";
\r
3279 for (int sm = 0; sm < 60; ++sm)
\r
3284 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
3288 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
3290 controls += sm_buf;
\r
3292 controls += "</select>";
\r
3293 controls += "</span>";
\r
3294 controls += "</div>";
\r
3297 controls += "</fieldset>";
\r
3300 controls += "<input type=\"submit\" class=\"whiteButton\" value=\"";
\r
3301 controls += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
3302 controls += "\">";
\r
3303 controls += "</form>";
\r
3308 contents += "</ul>";
\r
3309 contents += controls;
\r
3318 contents += "<ul id=\"keywords\" title=\"";
\r
3319 contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3320 contents += "\">";
\r
3322 contents += "<li><a href=\"#dialogForm\">";
\r
3323 contents += "<font color=\"red\">[";
\r
3324 // contents += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3325 contents += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3326 contents += "]</font>";
\r
3327 contents += "</a></li>";
\r
3330 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3331 if (keywords_info != NULL)
\r
3334 Array *keys = keywords_info->allKeys();
\r
3337 for (uint i = 0; i < keys->count(); ++i)
\r
3339 Dictionary *kwd_inf = keywords_info->dictionaryForKey((String *)keys->objectAtIndex(i));
\r
3340 if (kwd_inf == NULL)
\r
3346 sprintf_s(tmp, "%d", i);
\r
3347 contents += "<li><a href=\"#keywords_";
\r
3349 contents += "\">";
\r
3350 contents += ((String *)keys->objectAtIndex(i))->cString();
\r
3351 contents += "</a></li>";
\r
3353 controls += "<form name=\"filter\" id=\"keywords_";
\r
3355 controls += "\" class=\"panel\" method=\"GET\" action=\"mod_keywords.cgi\" target=\"_self\">";
\r
3356 controls += "<input type=\"hidden\" name=\"keywords\" value=\"";
\r
3357 controls += ((String *)keys->objectAtIndex(i))->cString();
\r
3358 controls += "\">";
\r
3359 controls += "<fieldset>";
\r
3361 controls += "<div class=\"row\">";
\r
3362 controls += "<label>";
\r
3363 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3364 controls += " : </label>";
\r
3365 controls += "<span>";
\r
3366 controls += ((String *)keys->objectAtIndex(i))->cString();
\r
3367 controls += "</span>";
\r
3368 controls += "</div>";
\r
3370 controls += "<div class=\"row\">";
\r
3371 controls += "<label>";
\r
3372 controls += LocalizedString(KEY_I18N_Station_Name, NULL)->cString();
\r
3373 controls += " : </label>";
\r
3374 controls += "<span>";
\r
3375 controls += "<select name=\"service_id\" size=\"1\">";
\r
3376 controls += "<option value=\"-\">----</option>";
\r
3378 String *service_id = kwd_inf->stringForKey(KEY_EPG_SERVICE_ID);
\r
3381 Array *stationInfos = Controller::stationInfos(Tuner::ISDB_T);
\r
3382 if (stationInfos != NULL)
\r
3384 stationInfos->addObjectsFromArray(Controller::stationInfos(Tuner::ISDB_S));
\r
3388 stationInfos = Controller::stationInfos(Tuner::ISDB_S);
\r
3390 for (uint i = 0; (stationInfos != NULL) && (i < stationInfos->count()); ++i)
\r
3392 Array *services = ((Dictionary *)stationInfos->objectAtIndex(i))->arrayForKey(KEY_SERVICES);
\r
3394 for (uint j = 0; (services != NULL) && (j < 1); ++j)
\r
3396 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
3399 if ((service->stringForKey(KEY_SERVICE_TYPE) != NULL) && service->stringForKey(KEY_SERVICE_TYPE)->isEqualToString("1"))
\r
3401 String *name = service->stringForKey(KEY_NAME);
\r
3402 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
3403 if ((name != NULL) && (sid != NULL))
\r
3405 if ((service_id != NULL) && (service_id->isEqualToString(sid)))
\r
3407 String *tmp = String::stringWithFormat("<option value=\"%s\" selected>%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
3408 controls += tmp->cString();
\r
3412 String *tmp = String::stringWithFormat("<option value=\"%s\">%s[%s]</option>", sid->cString(), name->cString(), sid->cString());
\r
3413 controls += tmp->cString();
\r
3420 controls += "</select>";
\r
3421 controls += "</span>";
\r
3422 controls += "</div>";
\r
3424 controls += "<div class=\"row\">";
\r
3425 controls += "<label>";
\r
3426 controls += LocalizedString(KEY_I18N_Start_Time, NULL)->cString();
\r
3427 controls += " : </label>";
\r
3428 controls += "<span>";
\r
3429 controls += "<select name=\"start_hour\" size=\"1\">";
\r
3430 controls += "<option value=\"-\">--</option>";
\r
3431 String *sh_str = kwd_inf->stringForKey(KEY_EPG_START);
\r
3432 for (int sh = 0; sh < 24; ++sh)
\r
3435 if ((sh_str != NULL) && (sh_str->length() == 5) && (sh_str->substringToIndex(2)->intValue() == sh))
\r
3437 sprintf_s(sh_buf, "<option value=\"%02d\" selected>%02d</option>", sh, sh);
\r
3441 sprintf_s(sh_buf, "<option value=\"%02d\">%02d</option>", sh, sh);
\r
3443 controls += sh_buf;
\r
3445 controls += "</select>";
\r
3446 controls += "<select name=\"start_min\" size=\"1\">";
\r
3447 controls += "<option value=\"-\">--</option>";
\r
3448 for (int sm = 0; sm < 60; ++sm)
\r
3451 if ((sh_str != NULL) && (sh_str->length() == 5) && (sh_str->substringFromIndex(3)->intValue() == sm))
\r
3453 sprintf_s(sm_buf, "<option value=\"%02d\" selected>%02d</option>", sm, sm);
\r
3457 sprintf_s(sm_buf, "<option value=\"%02d\">%02d</option>", sm, sm);
\r
3459 controls += sm_buf;
\r
3461 controls += "</select>";
\r
3462 controls += "</span>";
\r
3463 controls += "</div>";
\r
3465 controls += "</fieldset>";
\r
3467 controls += "<input type=\"submit\" class=\"whiteButton\" name=\"req_mod\" value=\"";
\r
3468 controls += LocalizedString(KEY_I18N_Registration, NULL)->cString();
\r
3469 controls += "\">";
\r
3471 controls += "<input type=\"submit\" class=\"redButton\" name=\"req_del\" value=\"";
\r
3472 controls += LocalizedString(KEY_I18N_Delete, NULL)->cString();
\r
3473 // controls += "\">";
\r
3474 controls += "\" onclick='return confirm(\"To delete. Is it ok?\");'>";
\r
3476 controls += "</form>";
\r
3481 contents += "</ul>";
\r
3482 contents += controls;
\r
3484 controls = "<form id=\"dialogForm\" title=\"";
\r
3485 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3486 controls += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3487 controls += "\" class=\"dialog\" target=\"_self\" action=\"add_keywords.cgi\" method=\"GET\">";
\r
3488 controls += "<fieldset>";
\r
3489 controls += "<h1>";
\r
3490 controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3491 controls += LocalizedString(KEY_I18N_Add, NULL)->cString();
\r
3492 controls += "</h1>";
\r
3493 controls += "<a class=\"button leftButton\" type=\"cancel\">Cancel</a>";
\r
3494 controls += "<a class=\"button blueButton\" type=\"submit\">Submit</a>";
\r
3495 controls += "<label>Parm1:</label>";
\r
3496 controls += "<input type=\"text\" name=\"keywords\" value=\"";
\r
3497 // controls += LocalizedString(KEY_I18N_Keywords, NULL)->cString();
\r
3498 controls += "\"/>";
\r
3499 controls += "</fieldset>";
\r
3500 controls += "<div class=\"spinner\"></div>";
\r
3501 controls += "</form>";
\r
3503 contents += controls;
\r
3508 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
3511 result = responseWithHTML(request, html);
\r
3523 HTTPResponse *Controller::responseForStatus(HTTPRequest *request, SOCKADDR_IN *client)
\r
3525 HTTPResponse *result = NULL;
\r
3526 if ((request != NULL) && (client != NULL))
\r
3528 String *path = _httpd->rootPath()->stringByAppendingPathComponent("template2.html");
\r
3529 String *html = String::stringWithContentsOfFile(path->cString(), UTF8StringEncoding);
\r
3532 html = html->stringByReplacingOccurrencesOfString("%%TITLE%%", LocalizedString(KEY_I18N_Tuner_Status, NULL));
\r
3533 std::string contents;
\r
3534 std::string status;
\r
3535 contents += "<ul id=\"home\" title=\"";
\r
3536 contents += LocalizedString(KEY_I18N_Tuner_Status, NULL)->cString();
\r
3537 contents += "\" selected=\"true\">";
\r
3538 DebugLog2("_tunerCount = %d", _tunerCount);
\r
3539 for (int i = 0; i < _tunerCount; ++i)
\r
3542 sprintf_s(key, sizeof(key), "%03d", i);
\r
3544 if (isTunerInitialized(i))
\r
3546 contents += "<li>";
\r
3547 contents += "<a href=\"#tuner";
\r
3549 contents += "\">";
\r
3552 contents += _tuners[i]->name();
\r
3553 contents += "</a></li>";
\r
3556 status += "<div id=\"";
\r
3557 status += "tuner";
\r
3559 status += "\" title=\"";
\r
3560 status += _tuners[i]->name();
\r
3561 status += "\" class=\"panel\">";
\r
3563 status += "<h2>Status</h2>";
\r
3564 status += "<fieldset>";
\r
3567 status += "<div class=\"row\">";
\r
3568 status += "<label>Type</label>";
\r
3569 status += "<span>";
\r
3570 switch (_tuners[i]->type())
\r
3572 case Tuner::ISDB_S:
\r
3573 status += "ISDB-S";
\r
3575 case Tuner::ISDB_T:
\r
3576 status += "ISDB-T";
\r
3578 case Tuner::TYPE_NA:
\r
3583 status += "</span>";
\r
3584 status += "</div>";
\r
3587 status += "<div class=\"row\">";
\r
3588 status += "<label>LnbPower</label>";
\r
3589 status += "<span>";
\r
3590 switch (_tuners[i]->lnbPower())
\r
3592 case Tuner::LNB_POWER_11V:
\r
3595 case Tuner::LNB_POWER_15V:
\r
3598 case Tuner::LNB_POWER_OFF:
\r
3603 status += "</span>";
\r
3604 status += "</div>";
\r
3608 status += "<div class=\"row\">";
\r
3609 status += "<label>Channel</label>";
\r
3610 status += "<span>";
\r
3611 sprintf_s(tmpstr, sizeof(tmpstr), "%03d", _tuners[i]->channel());
\r
3613 status += "</span>";
\r
3614 status += "</div>";
\r
3616 // C/N[dB] AGC xxx/255
\r
3617 uint32_t cn100 = 0;
\r
3619 uint32_t maxAgc = 0;
\r
3620 _tuners[i]->getCnAgc(&cn100, &agc, &maxAgc);
\r
3622 sprintf_s(tmpstr, sizeof(tmpstr), "%d.%02d[dB]", cn100 / 100, cn100 % 100);
\r
3624 status += "<div class=\"row\">";
\r
3625 status += "<label>C/N</label>";
\r
3626 status += "<span>";
\r
3628 status += "</span>";
\r
3629 status += "</div>";
\r
3631 sprintf_s(tmpstr, sizeof(tmpstr), "%03d/%03d", agc, maxAgc);
\r
3633 status += "<div class=\"row\">";
\r
3634 status += "<label>AGC</label>";
\r
3635 status += "<span>";
\r
3637 status += "</span>";
\r
3638 status += "</div>";
\r
3640 status += "</fieldset>";
\r
3641 status += "</div>";
\r
3646 contents += "<li>";
\r
3647 contents += _tuners[i]->name();
\r
3648 contents += "[uninitialized]";
\r
3649 contents += "</li>";
\r
3652 contents += "</ul>";
\r
3653 contents += status;
\r
3654 html = html->stringByReplacingOccurrencesOfString("%%CONTENTS%%", contents.c_str());
\r
3655 result = responseWithHTML(request, html);
\r
3659 DebugLog2("responseForStatus() html is null\n");
\r
3665 HTTPResponse *Controller::responseForRegistCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3667 DebugLog2("Controller::responseForRegistCGI()");
\r
3669 HTTPResponse *result = NULL;
\r
3672 Dictionary *cgi = request->parseAsCGI();
\r
3676 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/regist.cgi")))
\r
3679 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3680 if (params != NULL)
\r
3683 if (params->count() == 2)
\r
3686 String *service_id = NULL;
\r
3687 String *event_id = NULL;
\r
3689 for (uint i = 0; i < params->count(); ++i)
\r
3691 Dictionary *param = (Dictionary *)params->objectAtIndex(i);
\r
3692 String *value = param->stringForKey("service_id");
\r
3693 if ((value != NULL) && value->isMatch("^\\d+$"))
\r
3695 service_id = value;
\r
3697 value = param->stringForKey("event_id");
\r
3698 if ((value != NULL) && value->isMatch("^\\d+$"))
\r
3705 if ((service_id != NULL) && (event_id != NULL))
\r
3707 DebugLog2("valid request");
\r
3709 result = responseByResult(request, reserve(service_id->intValue(), event_id->intValue()));
\r
3714 else if (params->count() == 9)
\r
3717 String *service_id = NULL;
\r
3718 String *year = NULL;
\r
3719 String *month = NULL;
\r
3720 String *day = NULL;
\r
3721 String *start_hour = NULL;
\r
3722 String *start_min = NULL;
\r
3723 String *end_hour = NULL;
\r
3724 String *end_min = NULL;
\r
3725 String *repeat = NULL;
\r
3729 String **variable;
\r
3730 const char *regex;
\r
3734 {"service_id", &service_id, "^\\d+$"},
\r
3735 {"year", &year, "^\\d{4}$"},
\r
3736 {"month", &month, "^([1-9]|1[0-2])$"},
\r
3737 {"day", &day, "^([1-9]|[12][0-9]|3[01])$"},
\r
3738 {"start_hour", &start_hour, "^\\d{2}$"},
\r
3739 {"start_min", &start_min, "^\\d{2}$"},
\r
3740 {"end_hour", &end_hour, "^\\d{2}$"},
\r
3741 {"end_min", &end_min, "^\\d{2}$"},
\r
3742 {"repeat", &repeat, "^(off|everyday|weekly|weekday)$"},
\r
3743 {NULL, NULL, NULL}
\r
3746 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
3748 for (uint j = 0; j < params->count(); ++j)
\r
3750 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
3751 String *value = param->stringForKey(cgi[i].name);
\r
3752 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
3754 *(cgi[i].variable) = value;
\r
3761 if ((service_id != NULL) && (year != NULL) && (month != NULL) && (day != NULL) &&
\r
3762 (start_hour != NULL) && (start_min != NULL) && (end_hour != NULL) && (end_min != NULL) && (repeat != NULL))
\r
3765 DebugLog1("valid param");
\r
3767 Dictionary *epg = Dictionary::dictionaryWithCapacity(0);
\r
3770 epg->setString(String::stringWithFormat("%s/%02d/%02d", year->cString(), month->intValue(), day->intValue()), KEY_EPG_DATE);
\r
3773 epg->setString(String::stringWithFormat("%s:%s:00", start_hour->cString(), start_min->cString()), KEY_EPG_START);
\r
3776 epg->setString(String::stringWithFormat("%s:%s:00", end_hour->cString(), end_min->cString()), KEY_EPG_END);
\r
3779 epg->setString(repeat, KEY_EPG_REPEAT);
\r
3782 epg->setString(service_id, KEY_EPG_SERVICE_ID);
\r
3785 epg->setString("ready", KEY_EPG_STATUS);
\r
3787 result = responseByResult(request, reserve(epg));
\r
3797 HTTPResponse *Controller::responseForCancelCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3799 DebugLog2("Controller::responseForCancelCGI()");
\r
3801 HTTPResponse *result = NULL;
\r
3804 Dictionary *cgi = request->parseAsCGI();
\r
3808 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/cancel.cgi")))
\r
3811 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3812 if (params != NULL)
\r
3815 if (params->count() == 1)
\r
3817 Dictionary *param = (Dictionary *)params->objectAtIndex(0);
\r
3818 String *value = param->stringForKey("resv_id");
\r
3819 if ((value != NULL) && value->isMatch("^\\d{6}$"))
\r
3821 result = responseByResult(request, cancel(-1, value->intValue()));
\r
3830 HTTPResponse *Controller::responseForAddKeywordsCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3832 DebugLog2("Controller::responseForAddKeywordsCGI()");
\r
3834 HTTPResponse *result = NULL;
\r
3837 Dictionary *cgi = request->parseAsCGI();
\r
3841 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/add_keywords.cgi")))
\r
3844 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3845 if (params != NULL)
\r
3848 if (params->count() == 1)
\r
3850 Dictionary *param = (Dictionary *)params->objectAtIndex(0);
\r
3851 String *value = param->stringForKey("keywords");
\r
3852 if (value != NULL)
\r
3854 value = value->stringByReplacingOccurrencesOfString("+", " ");
\r
3855 if (value != NULL)
\r
3857 value = value->stringByRemovingPercentEncoding();
\r
3860 if (value != NULL)
\r
3865 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3866 if (keywords_info == NULL)
\r
3868 keywords_info = Dictionary::dictionaryWithCapacity(0);
\r
3869 _reservations->setObject(keywords_info, KEY_EPG_KEYWORDS);
\r
3872 if (keywords_info->dictionaryForKey(value) == NULL)
\r
3875 keywords_info->setObject(Dictionary::dictionaryWithCapacity(0), value);
\r
3878 updateKeywordsReservation();
\r
3884 _reservations->writeToFile(_reservations_path, true);
\r
3889 result = responseForReloadURI(request, client, "/reservation.html#_keywords");
\r
3898 HTTPResponse *Controller::responseForModKeywordsCGI(HTTPRequest *request, SOCKADDR_IN *client)
\r
3900 DebugLog2("Controller::responseForModKeywordsCGI()");
\r
3902 HTTPResponse *result = NULL;
\r
3905 Dictionary *cgi = request->parseAsCGI();
\r
3908 DebugLog3("cgi != NULL");
\r
3911 if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/mod_keywords.cgi")))
\r
3913 DebugLog3("CGI path OK.");
\r
3916 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
3917 if (params != NULL)
\r
3919 DebugLog3("params != NULL");
\r
3922 String *keywords = NULL;
\r
3923 String *service_id = NULL;
\r
3924 String *start_hour = NULL;
\r
3925 String *start_min = NULL;
\r
3926 String *req_mod = NULL;
\r
3927 String *req_del = NULL;
\r
3931 String **variable;
\r
3932 const char *regex;
\r
3936 {"keywords", &keywords, ".*"},
\r
3937 {"service_id", &service_id, "^(\\d+|-)$"},
\r
3938 {"start_hour", &start_hour, "^(\\d{2}|-)$"},
\r
3939 {"start_min", &start_min, "^(\\d{2}|-)$"},
\r
3940 {"req_mod", &req_mod, ".*"},
\r
3941 {"req_del", &req_del, ".*"},
\r
3942 {NULL, NULL, NULL}
\r
3945 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
3947 for (uint j = 0; j < params->count(); ++j)
\r
3949 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
3950 String *value = param->stringForKey(cgi[i].name);
\r
3951 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
3953 *(cgi[i].variable) = value;
\r
3959 if (keywords != NULL)
\r
3961 keywords = keywords->stringByReplacingOccurrencesOfString("+", " ");
\r
3962 if (keywords != NULL)
\r
3964 keywords = keywords->stringByRemovingPercentEncoding();
\r
3968 if ((keywords != NULL) && (service_id != NULL) && (start_hour != NULL) && (start_min != NULL) &&
\r
3969 ((req_mod != NULL) && (req_del == NULL)) || ((req_mod == NULL) && (req_del != NULL)))
\r
3975 Dictionary *keywords_info = _reservations->dictionaryForKey(KEY_EPG_KEYWORDS);
\r
3976 if (keywords_info != NULL)
\r
3978 if (req_mod != NULL)
\r
3980 DebugLog0("keywords: %s", keywords->cString());
\r
3981 DebugLog0("service_id: %s", service_id->cString());
\r
3982 DebugLog0("start_hour: %s", start_hour->cString());
\r
3983 DebugLog0("start_min: %s", start_min->cString());
\r
3984 Dictionary *kwd_inf = keywords_info->dictionaryForKey(keywords);
\r
3985 if (kwd_inf != NULL)
\r
3987 if (!service_id->isEqualToString("-"))
\r
3989 kwd_inf->setString(service_id, KEY_EPG_SERVICE_ID);
\r
3993 kwd_inf->removeObjectForKey(KEY_EPG_SERVICE_ID);
\r
3995 if (!start_hour->isEqualToString("-") && !start_min->isEqualToString("-"))
\r
3997 kwd_inf->setString(String::stringWithFormat("%s:%s", start_hour->cString(), start_min->cString()), KEY_EPG_START);
\r
4001 kwd_inf->removeObjectForKey(KEY_EPG_START);
\r
4005 else if (req_del != NULL)
\r
4007 DebugLog0("keywords: %s", keywords->cString());
\r
4008 keywords_info->removeObjectForKey(keywords);
\r
4012 updateKeywordsReservation();
\r
4018 _reservations->writeToFile(_reservations_path, true);
\r
4024 result = responseForReloadURI(request, client, "/reservation.html#_keywords");
\r
4032 HTTPResponse *Controller::responseForReloadURI(NET::HTTPRequest *request, SOCKADDR_IN *client, const char *uri, int sec)
\r
4034 HTTPResponse *result = NULL;
\r
4038 std::string contents;
\r
4039 contents = "<html>";
\r
4040 contents += "<head>";
\r
4042 contents += "<meta http-equiv=\"refresh\" content=\"0;URL=";
\r
4044 contents += "<meta http-equiv=\"refresh\" content=\"";
\r
4046 sprintf_s(tmp, "%d", sec);
\r
4048 contents += ";URL=";
\r
4051 contents += "\">";
\r
4052 contents += "</head>";
\r
4053 contents += "</html>";
\r
4054 String *html = String::stringWithUTF8String(contents.c_str());
\r
4057 result = responseWithHTML(request, html);
\r
4064 HTTPResponse *Controller::responseForPlaylist(HTTPRequest *request, SOCKADDR_IN *client)
\r
4066 HTTPResponse *result = NULL;
\r
4068 char hostname[NI_MAXHOST];
\r
4069 if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
\r
4071 if (_props->stringForKey(KEY_HTTP_HOST)->isEqualToString(hostname) || strcmp("127.0.0.1", hostname) == 0)
\r
4073 if (_iptv_m3u8_local != NULL)
\r
4075 result = responseWithUTF8Text(request, _iptv_m3u8_local);
\r
4080 if (_iptv_m3u8_remote != NULL)
\r
4082 result = responseWithUTF8Text(request, _iptv_m3u8_remote);
\r
4090 HTTPResponse *Controller::responseForXmltv(HTTPRequest *request, SOCKADDR_IN *client)
\r
4092 HTTPResponse *result = NULL;
\r
4094 std::string str_xmltv_xml;
\r
4095 str_xmltv_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
\r
4096 str_xmltv_xml += "<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\r\n";
\r
4097 str_xmltv_xml += "<tv generator-info-name=\"iPTd_R2\" generator-info-url=\"http://localhost/\">\r\n";
\r
4098 str_xmltv_xml += _xmltv_channels;
\r
4100 Dictionary *temp_data = _epgs->dictionaryForKey(KEY_TEMP_DATA);
\r
4101 if (temp_data != NULL)
\r
4103 Array *keys = temp_data->allKeys();
\r
4104 for (uint i = 0; i < keys->count(); ++i)
\r
4106 Dictionary *temp_service = temp_data->dictionaryForKey((String *)keys->objectAtIndex(i));
\r
4107 if (temp_service != NULL)
\r
4109 String *xmltv_programs = temp_service->stringForKey(KEY_PROGRAMS);
\r
4110 if (xmltv_programs != NULL)
\r
4112 str_xmltv_xml += xmltv_programs->cString();
\r
4118 str_xmltv_xml += "</tv>\r\n";
\r
4120 String *tmp = String::stringWithUTF8String(str_xmltv_xml.c_str());
\r
4123 result = responseWithUTF8Text(request, tmp);
\r
4130 * @brief HTTP Live Streaming制御
\r
4132 * http://hogehoge/チューナ番号_サービスID/streaming[-プリセット名].m3u8 がリクエスト(プリセットはオプション)され、
\r
4133 * チューナ番号/サービスID/プリセット名(ある場合)が有効値の場合にコールされる
\r
4135 * @param [in] request HTTPリクエスト
\r
4136 * @param [in] client リクエストしたクライアントのアドレス
\r
4137 * @param [in] tuner チューナ番号
\r
4138 * @param [in] service_id チャンネル番号
\r
4139 * @param [in] preset プリセット(URLで省略された場合 "default" )
\r
4141 HTTPResponse *Controller::responseForHLSControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner, int service_id, String *preset)
\r
4143 DebugLog2("Controller::responseForHLSControl()");
\r
4145 HTTPResponse *result = NULL;
\r
4147 // client からホスト名を取得
\r
4148 char hostname[NI_MAXHOST];
\r
4149 if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
\r
4151 // ストリーミング制御情報からHLS情報を取得
\r
4152 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
4153 if (hls_info == NULL)
\r
4155 hls_info = Dictionary::dictionaryWithCapacity(0);
\r
4156 _streaming_ctrls->setObject(hls_info, KEY_HLS_INFO);
\r
4159 // HLS情報から指定チューナの情報を取得
\r
4160 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[tuner]->name());
\r
4161 if (hls_info_tuner == NULL)
\r
4163 hls_info_tuner = Dictionary::dictionaryWithCapacity(0);
\r
4164 hls_info->setObject(hls_info_tuner, _tuners[tuner]->name());
\r
4167 // 指定チューナの情報からホスト名を確認
\r
4168 if ((hls_info_tuner->stringForKey(KEY_HOSTNAME) == NULL) || hls_info_tuner->stringForKey(KEY_HOSTNAME)->isEqualToString(hostname))
\r
4171 hls_info_tuner->setString(hostname, KEY_HOSTNAME);
\r
4174 if (!_tuners[tuner]->isRecording() && !_tuners[tuner]->isStreaming() && _tuners[tuner]->isLocked())
\r
4176 if (_tuners[tuner]->type() == Tuner::ISDB_S)
\r
4178 _cancel_epg_collect_s = true;
\r
4182 _cancel_epg_collect_t = true;
\r
4188 HTTPLiveStreaming *hls = (HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE);
\r
4192 hls = HTTPLiveStreaming::alloc()->init()->autorelease();
\r
4193 hls_info_tuner->setObject(hls, KEY_HLS_INSTANCE);
\r
4196 char tuner_and_service_id[10];
\r
4197 sprintf_s(tuner_and_service_id, "%03d_%d", tuner, service_id);
\r
4199 // 異チャンネルへのリクエスト、または、プリセット変更の場合
\r
4200 if (((hls_info_tuner->stringForKey(KEY_CHANNEL) != NULL) && !hls_info_tuner->stringForKey(KEY_CHANNEL)->isEqualToString(tuner_and_service_id)) ||
\r
4201 ((hls_info_tuner->stringForKey(KEY_PRESET) != NULL) && !hls_info_tuner->stringForKey(KEY_PRESET)->isEqualToString(preset)))
\r
4206 // チャンネルとプリセットは一旦削除
\r
4207 hls_info_tuner->removeObjectForKey(KEY_CHANNEL);
\r
4208 hls_info_tuner->removeObjectForKey(KEY_PRESET);
\r
4211 // 初回リクエスト or チャンネル/プリセット変更 か?
\r
4212 if ((hls_info_tuner->stringForKey(KEY_CHANNEL) == NULL) && (hls_info_tuner->stringForKey(KEY_PRESET) == NULL))
\r
4215 Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID);
\r
4216 if (mapping != NULL)
\r
4218 Array *ports = mapping->allKeys();
\r
4219 if (ports != NULL)
\r
4221 for (uint i = 0; i < ports->count(); ++i)
\r
4223 String *port = (String *)ports->objectAtIndex(i);
\r
4224 String *tmp = mapping->stringForKey(port);
\r
4225 if (tmp->isEqualToString(tuner_and_service_id))
\r
4227 DebugLog0("udp mapping %d -> %s", port->intValue(), tuner_and_service_id);
\r
4230 hls->setSource(String::stringWithFormat("udp://@0.0.0.0:%d", port->intValue()));
\r
4233 // hls->setTranscode(_props->dictionaryForKey(KEY_PRESETS)->dictionaryForKey(preset));
\r
4236 String *outpath = _props->stringForKey(KEY_CACHE_PATH)->stringByAppendingPathComponent(String::stringWithFormat("%03d", tuner));
\r
4237 _mkdir(outpath->cString());
\r
4238 hls->setOutputPath(outpath);
\r
4241 hls->setIndexName(String::stringWithFormat("live_%s", tuner_and_service_id));
\r
4246 DebugLog0("hls->start() success");
\r
4249 hls_info_tuner->setString(tuner_and_service_id, KEY_CHANNEL);
\r
4252 hls_info_tuner->setString(preset, KEY_PRESET);
\r
4264 String *index_path = hls->indexPath();
\r
4265 FileManager *fm = FileManager::defaultManager();
\r
4267 while (count++ < 5)
\r
4269 bool isDirectory = false;
\r
4270 if (fm->fileExistsAtPath(index_path, &isDirectory))
\r
4274 DebugLog0("file exists");
\r
4275 bool done = false;
\r
4279 result = _httpd->responseWithPath(index_path, request);
\r
4281 if (result != NULL)
\r
4295 hls_info_tuner->setInteger(0, KEY_COUNTER);
\r
4297 if (result == NULL)
\r
4299 DebugLog0("file no exists");
\r
4300 result = responseForReloadURI(request, client, request->URI()->cString(), 10);
\r
4312 HTTPResponse *Controller::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *client, int tuner)
\r
4314 DebugLog2("%s\n", __FUNCTION__);
\r
4316 HTTPResponse *result = NULL;
\r
4322 String *uri = request->URI();
\r
4323 while (uri != NULL)
\r
4326 Dictionary *cgi = request->parseAsCGI();
\r
4329 uri = cgi->stringForKey(HTTPRequest::KEY_CGI);
\r
4335 DebugLog0("uri: %s", uri->cString());
\r
4340 if (uri->isMatch("^/[0-9]{3}/info.xml$") && (cgi == NULL))
\r
4346 // /ttt/channel=nnn
\r
4348 else if (uri->isMatch("^/[0-9]{3}/channel=[0-9]{1,3}$") && (cgi == NULL))
\r
4350 DebugLog0("ch set");
\r
4351 String *ch = uri->substringFromIndex(13);
\r
4356 int channel = ch->intValue();
\r
4357 DebugLog0("set %d channel:%d(%s)\n", tuner, channel, ch->cString());
\r
4358 DebugLog2("set channel:%d(%s)\n", channel, ch->cString());
\r
4359 if (setChannel(tuner, channel))
\r
4362 DebugLog2("success.\n");
\r
4363 result = responseForSuccess(request);
\r
4368 DebugLog2("failed.\n");
\r
4369 result = responseForFailed(request);
\r
4374 // 録画開始(最大23:59まで)
\r
4375 // /ttt/recording=on?hour=hh&min=mm[&channel=nnn]
\r
4377 else if (uri->isMatch("^/[0-9]{3}/recording=on$") && (cgi != NULL))
\r
4380 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4381 if (params == NULL)
\r
4387 if ((params->count() != 2) && (params->count() != 3))
\r
4393 String *p_hour = NULL;
\r
4394 String *p_min = NULL;
\r
4395 String *p_channel = NULL;
\r
4399 String **variable;
\r
4400 const char *regex;
\r
4404 {"hour", &p_hour, "^[0-2][0-9]$"},
\r
4405 {"min", &p_min, "^[0-5][0-9]$"},
\r
4406 {"channel", &p_channel, "^[0-9]{3}$"},
\r
4407 {NULL, NULL, NULL}
\r
4410 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4412 *(cgi[i].variable) = NULL;
\r
4413 for (uint j = 0; j < params->count(); ++j)
\r
4415 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4416 String *value = param->stringForKey(cgi[i].name);
\r
4417 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4419 *(cgi[i].variable) = value;
\r
4425 if ((p_hour == NULL) || (p_min == NULL))
\r
4432 if (p_channel != NULL)
\r
4434 channel = p_channel->intValue();
\r
4438 channel = _tuners[tuner]->channel();
\r
4444 int hour = p_hour->intValue();
\r
4445 int min = p_min->intValue();
\r
4449 Dictionary *epg = Dictionary::dictionaryWithCapacity(0);
\r
4454 now += 1; // margin
\r
4456 if (localtime_s(&tm, &now) != 0)
\r
4463 end.tm_hour += hour;
\r
4464 end.tm_min += min;
\r
4465 end.tm_sec += 1; // margin
\r
4466 if (mktime(&end) == -1)
\r
4475 sprintf_s(tmp, sizeof(tmp), "%04d/%02d/%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
\r
4476 epg->setString(tmp, KEY_EPG_DATE);
\r
4479 sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
\r
4480 epg->setString(tmp, KEY_EPG_START);
\r
4483 sprintf_s(tmp, sizeof(tmp), "%02d:%02d:%02d", end.tm_hour, end.tm_min, end.tm_sec);
\r
4484 epg->setString(tmp, KEY_EPG_END);
\r
4487 sprintf_s(tmp, sizeof(tmp), "%d", channel);
\r
4488 epg->setString(tmp, KEY_EPG_CHANNEL);
\r
4491 epg->setString("off", KEY_EPG_REPEAT);
\r
4494 epg->setString("ready", KEY_EPG_STATUS);
\r
4502 result = responseByResult(request, reserve(tuner, epg));
\r
4510 // /ttt/recording=off
\r
4512 else if (uri->isMatch("^/[0-9]{3}/recording=off$") && (cgi == NULL))
\r
4515 DebugLog2("recording off: %s\n", uri->cString());
\r
4516 if (cancel(tuner, -1))
\r
4519 DebugLog2("success.\n");
\r
4520 result = responseForSuccess(request);
\r
4525 DebugLog2("failed.\n");
\r
4526 result = responseForFailed(request);
\r
4532 // /ttt/streaming=on?udp=nnnnn[&host=aaaaaa][&sid=sssss]
\r
4534 else if (uri->isMatch("^/[0-9]{3}/streaming=on$") && (cgi != NULL))
\r
4537 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4538 if ((params == NULL) || (params->count() < 0) || (params->count() > 3))
\r
4544 String *p_udp = NULL;
\r
4545 String *p_host = NULL;
\r
4546 String *p_sid = NULL;
\r
4550 String **variable;
\r
4551 const char *regex;
\r
4555 {"udp", &p_udp, "^[0-9]{1,5}$"},
\r
4556 {"host", &p_host, "^.+$"},
\r
4557 {"sid", &p_sid, "^[0-9]{1,5}$"},
\r
4558 {NULL, NULL, NULL}
\r
4561 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4563 *(cgi[i].variable) = NULL;
\r
4564 for (uint j = 0; j < params->count(); ++j)
\r
4566 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4567 String *value = param->stringForKey(cgi[i].name);
\r
4568 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4570 *(cgi[i].variable) = value;
\r
4576 if (p_udp == NULL)
\r
4581 SOCKADDR_IN dst_addr;
\r
4583 if (p_host != NULL)
\r
4586 std::string host = udpstr.substr(idx + 5);
\r
4587 udpstr = udpstr.substr(0, idx - 1);
\r
4588 DebugLog2("udp: %s\n", udpstr.c_str());
\r
4589 DebugLog2("host: %s\n", host.c_str());
\r
4590 struct hostent *ent = gethostbyname(host.c_str());
\r
4595 memcpy(&dst_addr, client, sizeof(SOCKADDR_IN));
\r
4597 dst_addr.sin_port = htons(p_udp->intValue());
\r
4599 if (p_sid == NULL)
\r
4601 if (_tuners[tuner]->startStreaming(&dst_addr))
\r
4604 DebugLog2("success.\n");
\r
4605 result = responseForSuccess(request);
\r
4610 DebugLog2("failed.\n");
\r
4611 result = responseForFailed(request);
\r
4616 DebugLog0("sid: %s", p_sid->cString());
\r
4617 DebugLog0("sid: %d", p_sid->intValue());
\r
4618 result = responseForFailed(request);
\r
4624 // /ttt/streaming=off(?host=aaaa)
\r
4626 else if (uri->isMatch("^/[0-9]{3}/streaming=off$"))
\r
4629 String *p_host = NULL;
\r
4634 Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS);
\r
4635 if (params == NULL)
\r
4641 if ((params->count() != 0) && (params->count() != 1))
\r
4648 String **variable;
\r
4649 const char *regex;
\r
4653 {"host", &p_host, "^.+$"},
\r
4654 {NULL, NULL, NULL}
\r
4657 for (uint i = 0; cgi[i].name != NULL; ++i)
\r
4659 *(cgi[i].variable) = NULL;
\r
4660 for (uint j = 0; j < params->count(); ++j)
\r
4662 Dictionary *param = (Dictionary *)params->objectAtIndex(j);
\r
4663 String *value = param->stringForKey(cgi[i].name);
\r
4664 if ((value != NULL) && value->isMatch(cgi[i].regex))
\r
4666 *(cgi[i].variable) = value;
\r
4672 SOCKADDR_IN dst_addr;
\r
4673 if (p_host != NULL)
\r
4680 _tuners[tuner]->stopStreaming();
\r
4683 DebugLog2("success.\n");
\r
4684 result = responseForSuccess(request);
\r
4690 else if (uri->isMatch("^/[0-9]{3}/[0-9]+/streaming(-[^\\.]+)?.m3u8$") && (cgi == NULL))
\r
4693 Range r = uri->rangeOfString("/streaming");
\r
4694 int service_id = uri->substringToIndex(r.location)->substringFromIndex(5)->intValue();
\r
4696 // presetが指定されている場合、presetを抽出
\r
4697 String *preset = NULL;
\r
4698 if (uri->isMatch("streaming-"))
\r
4700 preset = uri->substringFromIndex(r.location + 11);
\r
4701 preset = preset->substringToIndex(preset->length() - 5);
\r
4706 preset = String::stringWithUTF8String(KEY_DEFAULT);
\r
4709 // チャンネル/presetが有効か確認
\r
4710 Dictionary *mapping = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);
\r
4711 if ((mapping != NULL) && (mapping->stringForKey(String::stringWithFormat("%03d_%d", tuner, service_id)) != NULL) &&
\r
4712 (_props->dictionaryForKey(KEY_PRESETS) != NULL) &&
\r
4713 (_props->dictionaryForKey(KEY_PRESETS)->objectForKey(preset) != NULL))
\r
4716 result = responseForHLSControl(request, client, tuner, service_id, preset);
\r
4720 result = responseForFailed(request);
\r
4723 else if (uri->isMatch("^/[0-9]{3}/[0-9]+/streaming-[0-9]+.ts$") && (cgi == NULL))
\r
4726 Range r = uri->rangeOfString("/streaming");
\r
4727 int service_id = uri->substringToIndex(r.location)->substringFromIndex(5)->intValue();
\r
4729 // client からホスト名を取得
\r
4730 char hostname[NI_MAXHOST];
\r
4731 if (getnameinfo((SOCKADDR *)client, sizeof(SOCKADDR_IN), hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0)
\r
4733 Dictionary *hls_info = _streaming_ctrls->dictionaryForKey(KEY_HLS_INFO);
\r
4734 if (hls_info != NULL)
\r
4736 Dictionary *hls_info_tuner = hls_info->dictionaryForKey(_tuners[tuner]->name());
\r
4737 if (hls_info_tuner != NULL)
\r
4739 if (hls_info_tuner->stringForKey(KEY_HOSTNAME)->isEqualToString(hostname) &&
\r
4740 hls_info_tuner->stringForKey(KEY_CHANNEL)->isEqualToString(String::stringWithFormat("%03d_%d", tuner, service_id)))
\r
4742 String *path = ((HTTPLiveStreaming *)hls_info_tuner->objectForKey(KEY_HLS_INSTANCE))->outputPath();
\r
4745 result = _httpd->responseWithPath(path->stringByAppendingPathComponent(uri->substringFromIndex(r.location + 1)), request);
\r
4762 HTTPResponse *Controller::requestRTSP(RTSPRequest *request, SOCKET sock, SOCKADDR_IN *client)
\r
4764 HTTPResponse *result = NULL;
\r
4766 static int streaming_port = 0;
\r
4768 String *uri = request->URI();
\r
4769 if (uri->isMatch("^rtsp://[^/]+(:\\d+)/[0-9]{3}/[0-9]+/streaming.sdp/?$"))
\r
4771 if (request->method()->isEqualToString("OPTIONS"))
\r
4773 result = HTTPResponse::alloc()->init();
\r
4774 result->setVersion(request->version());
\r
4775 result->setStatus(HTTP_STATUS_OK);
\r
4776 result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));
\r
4778 InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();
\r
4779 header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), String::stringWithUTF8String("CSeq"));
\r
4780 header->setFieldBodyWithName(String::stringWithUTF8String("DESCRIBE, SETUP, TEARDOWN, PLAY"), String::stringWithUTF8String("Public"));
\r
4782 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);
\r
4785 result->setMessage(message);
\r
4786 result->autorelease();
\r
4789 else if (request->method()->isEqualToString("DESCRIBE"))
\r
4791 String *accept = request->message()->header()->fieldBodyForName("Accept");
\r
4792 if ((accept != NULL) && accept->isMatch("application/sdp"))
\r
4794 result = HTTPResponse::alloc()->init();
\r
4795 result->setVersion(request->version());
\r
4796 result->setStatus(HTTP_STATUS_OK);
\r
4797 result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));
\r
4799 InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();
\r
4800 header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), "CSeq");
\r
4801 header->setFieldBodyWithName("23 Jan 2007 15:35:06 JST", "Date");
\r
4802 header->setFieldBodyWithName("application/sdp", "Content-Type");
\r
4804 std::string str_body;
\r
4805 str_body = "v=0\r\n"; // プロトコルのバージョン
\r
4806 str_body += "o=hoge 1234 5678 IN IP4 172.19.29.9\r\n"; // 発信元およびセッション識別子
\r
4807 str_body += "s=test\r\n"; // セッション名
\r
4808 str_body += "c=IN IP4 172.19.29.9\r\n"; //
\r
4809 str_body += "t=0 0\r\n";
\r
4810 str_body += "a=control:*\r\n";
\r
4811 str_body += "a=range:npt=0-\r\n";
\r
4812 str_body += "m=video 0 RAW/RAW/UDP 33\r\n";
\r
4815 header->setFieldBodyWithName(String::stringWithFormat("%I64u", str_body.length()), "Content-Length");
\r
4817 InternetTextMessageBody *body = InternetTextMessageBody::alloc()->initWithString(String::stringWithUTF8String(str_body.c_str()));
\r
4819 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, body);
\r
4823 result->setMessage(message);
\r
4824 result->autorelease();
\r
4828 else if (request->method()->isEqualToString("SETUP"))
\r
4830 String *transport = request->message()->header()->fieldBodyForName("Transport");
\r
4831 if ((transport != NULL) && transport->isMatch("UDP.*;unicast;client_port=\\d+"))
\r
4833 Range r = transport->rangeOfString("_port=");
\r
4834 String *port = transport->substringFromIndex(r.location + 6);
\r
4835 r = port->rangeOfString("-");
\r
4836 port = port->substringToIndex(r.location);
\r
4837 DebugLog0("port: %s", port->cString());
\r
4838 streaming_port = port->intValue();
\r
4840 result = HTTPResponse::alloc()->init();
\r
4841 result->setVersion(request->version());
\r
4842 result->setStatus(HTTP_STATUS_OK);
\r
4843 result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));
\r
4845 InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();
\r
4846 header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), "CSeq");
\r
4847 header->setFieldBodyWithName("12345678", "Session");
\r
4848 String *tr = transport->stringByAppendingString(";server_port=50020-50021");
\r
4849 header->setFieldBodyWithName(tr, "Transport");
\r
4851 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);
\r
4854 result->setMessage(message);
\r
4855 result->autorelease();
\r
4859 else if (request->method()->isEqualToString("PLAY"))
\r
4861 String *range = request->message()->header()->fieldBodyForName("Range");
\r
4862 if (range != NULL)
\r
4864 result = HTTPResponse::alloc()->init();
\r
4865 result->setVersion(request->version());
\r
4866 result->setStatus(HTTP_STATUS_OK);
\r
4867 result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));
\r
4869 InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();
\r
4870 header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), "CSeq");
\r
4871 header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("Session"), "Session");
\r
4872 header->setFieldBodyWithName(range, "Range");
\r
4874 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);
\r
4877 result->setMessage(message);
\r
4878 result->autorelease();
\r
4881 SOCKADDR_IN dst_addr;
\r
4883 dst_addr.sin_family = AF_INET;
\r
4884 dst_addr.sin_addr.s_addr = htonl(0xac131d01);
\r
4885 dst_addr.sin_port = htons(streaming_port);
\r
4887 if (_tuners[1]->startStreaming(&dst_addr))
\r
4889 DebugLog0("streaming start ok");
\r
4893 else if (request->method()->isEqualToString("TEARDOWN"))
\r
4895 result = HTTPResponse::alloc()->init();
\r
4896 result->setVersion(request->version());
\r
4897 result->setStatus(HTTP_STATUS_OK);
\r
4898 result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_OK));
\r
4900 InternetTextMessageHeader *header =InternetTextMessageHeader::alloc()->init();
\r
4901 header->setFieldBodyWithName(request->message()->header()->fieldBodyForName("CSeq"), String::stringWithUTF8String("CSeq"));
\r
4903 InternetTextMessage *message = InternetTextMessage::alloc()->initWithHeaderAndBody(header, NULL);
\r
4906 result->setMessage(message);
\r
4907 result->autorelease();
\r
4913 DebugLog0("no match");
\r
4916 if (result == NULL)
\r
4918 result = HTTPResponse::alloc()->init();
\r
4919 result->setVersion(request->version());
\r
4920 result->setStatus(HTTP_STATUS_NOT_FOUND);
\r
4921 result->setReason(HTTPDaemon::reasonForStatus(HTTP_STATUS_NOT_FOUND));
\r
4922 result->autorelease();
\r
4928 HTTPResponse *Controller::request(HTTPRequest *request, SOCKET sock, SOCKADDR_IN *client)
\r
4930 DebugLog2("%s\n", __FUNCTION__);
\r
4933 bool flag = false;
\r
4935 flag = _initialized;
\r
4942 if (request->version()->isEqualToString("RTSP/1.0"))
\r
4944 return requestRTSP((RTSPRequest *)request, sock, client);
\r
4947 HTTPResponse *response = NULL;
\r
4949 if (request->method()->isEqualToString("GET") ||
\r
4950 request->method()->isEqualToString("HEAD"))
\r
4953 String *uri = request->URI();
\r
4954 DebugLog0("request(%d): %s\n", sock, uri->cString());
\r
4959 if (uri->isMatch("^(/|/index\\.(htm|html))$"))
\r
4961 response = responseForMain(request, client);
\r
4964 else if (uri->isMatch("^/status.html$"))
\r
4966 response = responseForStatus(request, client);
\r
4970 else if (uri->isMatch("^/info.xml$"))
\r
4973 else if (uri->isMatch("^/video.xml$"))
\r
4980 else if (uri->isMatch("^/[0-9]{3}/"))
\r
4982 // String::substringWithRange() を実装するのを後回しにするので。。
\r
4983 std::string s = uri->cString();
\r
4984 int tuner = atoi(s.substr(1, 3).c_str());
\r
4985 if ((0 <= tuner) && (tuner < _tunerCount))
\r
4987 response = requestTunerControl(request, client, tuner);
\r
4992 // reservation control
\r
4994 else if (uri->isMatch("^/reservation.html$"))
\r
4996 response = responseForReservation(request, client);
\r
4998 else if (uri->isMatch("^/regist.cgi"))
\r
5000 response = responseForRegistCGI(request, client);
\r
5002 else if (uri->isMatch("^/cancel.cgi"))
\r
5004 response = responseForCancelCGI(request, client);
\r
5006 else if (uri->isMatch("^/add_keywords.cgi"))
\r
5008 response = responseForAddKeywordsCGI(request, client);
\r
5010 else if (uri->isMatch("^/mod_keywords.cgi"))
\r
5012 response = responseForModKeywordsCGI(request, client);
\r
5014 else if (uri->isMatch("^/reservation.xml$"))
\r
5017 else if (uri->isMatch("^/[0-9]{6}/"))
\r
5019 // DebugLog2("reservation: %s\n", uri.c_str());
\r
5025 else if (uri->isMatch("^/[0-9]{9}/"))
\r
5027 // DebugLog2("video: %s\n", uri.c_str());
\r
5033 else if (uri->isMatch("^/programs.*\\.html$"))
\r
5035 response = responseForPrograms(request, client);
\r
5037 else if (uri->isMatch("^/programs.xml$"))
\r
5040 // return responseWithDictionary(request, _programs);
\r
5045 else if (uri->isMatch("^/tv.html$"))
\r
5047 // return responseForTV(request, client);
\r
5051 else if (uri->isMatch("^/iptv.m3u8$"))
\r
5053 return responseForPlaylist(request, client);
\r
5055 else if (uri->isMatch("^/xmltv.xml$"))
\r
5057 return responseForXmltv(request, client);
\r
5061 else if (uri->isMatch("^/iptd\\.log$"))
\r
5063 String *path = _system_path->stringByAppendingPathComponent("log");
\r
5066 path = path->stringByAppendingPathComponent("iptd_core.log");
\r
5069 response = _httpd->responseWithPath(path, request);
\r
5070 if (response != NULL)
\r
5072 if (response->message() != NULL)
\r
5074 if (response->message()->header() != NULL)
\r
5076 response->message()->header()->setFieldBodyWithName("text/plane; charset=UTF-8", "Content-Type");
\r
5083 else if (uri->isMatch("^/non_idle\\.xml$"))
\r
5088 Service::cancelShutdown();
\r
5089 return responseForSuccess(request);
\r
5091 else if (uri->isMatch("^/config\\.xml\\?shutdown_time=\\d+$"))
\r
5093 Range r = uri->rangeOfString("time=");
\r
5094 int val = uri->substringFromIndex(r.location + 5)->intValue();
\r
5095 if (val >= DEF_SHUTDOWN_TIME)
\r
5098 _shutdown_time = val;
\r
5100 return responseForSuccess(request);
\r
5104 return responseForFailed(request);
\r
5108 else if (request->method()->isEqualToString("POST"))
\r
5111 String *uri = request->URI();
\r
5112 DebugLog1("POST: %s\n", uri->cString());
\r
5113 InternetTextMessage *message = request->message();
\r
5114 if (message != NULL)
\r
5116 DebugLog3("message: ");
\r
5117 InternetTextMessageHeader *header = message->header();
\r
5118 if (header != NULL)
\r
5120 DebugLog3("header: ");
\r
5122 InternetTextMessageBody *body = message->body();
\r
5125 DebugLog3("body: ");
\r
5133 HTTPRequest * Controller::readRequest(SOCKET sock)
\r
5135 return RTSPRequest::requestWithSocket(sock);
\r
5140 #pragma mark ------- プロパティ取得 -------
\r
5143 bool Controller::isTunerInitialized(int tuner)
\r
5145 DebugLog2("Controller::isTunerInitialized()");
\r
5147 bool result = false;
\r
5149 if ((0 <= tuner) && (tuner < _tunerCount))
\r
5154 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
5155 if (tunersInfo != NULL)
\r
5157 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
5158 if (tunerInfo != NULL)
\r
5160 result = tunerInfo->boolForKey(KEY_INITIALIZED);
\r
5171 bool Controller::isTunerEnabled(int tuner)
\r
5173 DebugLog2("Controller::isTunerEnabled()");
\r
5175 bool result = false;
\r
5177 if ((0 <= tuner) && (tuner < _tunerCount))
\r
5182 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
5183 if (tunersInfo != NULL)
\r
5185 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
5186 if (tunerInfo != NULL)
\r
5188 result = tunerInfo->boolForKey(KEY_ENABLED);
\r
5199 bool Controller::isChannelEnabled(int tuner, int channel)
\r
5201 DebugLog2("Controller::isChannelEnabled()");
\r
5203 bool result = false;
\r
5205 if ((0 <= tuner) && (tuner < _tunerCount) && (0 <= channel) && (channel <= Tuner::MAX_CHANNELS_ISDB_T))
\r
5210 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
5211 if (tunersInfo != NULL)
\r
5213 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[tuner]->name());
\r
5214 if (tunerInfo != NULL)
\r
5216 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
5217 if (channels != NULL)
\r
5220 sprintf_s(key, "%03d", channel);
\r
5221 Dictionary *chInfo = channels->dictionaryForKey(key);
\r
5222 if (chInfo != NULL)
\r
5224 result = chInfo->boolForKey(KEY_ENABLED);
\r
5237 Array *Controller::stationInfos(Tuner::Type type)
\r
5239 DebugLog2("Controller::stationInfosForISDB_T()");
\r
5241 Array *result = Array::arrayWithCapacity(0);
\r
5246 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
5247 if (tunersInfo != NULL)
\r
5249 for (int i = 0; i < _tunerCount; ++i)
\r
5251 if (_tuners[i]->type() == type)
\r
5253 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[i]->name());
\r
5254 if (tunerInfo != NULL)
\r
5256 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
5257 if (channels != NULL)
\r
5259 for (uint ch = 0; ch <= (type == Tuner::ISDB_T ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S); ++ch)
\r
5262 sprintf_s(chkey, "%03d", ch);
\r
5263 Dictionary *channel = channels->dictionaryForKey(chkey);
\r
5264 if ((channel != NULL) && channel->boolForKey(KEY_ENABLED))
\r
5266 result->addObject(channel);
\r
5282 String *Controller::stationName(Tuner::Type type, int channel)
\r
5284 DebugLog2("Controller::stationName()");
\r
5286 String *result = NULL;
\r
5291 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
5292 if (tunersInfo != NULL)
\r
5294 for (int i = 0; i < _tunerCount; ++i)
\r
5296 if (_tuners[i]->type() == type)
\r
5298 Dictionary *tunerInfo = tunersInfo->dictionaryForKey(_tuners[i]->name());
\r
5299 if (tunerInfo != NULL)
\r
5301 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
5302 if (channels != NULL)
\r
5305 sprintf_s(chkey, "%03d", channel);
\r
5306 Dictionary *channel = channels->dictionaryForKey(chkey);
\r
5307 if ((channel != NULL) && channel->boolForKey(KEY_ENABLED))
\r
5309 result = channel->stringForKey(KEY_NAME);
\r
5324 Array *Controller::programsForServices(Array *services)
\r
5326 DebugLog2("Controller::programsForServices()");
\r
5328 Array *result = Array::arrayWithCapacity(0);
\r
5333 for (uint i = 0; i < services->count(); ++i)
\r
5335 Dictionary *service = (Dictionary *)services->objectAtIndex(i);
\r
5336 Dictionary *services = _epgs->dictionaryForKey(KEY_SERVICES);
\r
5337 Array *epgs = services->arrayForKey(service->stringForKey(KEY_SERVICE_ID));
\r
5340 result->addObjectsFromArray(epgs);
\r
5345 result = result->sortedArrayUsingFunction(compareFunction, this);
\r
5348 RaymUnlock(_epgs);
\r
5353 String *Controller::stationNameForServiceID(String *service_id)
\r
5355 DebugLog2("Controller::stationNameForServiceID()");
\r
5357 String *result = NULL;
\r
5359 if (service_id != NULL)
\r
5364 Dictionary *tunersInfo = _props->dictionaryForKey(KEY_TUNERS);
\r
5365 if (tunersInfo != NULL)
\r
5367 Array *tuners_key = tunersInfo->allKeys();
\r
5369 for (uint i = 0; (result == NULL) && (i < tuners_key->count()); ++i)
\r
5371 Dictionary *tunerInfo = tunersInfo->dictionaryForKey((String *)tuners_key->objectAtIndex(i));
\r
5372 if (tunerInfo != NULL)
\r
5374 Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS);
\r
5375 if (channels != NULL)
\r
5377 Array *chkey = channels->allKeys();
\r
5378 for (uint ch = 0; (result == NULL) && (ch < chkey->count()); ++ch)
\r
5380 Dictionary *channel = channels->dictionaryForKey((String *)chkey->objectAtIndex(ch));
\r
5381 if (channel != NULL)
\r
5383 Array *services = channel->arrayForKey(KEY_SERVICES);
\r
5384 if (services != NULL)
\r
5386 for (uint j = 0; j < services->count(); ++j)
\r
5388 Dictionary *service = (Dictionary *)services->objectAtIndex(j);
\r
5389 String *sid = service->stringForKey(KEY_SERVICE_ID);
\r
5392 if (sid->isEqualToString(service_id))
\r
5394 result = service->stringForKey(KEY_NAME);
\r
5416 #pragma mark ------- タイマディスパッチャ -------
\r
5419 void Controller::timerExpired(Timer *timer, void *userInfo)
\r
5421 DebugLog2("Controller::timerExpired()");
\r
5425 switch ((long long)userInfo)
\r
5428 if (restart() > 0)
\r
5431 DebugLog2("tuner initialize success.");
\r
5433 _cancel_epg_collect_s = false;
\r
5434 _cancel_epg_collect_t = false;
\r
5436 // EPG収集用タイマ起動(ISDB-S)
\r
5437 _timer_epg_s = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_S, true);
\r
5438 if (_timer_epg_s != NULL)
\r
5440 _timer_epg_s->fire();
\r
5443 // EPG収集用タイマ起動(ISDB-T)
\r
5444 _timer_epg_t = Timer::alloc()->initWithTimeInterval(DEF_COLLECT_EPG_DELAY, this, (void *)CMD_COLLECT_EPG_ISDB_T, true);
\r
5445 if (_timer_epg_t != NULL)
\r
5447 _timer_epg_t->fire();
\r
5453 DebugLog0("tuner initialize failed.");
\r
5457 case CMD_PERIODIC: // 周期処理
\r
5461 case CMD_PERIODIC_2: // 周期処理2
\r
5465 case CMD_COLLECT_EPG_ISDB_S: // EPG収集(ISDB-S)
\r
5467 if (collectEPGs(Tuner::ISDB_S))
\r
5470 _timer_epg_s->setRepeats(false);
\r
5475 _timer_epg_s->setTimeInterval(DEF_COLLECT_EPG_RETRY);
\r
5479 case CMD_COLLECT_EPG_ISDB_T: // 番組情報収集(ISDB-T)
\r
5480 if (collectEPGs(Tuner::ISDB_T))
\r
5483 _timer_epg_t->setRepeats(false);
\r
5488 _timer_epg_t->setTimeInterval(DEF_COLLECT_EPG_RETRY);
\r
5496 #pragma mark ------- 起動/停止関連 -------
\r
5499 bool Controller::isIdleState()
\r
5501 DebugLog2("Controller::isIdleState() start.");
\r
5503 bool result = _initialized;
\r
5509 time_t now = time(NULL);
\r
5511 for (int tuner = 0; tuner < _tunerCount; ++tuner)
\r
5513 Array *array = _reservations->arrayForKey(_tuners[tuner]->name());
\r
5514 if ((array == NULL) || (array->count() == 0))
\r
5521 Dictionary *epg = (Dictionary *)array->objectAtIndex(0);
\r
5524 getTimeWithEPG(epg, &start, &end);
\r
5526 if (start + OFFSET_OF_SUPPRESSION_TIME <= now)
\r
5537 DebugLog2("Controller::isIdleState() end.");
\r
5543 * TrayApp::WndProc() からコールされる
\r
5545 * スレッドコンテキスト:メインスレッド
\r
5547 void Controller::systemWillSuspend()
\r
5549 DebugLog2("Controller::systemWillSuspend() start");
\r
5552 _cancel_epg_collect_s = true;
\r
5553 _cancel_epg_collect_t = true;
\r
5557 if ((_timer_restart != NULL) && _timer_restart->valid())
\r
5559 _timer_restart->invalidate();
\r
5561 if ((_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
5563 _timer_epg_s->invalidate();
\r
5565 if ((_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
5567 _timer_epg_t->invalidate();
\r
5569 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
5571 _timer_periodic->invalidate();
\r
5573 if ((_timer_periodic_2 != NULL) && _timer_periodic_2->valid())
\r
5575 _timer_periodic_2->invalidate();
\r
5582 RELEASE(_timer_restart);
\r
5583 RELEASE(_timer_epg_s);
\r
5584 RELEASE(_timer_epg_t);
\r
5585 RELEASE(_timer_periodic);
\r
5586 RELEASE(_timer_periodic_2);
\r
5592 _initialized = false;
\r
5595 for (int i = 0; i < _tunerCount; ++i)
\r
5597 if (_tuners[i] != NULL)
\r
5599 delete _tuners[i];
\r
5600 _tuners[i] = NULL;
\r
5604 DebugLog0("system will suspend...");
\r
5609 #ifdef OBJC_MEMORY_CHECK
\r
5610 DebugLog0("global_objc_count_ = %d", Raym::global_objc_count_);
\r
5613 DebugLog2("Controller::systemWillSuspend() end");
\r
5617 * TrayApp::WndProc() からコールされる
\r
5619 * スレッドコンテキスト:メインスレッド
\r
5621 void Controller::systemResumed()
\r
5623 DebugLog2("Controller::systemResumed() start");
\r
5625 DebugLog0("system resumed.");
\r
5627 if (_timer_restart == NULL)
\r
5630 _timer_restart = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_RESTART, false);
\r
5631 _timer_restart->fire();
\r
5634 DebugLog2("Controller::systemResumed()");
\r
5637 void Controller::detectNonIdle()
\r
5639 DebugLog2("Controller::detectNonIdle()");
\r
5644 if (_idle_count > 0)
\r
5646 DebugLog0("detect non idle...");
\r
5654 int Controller::restart()
\r
5660 _initialized = false;
\r
5663 for (int i = 0; i < _tunerCount; ++i)
\r
5665 if (_tuners[i] != NULL)
\r
5667 delete _tuners[i];
\r
5668 _tuners[i] = NULL;
\r
5676 _tunerCount = ry0::device::TunerFactory::scan(_tuners, _multi2_dll);
\r
5682 for (int i = 0; i < _tunerCount; ++i)
\r
5685 if (!isTunerInitialized(i))
\r
5691 if (isTunerEnabled(i))
\r
5694 setChannel(i, getChannel(i));
\r
5698 Dictionary *tunerInfos = _props->dictionaryForKey(KEY_TUNERS);
\r
5701 // 最大チューナ番号の各サービスにIPTV有効フラグを立てる
\r
5702 if (_epgs->count() == 0)
\r
5704 Dictionary *flags = Dictionary::dictionaryWithCapacity(0);
\r
5705 for (int idx = _tunerCount - 1; idx >= 0; --idx)
\r
5707 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[idx]->name());
\r
5708 if (tunerInfo->boolForKey(KEY_ENABLED))
\r
5710 int ch_max = (_tuners[idx]->type() == Tuner::Type::ISDB_T) ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S;
\r
5711 for (int ch = 0; ch < ch_max; ++ch)
\r
5714 sprintf_s(key, "%03d", ch);
\r
5715 Dictionary *channelInfo = tunerInfo->dictionaryForKey(KEY_CHANNELS)->dictionaryForKey(key);
\r
5716 if ((channelInfo != NULL) && channelInfo->boolForKey(KEY_ENABLED))
\r
5718 Array *services = channelInfo->arrayForKey(KEY_SERVICES);
\r
5719 for (uint service_idx = 0; service_idx < services->count(); ++service_idx)
\r
5721 Dictionary *service = (Dictionary *)services->objectAtIndex(service_idx);
\r
5722 if (!flags->boolForKey(service->stringForKey(KEY_SERVICE_ID)))
\r
5724 service->setBool(true, KEY_IPTV_ENABLED);
\r
5725 flags->setBool(true, service->stringForKey(KEY_SERVICE_ID));
\r
5732 _props->writeToFile(_props_path, true);
\r
5735 // IPTV用データの準備/UDPポートマッピング
\r
5736 Dictionary *temp_data = Dictionary::dictionaryWithCapacity(0);
\r
5737 _epgs->setObject(temp_data, KEY_TEMP_DATA);
\r
5739 _xmltv_channels = "";
\r
5740 std::string str_iptv_m3u8_local;
\r
5741 std::string str_iptv_m3u8_remote;
\r
5743 str_iptv_m3u8_local = "#EXTM3U\r\n";
\r
5744 str_iptv_m3u8_local += "\r\n";
\r
5745 str_iptv_m3u8_remote = "#EXTM3U\r\n";
\r
5746 str_iptv_m3u8_remote += "\r\n";
\r
5748 int udpport = _props->integerForKey(KEY_BEGIN_UDP_PORT);
\r
5749 char http_port_str[10];
\r
5750 sprintf_s(http_port_str, "%d", _props->integerForKey(KEY_HTTP_PORT));
\r
5751 int idx_isdb_t = 0;
\r
5752 int idx_isdb_s = 0;
\r
5753 Tuner::Type type = Tuner::Type::ISDB_T;
\r
5754 while ((idx_isdb_t < _tunerCount) || (idx_isdb_s < _tunerCount))
\r
5756 int *idx = (type == Tuner::Type::ISDB_T) ? &idx_isdb_t : &idx_isdb_s;
\r
5757 while (*idx < _tunerCount)
\r
5759 if (_tuners[*idx]->type() == type)
\r
5761 Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[*idx]->name());
\r
5762 if (tunerInfo->boolForKey(KEY_ENABLED))
\r
5764 int ch_max = (type == Tuner::Type::ISDB_T) ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S;
\r
5765 for (int ch = 0; ch < ch_max; ++ch)
\r
5768 sprintf_s(key, "%03d", ch);
\r
5769 Dictionary *channelInfo = tunerInfo->dictionaryForKey(KEY_CHANNELS)->dictionaryForKey(key);
\r
5770 if ((channelInfo != NULL) && channelInfo->boolForKey(KEY_ENABLED))
\r
5772 Array *services = channelInfo->arrayForKey(KEY_SERVICES);
\r
5773 for (uint service_idx = 0; service_idx < services->count(); ++service_idx)
\r
5775 Dictionary *service = (Dictionary *)services->objectAtIndex(service_idx);
\r
5776 if (service->boolForKey(KEY_IPTV_ENABLED))
\r
5778 char channel_name[32];
\r
5779 sprintf_s(channel_name, "%03d_%s", *idx, service->stringForKey(KEY_SERVICE_ID)->cString());
\r
5780 char channel_service_id[32];
\r
5781 sprintf_s(channel_service_id, "%03d/%s", *idx, service->stringForKey(KEY_SERVICE_ID)->cString());
\r
5783 Dictionary *temp_service = temp_data->dictionaryForKey(service->stringForKey(KEY_SERVICE_ID));
\r
5784 if (temp_service == NULL)
\r
5786 temp_service = Dictionary::dictionaryWithCapacity(0);
\r
5787 temp_data->setObject(temp_service, service->stringForKey(KEY_SERVICE_ID));
\r
5789 Array *ch_list = temp_service->arrayForKey(KEY_CHANNELS);
\r
5790 if (ch_list == NULL)
\r
5792 ch_list = Array::arrayWithCapacity(0);
\r
5793 temp_service->setObject(ch_list, KEY_CHANNELS);
\r
5795 ch_list->addObject(String::stringWithUTF8String(channel_name));
\r
5797 Dictionary *udp_to_tuner_service_id = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID);
\r
5798 if (udp_to_tuner_service_id == NULL)
\r
5800 udp_to_tuner_service_id = Dictionary::dictionaryWithCapacity(0);
\r
5801 _streaming_ctrls->setObject(udp_to_tuner_service_id, KEY_MAPPING_UDP_TO_TUNER_SERVICE_ID);
\r
5804 Dictionary *tuner_service_id_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);
\r
5805 if (tuner_service_id_to_udp == NULL)
\r
5807 tuner_service_id_to_udp = Dictionary::dictionaryWithCapacity(0);
\r
5808 _streaming_ctrls->setObject(tuner_service_id_to_udp, KEY_MAPPING_TUNER_SERVICE_ID_TO_UDP);
\r
5811 Dictionary *tuner_service_id_to_channel = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL);
\r
5812 if (tuner_service_id_to_channel == NULL)
\r
5814 tuner_service_id_to_channel = Dictionary::dictionaryWithCapacity(0);
\r
5815 _streaming_ctrls->setObject(tuner_service_id_to_channel, KEY_MAPPING_TUNER_SERVICE_ID_TO_CHANNEL);
\r
5818 char port_str[10];
\r
5819 sprintf_s(port_str, "%d", udpport++);
\r
5821 udp_to_tuner_service_id->setString(channel_name, port_str);
\r
5822 tuner_service_id_to_udp->setString(port_str, channel_name);
\r
5823 tuner_service_id_to_channel->setInteger(ch, channel_name);
\r
5826 _xmltv_channels += " <channel id=\"";
\r
5827 _xmltv_channels += channel_name;
\r
5828 _xmltv_channels += "\"";
\r
5829 // transport_stream_id
\r
5830 // original_network_id
\r
5831 _xmltv_channels += " service_id=\"";
\r
5832 _xmltv_channels += service->stringForKey(KEY_SERVICE_ID)->cString();
\r
5833 _xmltv_channels += "\">\r\n";
\r
5835 _xmltv_channels += " <display-name lang=\"ja_JP\">";
\r
5836 _xmltv_channels += service->stringForKey(KEY_NAME)->cString();
\r
5837 _xmltv_channels += "</display-name>\r\n";
\r
5839 _xmltv_channels += " </channel>\r\n";
\r
5841 str_iptv_m3u8_local += "#EXTINF:-1 tvg-id=\"";
\r
5842 str_iptv_m3u8_local += channel_name;
\r
5843 str_iptv_m3u8_local += "\" tvg-logo=\"logo_";
\r
5844 str_iptv_m3u8_local += channel_name;
\r
5845 str_iptv_m3u8_local += "\" group-title=\"";
\r
5846 str_iptv_m3u8_local += _tuners[*idx]->name();
\r
5847 str_iptv_m3u8_local += "\", ";
\r
5848 str_iptv_m3u8_local += service->stringForKey(KEY_NAME)->cString();
\r
5849 str_iptv_m3u8_local += "\r\n";
\r
5850 str_iptv_m3u8_local += "udp://0.0.0.0:";
\r
5851 str_iptv_m3u8_local += port_str;
\r
5852 str_iptv_m3u8_local += "\r\n";
\r
5854 str_iptv_m3u8_remote += "#EXTINF:-1 tvg-id=\"";
\r
5855 str_iptv_m3u8_remote += channel_name;
\r
5856 str_iptv_m3u8_remote += "\" tvg-logo=\"logo_";
\r
5857 str_iptv_m3u8_remote += channel_name;
\r
5858 str_iptv_m3u8_remote += "\" group-title=\"";
\r
5859 str_iptv_m3u8_remote += _tuners[*idx]->name();
\r
5860 str_iptv_m3u8_remote += "\", ";
\r
5861 str_iptv_m3u8_remote += service->stringForKey(KEY_NAME)->cString();
\r
5862 str_iptv_m3u8_remote += "\r\n";
\r
5864 if (_props->stringForKey(KEY_HTTP_HOST) != NULL)
\r
5866 str_iptv_m3u8_remote += "http://";
\r
5867 str_iptv_m3u8_remote += _props->stringForKey(KEY_HTTP_HOST)->cString();
\r
5868 str_iptv_m3u8_remote += ":";
\r
5869 str_iptv_m3u8_remote += http_port_str;
\r
5870 str_iptv_m3u8_remote += "/";
\r
5871 str_iptv_m3u8_remote += channel_service_id;
\r
5872 str_iptv_m3u8_remote += "/streaming.m3u8\r\n";
\r
5875 // str_iptv_m3u8_remote += "rtsp://";
\r
5876 str_iptv_m3u8_remote += "sip://";
\r
5877 str_iptv_m3u8_remote += _props->stringForKey(KEY_HTTP_HOST)->cString();
\r
5878 str_iptv_m3u8_remote += ":";
\r
5879 str_iptv_m3u8_remote += http_port_str;
\r
5880 str_iptv_m3u8_remote += "/";
\r
5881 str_iptv_m3u8_remote += channel_service_id;
\r
5882 str_iptv_m3u8_remote += "/streaming.sdp\r\n";
\r
5894 type = (type == Tuner::Type::ISDB_T) ? Tuner::Type::ISDB_S : Tuner::Type::ISDB_T;
\r
5897 RELEASE(_iptv_m3u8_local);
\r
5898 _iptv_m3u8_local = String::alloc()->initWithUTF8String(str_iptv_m3u8_local.c_str());
\r
5899 RELEASE(_iptv_m3u8_remote);
\r
5900 _iptv_m3u8_remote = String::alloc()->initWithUTF8String(str_iptv_m3u8_remote.c_str());
\r
5906 _timer_periodic = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC, true);
\r
5907 _timer_periodic->fire();
\r
5910 _timer_periodic_2 = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_PERIODIC_2, true);
\r
5911 _timer_periodic_2->fire();
\r
5917 _initialized = true;
\r
5922 DebugLog0("initialize done.");
\r
5924 return (_tunerCount > 0);
\r
5927 void Controller::start()
\r
5931 Raym::LOG_NUM_MAX = 8;
\r
5934 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
\r
5935 if (hProcess != NULL)
\r
5937 if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == FALSE)
\r
5939 DebugLog0("SetPriorityClass failed.");
\r
5941 CloseHandle(hProcess);
\r
5945 #ifdef RAYM_MEMORY_CHECK
\r
5947 DebugLog0("global_raym_count_ = %d", Raym::global_raym_count_);
\r
5951 AutoreleasePool *pool = AutoreleasePool::alloc()->init();
\r
5955 _system_path = NULL;
\r
5956 _props_path = NULL;
\r
5958 _status_path = NULL;
\r
5960 _epgs_path = NULL;
\r
5962 _store_path = NULL;
\r
5963 _store_remain = -1;
\r
5964 _reservations = NULL;
\r
5965 _reservations_path = NULL;
\r
5966 _timer_restart = NULL;
\r
5967 _timer_periodic = NULL;
\r
5968 _timer_periodic_2 = NULL;
\r
5969 _timer_epg_s = NULL;
\r
5970 _timer_epg_t = NULL;
\r
5971 _multi2_dll = NULL;
\r
5972 _streaming_ctrls = NULL;
\r
5975 _shutdown_time = 0;
\r
5976 _initialized = false;
\r
5977 _reservation_seq_id = 0;
\r
5978 _cancel_epg_collect_s = false;
\r
5979 _cancel_epg_collect_t = false;
\r
5981 _iptv_m3u8_local = NULL;
\r
5982 _iptv_m3u8_remote = NULL;
\r
5985 for (int i = 0; i < ry0::device::MAX_TUNERS; ++i)
\r
5987 _tuners[i] = NULL;
\r
5991 DebugLog0("------------------------------------------------------------------------");
\r
5992 DebugLog0("iPTd ver %s (rev.%d)", VERSION, REVISION);
\r
5993 DebugLog0("initialize...");
\r
5998 bool updated = false;
\r
6001 _system_path = String::stringWithFormat("%s", GetExecutePath());
\r
6002 if (_system_path == NULL)
\r
6004 DebugLog0("error: GetExecutePath()");
\r
6007 _system_path = _system_path->stringByReplacingOccurrencesOfString("iptd_core.exe", "");
\r
6008 _system_path->retain();
\r
6009 DebugLog2("_system_path: %s", _system_path->cString());
\r
6012 _props_path = String::alloc()->initWithFormat("%s%s.iptd.plist", _system_path->cString(), PLIST_PREFIX);
\r
6013 if (_props_path == NULL)
\r
6015 DebugLog0("error: set property file path.");
\r
6020 _props = Dictionary::alloc()->initWithContentsOfFile(_props_path);
\r
6021 if (_props == NULL)
\r
6023 DebugLog1("property file: %s (created)", _props_path->cString());
\r
6024 _props = Dictionary::alloc()->initWithCapacity(0);
\r
6028 DebugLog1("property file: %s", _props_path->cString());
\r
6032 _status_path = String::alloc()->initWithFormat("%s%s.iptd.status.plist", _system_path->cString(), PLIST_PREFIX);
\r
6033 if (_status_path == NULL)
\r
6035 DebugLog0("error: set status file path.");
\r
6040 _status = Dictionary::alloc()->initWithContentsOfFile(_status_path);
\r
6041 if (_status == NULL)
\r
6043 DebugLog1("status file: %s (created)", _status_path->cString());
\r
6044 _status = Dictionary::alloc()->initWithCapacity(0);
\r
6048 DebugLog1("status file: %s", _status_path->cString());
\r
6052 if (_props->stringForKey(KEY_NAME) == NULL)
\r
6054 _props->setString(DEF_NAME, KEY_NAME);
\r
6059 if (_props->stringForKey(KEY_HOSTNAME) == NULL)
\r
6061 _props->setString(DEF_HOSTNAME, KEY_HOSTNAME);
\r
6065 // multi2デコード可否判定: multi2.dll が使えるか確認する
\r
6066 _multi2_dll = ::LoadLibrary(L"multi2.dll");
\r
6067 while (_multi2_dll != NULL)
\r
6070 ARIB_STD_B25 *(*func_b25)();
\r
6071 func_b25 = reinterpret_cast<ARIB_STD_B25 *(*)()>(::GetProcAddress(_multi2_dll, "create_arib_std_b25"));
\r
6072 if (func_b25 == NULL)
\r
6075 FreeLibrary(_multi2_dll);
\r
6076 _multi2_dll = NULL;
\r
6081 ARIB_STD_B25 * _b25;
\r
6082 _b25 = func_b25();
\r
6086 FreeLibrary(_multi2_dll);
\r
6087 _multi2_dll = NULL;
\r
6090 _b25->release(_b25);
\r
6093 B_CAS_CARD *(*func_bcas)();
\r
6094 func_bcas = reinterpret_cast<B_CAS_CARD *(*)()>(::GetProcAddress(_multi2_dll, "create_b_cas_card"));
\r
6095 if (func_bcas == NULL)
\r
6098 FreeLibrary(_multi2_dll);
\r
6099 _multi2_dll = NULL;
\r
6104 B_CAS_CARD * _bcas;
\r
6105 _bcas = func_bcas();
\r
6106 if (_bcas == NULL)
\r
6109 FreeLibrary(_multi2_dll);
\r
6110 _multi2_dll = NULL;
\r
6113 if (_bcas->init(_bcas) != 0)
\r
6116 FreeLibrary(_multi2_dll);
\r
6117 _multi2_dll = NULL;
\r
6120 _bcas->release(_bcas);
\r
6127 if (_props->integerForKey(KEY_HTTP_PORT) == 0)
\r
6129 _props->setInteger(DEF_HTTP_PORT, KEY_HTTP_PORT);
\r
6133 if (_props->stringForKey(KEY_HTTP_HOST) == NULL)
\r
6135 char hostname[NI_MAXHOST];
\r
6136 if (gethostname(hostname, sizeof(hostname)) == 0)
\r
6139 ai.ai_family = PF_INET;
\r
6140 ai.ai_flags = AI_CANONNAME;
\r
6141 addrinfo *p = NULL;
\r
6142 if (getaddrinfo(hostname, 0, &ai, &p) == 0)
\r
6144 char hostaddr[40];
\r
6145 if (getnameinfo(p->ai_addr, (int)p->ai_addrlen, hostaddr, sizeof(hostaddr), 0, 0, NI_NUMERICHOST) == 0)
\r
6147 _props->setString(hostaddr, KEY_HTTP_HOST);
\r
6155 if (_props->integerForKey(KEY_BEGIN_UDP_PORT) == 0)
\r
6157 _props->setInteger(DEF_BEGIN_UDP_PORT, KEY_BEGIN_UDP_PORT);
\r
6162 if ((_props->stringForKey(KEY_COLLECT_EPG_TIME) == NULL) ||
\r
6163 !_props->stringForKey(KEY_COLLECT_EPG_TIME)->isMatch(String::stringWithUTF8String("^\\d\\d:\\d\\d:\\d\\d$")))
\r
6165 _props->setString(DEF_COLLECT_EPG_TIME, KEY_COLLECT_EPG_TIME);
\r
6170 _store_path = _props->stringForKey(KEY_STORE_PATH);
\r
6171 if (_store_path == NULL)
\r
6174 // <Public Directory>/Videos を設定
\r
6175 const char *public_dir = GetPublicDirectory();
\r
6176 if (public_dir == NULL)
\r
6178 DebugLog0("error: GetPublicDirectory().");
\r
6181 _store_path = String::alloc()->initWithFormat("%s\\Videos", public_dir);
\r
6182 _props->setString(_store_path, KEY_STORE_PATH);
\r
6189 _store_path->retain();
\r
6192 // 実際にディレクトリが存在しているか確認
\r
6193 FileManager *fm = FileManager::defaultManager();
\r
6194 bool isDir = false;
\r
6195 if (!fm->fileExistsAtPath(_store_path, &isDir))
\r
6201 DebugLog0("error: \"%s\" is not exists.", _store_path->cString());
\r
6205 _store_remain = FileManager::freeSpaceForPath(_store_path);
\r
6208 if (_props->dictionaryForKey(KEY_PRESETS) == NULL)
\r
6210 Dictionary *presets = Dictionary::dictionaryWithCapacity(0);
\r
6211 _props->setObject(presets, KEY_PRESETS);
\r
6214 // プリセットは、あとで実装。。。
\r
6218 preset = STR_ARRAY("-vcodec", "libx264",
\r
6221 "-acodec", "libfaac",
\r
6224 "-flags", "+loop-global_header",
\r
6226 "-bsf", "h264_mp4toannexb",
\r
6228 "-segment_format", "mpegts",
\r
6229 "-segment_time", "10",
\r
6231 presets->setObject(preset, KEY_DEFAULT);
\r
6236 // キャッシュ(HLSの一時ファイル格納先)パス
\r
6237 if (_props->stringForKey(KEY_CACHE_PATH) == NULL)
\r
6239 _props->setString(_store_path->stringByAppendingPathComponent("Cache"), KEY_CACHE_PATH);
\r
6240 _mkdir(_props->stringForKey(KEY_CACHE_PATH)->cString());
\r
6244 if (!fm->fileExistsAtPath(_props->stringForKey(KEY_CACHE_PATH), &isDir))
\r
6250 DebugLog0("error: \"%s\" is not exists.", _props->stringForKey(KEY_CACHE_PATH)->cString());
\r
6255 if ((_props->integerForKey(KEY_FORCED_SHUTDOWN) == 0) || (_props->integerForKey(KEY_FORCED_SHUTDOWN) < DEF_FORCED_SHUTDOWN))
\r
6257 _props->setInteger(DEF_FORCED_SHUTDOWN, KEY_FORCED_SHUTDOWN);
\r
6261 // シャットダウン抑止アプリリスト
\r
6262 if (_props->arrayForKey(KEY_DO_NOT_IN_SHUTDOWN) == NULL)
\r
6264 Array *apps = Array::arrayWithCapacity(0);
\r
6265 apps->addObject(String::stringWithUTF8String("PIXELACORPORATION.*DtvView\\.exe$"));
\r
6266 apps->addObject(String::stringWithUTF8String("Common7\\\\IDE\\\\devenv\\.exe$"));
\r
6267 apps->addObject(String::stringWithUTF8String("Kodi\\\\Kodi\\.exe$"));
\r
6268 _props->setObject(apps, KEY_DO_NOT_IN_SHUTDOWN);
\r
6275 DebugLog0("props updated.");
\r
6276 if (!_props->writeToFile(_props_path, true))
\r
6278 DebugLog0("Can't write property file.");
\r
6284 DebugLog0(" Name : %s", _props->stringForKey(KEY_NAME)->cString());
\r
6285 DebugLog0(" Decode Enabled : %s", (_multi2_dll != NULL) ? "true" : "false");
\r
6286 DebugLog0(" HTTP Port : %d", _props->integerForKey(KEY_HTTP_PORT));
\r
6287 if (_props->stringForKey(KEY_POWER_MANAGER) != NULL)
\r
6289 DebugLog0(" Power Manager : %s", _props->stringForKey(KEY_POWER_MANAGER)->cString());
\r
6293 _epgs_path = String::alloc()->initWithFormat("%s%s.iptd.epgs.plist", _system_path->cString(), PLIST_PREFIX);
\r
6294 if (_epgs_path == NULL)
\r
6296 DebugLog0("error: set epgs file path.");
\r
6301 _epgs = Dictionary::alloc()->initWithContentsOfFile(_epgs_path);
\r
6302 if (_epgs == NULL)
\r
6304 DebugLog1("epgs file: %s (created)", _epgs_path->cString());
\r
6305 _epgs = Dictionary::alloc()->initWithCapacity(0);
\r
6309 DebugLog1("epgs file: %s", _epgs_path->cString());
\r
6313 _reservations_path = String::alloc()->initWithFormat("%s%s.iptd.reservations.plist", _system_path->cString(), PLIST_PREFIX);
\r
6314 if (_reservations_path == NULL)
\r
6316 DebugLog0("error: set reservations file path.");
\r
6321 _reservations = Dictionary::alloc()->initWithContentsOfFile(_reservations_path);
\r
6322 if (_reservations == NULL)
\r
6324 DebugLog1("reservations file: %s (created)", _reservations_path->cString());
\r
6325 _reservations = Dictionary::alloc()->initWithCapacity(0);
\r
6329 DebugLog1("reservations file: %s", _reservations_path->cString());
\r
6332 _reservation_seq_id = _reservations->integerForKey(KEY_EPG_LAST_RESV_ID);
\r
6336 _streaming_ctrls = Dictionary::alloc()->initWithCapacity(0);
\r
6339 String *rootPath = _system_path->stringByAppendingPathComponent("iptd_html");
\r
6340 if (!fm->fileExistsAtPath(rootPath, &isDir))
\r
6346 DebugLog0("error: \"%s\" is not exists.", rootPath->cString());
\r
6351 int port = _props->integerForKey(KEY_HTTP_PORT);
\r
6352 _httpd = NET::HTTPDaemon::alloc()->initWithPort(port, 30);
\r
6353 _httpd->setRootPath(rootPath);
\r
6354 _httpd->setDelegate(this);
\r
6355 if (!_httpd->start())
\r
6357 DebugLog0("Can't start httpd.");
\r
6362 _timer_restart = Timer::alloc()->initWithTimeInterval(1.0, this, (void *)CMD_RESTART, false);
\r
6363 _timer_restart->fire();
\r
6366 SERVICE_STATUS ss;
\r
6367 ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
\r
6368 ss.dwWin32ExitCode = NO_ERROR;
\r
6369 ss.dwServiceSpecificExitCode = 0;
\r
6370 ss.dwCheckPoint = 0;
\r
6371 ss.dwWaitHint = 0;
\r
6372 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
\r
6373 ss.dwCurrentState = SERVICE_RUNNING;
\r
6375 if (setServiceStatus(&ss))
\r
6379 while (_state == ST_RUN)
\r
6381 RaymCondWait(this);
\r
6386 _cancel_epg_collect_s = true;
\r
6387 _cancel_epg_collect_t = true;
\r
6398 DebugLog0("error: SetServiceStatus(): %u", GetLastError());
\r
6405 if ((_timer_restart != NULL) && _timer_restart->valid())
\r
6407 _timer_restart->invalidate();
\r
6409 if ((_timer_epg_s != NULL) && _timer_epg_s->valid())
\r
6411 _timer_epg_s->invalidate();
\r
6413 if ((_timer_epg_t != NULL) && _timer_epg_t->valid())
\r
6415 _timer_epg_t->invalidate();
\r
6417 if ((_timer_periodic != NULL) && _timer_periodic->valid())
\r
6419 _timer_periodic->invalidate();
\r
6421 if ((_timer_periodic_2 != NULL) && _timer_periodic_2->valid())
\r
6423 _timer_periodic_2->invalidate();
\r
6427 for (int i = 0; i < _tunerCount; ++i)
\r
6429 if (_tuners[i] != NULL)
\r
6431 delete _tuners[i];
\r
6432 _tuners[i] = NULL;
\r
6437 RELEASE(_timer_restart);
\r
6438 RELEASE(_timer_epg_s);
\r
6439 RELEASE(_timer_epg_t);
\r
6440 RELEASE(_timer_periodic);
\r
6441 RELEASE(_timer_periodic_2);
\r
6442 RELEASE(_streaming_ctrls);
\r
6444 RELEASE(_system_path);
\r
6445 RELEASE(_props_path);
\r
6447 RELEASE(_status_path);
\r
6449 RELEASE(_epgs_path);
\r
6451 RELEASE(_store_path);
\r
6452 RELEASE(_reservations_path);
\r
6453 RELEASE(_reservations);
\r
6454 RELEASE(_iptv_m3u8_local);
\r
6455 RELEASE(_iptv_m3u8_remote);
\r
6457 if (_multi2_dll != NULL)
\r
6459 FreeLibrary(_multi2_dll);
\r
6464 RaymCondSignal(this);
\r
6470 DebugLog0("finished.");
\r
6472 #ifdef RAYM_MEMORY_CHECK
\r
6473 DebugLog0("global_raym_count_ = %d", Raym::global_raym_count_);
\r
6477 void Controller::stop()
\r
6480 if (_state == ST_RUN)
\r
6483 RaymCondSignal(this);
\r
6484 while (_state != ST_IDLE)
\r
6486 RaymCondWait(this);
\r
6494 #pragma mark ------- コンストラクタ/デストラクタ -------
\r
6497 Controller::Controller()
\r
6501 Controller::~Controller()
\r
6505 Controller *Controller::alloc()
\r
6507 return new Controller();
\r
6512 #pragma mark ------- その他 -------
\r
6516 // HH:MM:SS 形式の文字列から time_t に変換
\r
6517 // 現在時刻が指定文字列の時刻以前の場合、当日の時刻。指定文字列の時刻よりも過ぎている場合、翌日の時刻を返す。
\r
6519 void Controller::getTimeWithString(String *str, time_t *time_var)
\r
6521 if ((str != NULL) && str->isMatch(String::stringWithUTF8String("^\\d\\d:\\d\\d:\\d\\d$")) && (time_var != NULL))
\r
6523 // 時:分:秒 を int型に分解
\r
6524 std::string time_str = str->cString();
\r
6525 int hour = atoi(time_str.substr(0, 2).c_str());
\r
6526 int min = atoi(time_str.substr(3, 2).c_str());
\r
6527 int sec = atoi(time_str.substr(6, 2).c_str());
\r
6528 DebugLog2("%02d:%02d:%02d", hour, min, sec);
\r
6531 time_t now = time(NULL);
\r
6533 if (localtime_s(&now_tm, &now) == 0)
\r
6535 int now_sec = now_tm.tm_hour * 3600 + now_tm.tm_min * 60 + now_tm.tm_sec;
\r
6536 int col_sec = hour * 3600 + min * 3600 + sec;
\r
6537 if (now_sec > col_sec)
\r
6541 now_tm.tm_hour = hour;
\r
6542 now_tm.tm_min = min;
\r
6543 now_tm.tm_sec = sec;
\r
6545 *time_var = mktime(&now_tm);
\r
6550 void Controller::getTimeWithEPG(Dictionary *epg, time_t *start, time_t *end)
\r
6552 if ((epg == NULL) || (start == NULL) || (end == NULL))
\r
6556 String *date = epg->stringForKey(KEY_EPG_DATE);
\r
6557 String *st = epg->stringForKey(KEY_EPG_START);
\r
6558 String *ed = epg->stringForKey(KEY_EPG_END);
\r
6559 if ((date == NULL) || (st == NULL) || (ed == NULL))
\r
6564 std::string dateStr = date->cString();
\r
6565 std::string stStr = st->cString();
\r
6566 std::string edStr = ed->cString();
\r
6568 tm_start.tm_year = atoi(dateStr.substr(0, 4).c_str()) - 1900;
\r
6569 tm_start.tm_mon = atoi(dateStr.substr(5, 2).c_str()) - 1;
\r
6570 tm_start.tm_mday = atoi(dateStr.substr(8, 2).c_str());
\r
6571 tm_start.tm_hour = atoi(stStr.substr(0, 2).c_str());
\r
6572 tm_start.tm_min = atoi(stStr.substr(3, 2).c_str());
\r
6573 tm_start.tm_sec = atoi(stStr.substr(6, 2).c_str());
\r
6576 tm_end.tm_year = atoi(dateStr.substr(0, 4).c_str()) - 1900;
\r
6577 tm_end.tm_mon = atoi(dateStr.substr(5, 2).c_str()) - 1;
\r
6578 tm_end.tm_mday = atoi(dateStr.substr(8, 2).c_str());
\r
6579 tm_end.tm_hour = atoi(edStr.substr(0, 2).c_str());
\r
6580 tm_end.tm_min = atoi(edStr.substr(3, 2).c_str());
\r
6581 tm_end.tm_sec = atoi(edStr.substr(6, 2).c_str());
\r
6582 if (stStr > edStr)
\r
6584 tm_end.tm_mday += 1;
\r
6586 *start = mktime(&tm_start);
\r
6587 *end = mktime(&tm_end);
\r