From: osx86_pt1 Date: Fri, 18 Mar 2016 15:21:01 +0000 (+0900) Subject: 録画予約 X-Git-Url: http://git.osdn.net/view?p=iptd%2FiPTd.git;a=commitdiff_plain;h=e40ac8ec84bc1dbce708f3f38afb48cffb7e8900 録画予約 --- diff --git a/iPTd_R2.sdf b/iPTd_R2.sdf index 4b2e466..5c676f5 100644 Binary files a/iPTd_R2.sdf and b/iPTd_R2.sdf differ diff --git a/src/ry0/iPTd/Controller.cpp b/src/ry0/iPTd/Controller.cpp index a33c7bb..52e902e 100644 --- a/src/ry0/iPTd/Controller.cpp +++ b/src/ry0/iPTd/Controller.cpp @@ -55,14 +55,10 @@ const char *Controller::_plist_prefix = "com.gmail.tim.and.pom"; Controller::Controller() { DebugLog3("%s", __FUNCTION__); - -// InitializeCriticalSection(&_cs); } Controller::~Controller() { -// DeleteCriticalSection(&_cs); - DebugLog3("%s", __FUNCTION__); } @@ -171,8 +167,7 @@ void Controller::detectIdle() // ARP生成 AutoreleasePool *pool = AutoreleasePool::alloc()->init(); - // lock - EnterCriticalSection(&_cs); + RaymLock(this); // サスペンド可能か確認 if (canSuspend()) @@ -220,8 +215,7 @@ void Controller::detectIdle() DebugLog3("found: %d, _idle_count: %d, limit: %d", found, _idle_count, limit); if (_idle_count >= limit) { - // unlock - LeaveCriticalSection(&_cs); + RaymUnlock(this); // サスペンド前にARPを解放しておく pool->release(); @@ -236,8 +230,7 @@ void Controller::detectIdle() // 再度 ARPを用意 pool = AutoreleasePool::alloc()->init(); - // lock - EnterCriticalSection(&_cs); + RaymLock(this); // アイドルカウンタをクリア _idle_count = 0; @@ -249,8 +242,7 @@ void Controller::detectIdle() _idle_count = 0; } - // unlock - LeaveCriticalSection(&_cs); + RaymUnlock(this); // ARP解放 pool->release(); @@ -260,8 +252,7 @@ void Controller::detectNonIdle() { DebugLog2("Controller::detectNonIdle()"); - // lock - EnterCriticalSection(&_cs); + RaymLock(this); if (_idle_count > 0) { @@ -269,8 +260,7 @@ void Controller::detectNonIdle() } _idle_count = 0; - // unlock - LeaveCriticalSection(&_cs); + RaymUnlock(this); } #ifndef _WIN32 diff --git a/src/ry0/iPTd/Controller.h b/src/ry0/iPTd/Controller.h index 2984fc3..db63a55 100644 --- a/src/ry0/iPTd/Controller.h +++ b/src/ry0/iPTd/Controller.h @@ -16,7 +16,7 @@ #include "ry0/iPTd/HTTPD.h" #define VERSION "1.00" -#define REVISION 12 +#define REVISION 13 namespace ry0 { diff --git a/src/ry0/iPTd/HTTPD.cpp b/src/ry0/iPTd/HTTPD.cpp index 8693e8a..5d31a14 100644 --- a/src/ry0/iPTd/HTTPD.cpp +++ b/src/ry0/iPTd/HTTPD.cpp @@ -73,12 +73,12 @@ HTTPResponse *HTTPD::request(HTTPRequest *request, SOCKADDR_IN *client) // 初期化チェック bool flag = false; - EnterCriticalSection(&_cs); -// flag = _initialized; - LeaveCriticalSection(&_cs); + RaymLock(_controller); + flag = _controller->_initialized; + RaymUnlock(_controller); if (!flag) { -// return NULL; + return NULL; } HTTPResponse *response = NULL; @@ -89,24 +89,28 @@ HTTPResponse *HTTPD::request(HTTPRequest *request, SOCKADDR_IN *client) // URI String *uri = request->URI(); DebugLog0("request: %s\n", uri->cString()); - if (uri->isMatch("^/config.xml$")) + if (uri->isMatch("^/config\\.xml$")) { RaymLock(_controller); response = responseWithDictionary(request, _controller->_props); RaymUnlock(_controller); } - else if (uri->isMatch("^/status.xml$")) + else if (uri->isMatch("^/status\\.xml$")) { RaymLock(_controller); response = responseWithDictionary(request, _controller->_status); RaymUnlock(_controller); } - // - // tuner control - // + else if (uri->isMatch("^/iptv\\.m3u8$")) + { + return responseForPlaylist(request, client); + } + else if (uri->isMatch("^/regist\\.cgi")) + { + response = responseForRegistCGI(request, client); + } else if (uri->isMatch("^/[0-9]{3}/")) { - // String::substringWithRange() の実装は後回しなので。。 std::string s = uri->cString(); int tuner = atoi(s.substr(1, 3).c_str()); if ((0 <= tuner) && (tuner < _controller->_tuner_count)) @@ -115,7 +119,7 @@ HTTPResponse *HTTPD::request(HTTPRequest *request, SOCKADDR_IN *client) } } - else if (uri->isMatch("^/iptd.log$")) + else if (uri->isMatch("^/iptd\\.log$")) { String *path = _controller->_system_path->stringByAppendingPathComponent("log"); if (path != NULL) @@ -166,16 +170,11 @@ HTTPResponse *HTTPD::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *clie } } - if (uri->isMatch("^/iptv.m3u8$")) - { - return responseForPlaylist(request, client); - } - // // チャンネル設定 // /ttt/channel=nnn // - else if (uri->isMatch("^/[0-9]{3}/channel=[0-9]{1,3}$") && (cgi == NULL)) + if (uri->isMatch("^/[0-9]{3}/channel=[0-9]{1,3}$") && (cgi == NULL)) { String *ch = uri->substringFromIndex(13); if (ch == NULL) @@ -499,7 +498,7 @@ HTTPResponse *HTTPD::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *clie } } - SOCKADDR_IN dst_addr; +// SOCKADDR_IN dst_addr; if (p_host != NULL) { } @@ -570,102 +569,166 @@ HTTPResponse *HTTPD::requestTunerControl(HTTPRequest *request, SOCKADDR_IN *clie return result; } -HTTPResponse *HTTPD::responseForPlaylist(HTTPRequest *request, SOCKADDR_IN *client) +HTTPResponse *HTTPD::responseForRegistCGI(HTTPRequest *request, SOCKADDR_IN *client) { - HTTPResponse *result = NULL; - // http://bit.ly/iptv_feb2015 - -#if 0 + DebugLog2("Controller::responseForRegistCGI()"); -#EXTM3U - -#EXTINF:-1, [COLOR yellow]Updated 15/04/2015 @ 03:45 [/COLOR] -plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM -#EXTINF:-1, [COLOR green] --Uk Live Tv--[/COLOR] -plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM -#EXTINF:-1, [COLOR green] --Free Collection of IPTV sports links--[/COLOR] -plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM -#EXTINF:-1, [COLOR red] --Links will go down. Please note that it will take time to update--[/COLOR] -plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM -#EXTINF:-1, [COLOR red] --Please contact me at the husham.com website--[/COLOR] -plugin://plugin.video.youtube/?action=play_video&videoid=eMduu81gNgM + HTTPResponse *result = NULL; -#EXTINF:-1, Sky sports news -rtmp://89.248.172.159:443/liverepeater playpath=35 swfUrl=http://popeoftheplayers.eu/atdedead.swf pageUrl=http://popeoftheplayers.eu/crichd.php?id=35&width=600&height=450 token=#atd%#$ZH -#EXTINF:-1,Bt sports 1 -rtmp://80.82.78.87:443/liverepeater/starsp pageUrl=http://xxxxxxxxxxxxxxxx.xx/rtmpe://strm.dcast.tv:1935/live/asdfadfaa/pageUrl=http://xxxxx.xx/rtmp://80.82.64.90:443/liverepeater/79/pageUrl=http://filotv.pw/rtmpe://strm.ukcast.tv:1935/redirect/FUNKTSN/pageUrl=http://ukcast.tv/rtmp://173.192.81.176:443/liverepeater/stream1/token%ZZri(nKa@#Z/pageUrl=http://hdcast.org/cdn.kingofplayers.com/rtmpe://46.246.29.152:1935/redirect/HDMNBC playpath=41?18?49?33?48?38?11 pageUrl=http://popeoftheplayers.eu/hdcast.org/rtmp://31.220.0.134:1935/live/tsn2/pageUrl=http://www.eucast.tv/rtmp://195.154.236.152:80/liverepeater/141449/pageUrl=http://goodcast.pw/rtmp://77.81.98.134/tv/bt1h28qn?v=pageUrl=http://castok.com/rtmp://89.46.102.70:443/liveedge/bt1pageUrl=http://hqstreams.tv/rtmpe://play.finecast.tv/live/hqbt1page/playpath=42?finecast.tv/rtmpe://cdn.hdcast.org:1935/redirect/swfUrl=http://www.hdcast.org/aplayer/jwplayer.flash.swfpageUrl=http://www.hdcast.org/token=Fo5_n0w?U.rA6l3-70w47ch@#8x12pX@ token=#atd%#$ZH + // CGIリクエストとして解析 + Dictionary *cgi = request->parseAsCGI(); + if (cgi != NULL) + { + // CGIパスが一致しているか + if ((cgi->stringForKey(HTTPRequest::KEY_CGI) != NULL) && (cgi->stringForKey(HTTPRequest::KEY_CGI)->isEqualToString("/regist.cgi"))) + { + // パラメータがあるか + Array *params = cgi->arrayForKey(HTTPRequest::KEY_PARAMS); + if (params != NULL) + { + // パラメータ数が2か + if (params->count() == 2) + { + // パラメータのチェック + String *service_id = NULL; + String *event_id = NULL; -#endif + for (uint i = 0; i < params->count(); ++i) + { + Dictionary *param = (Dictionary *)params->objectAtIndex(i); + String *value = param->stringForKey("service_id"); + if ((value != NULL) && value->isMatch("^\\d+$")) + { + service_id = value; + } + value = param->stringForKey("event_id"); + if ((value != NULL) && value->isMatch("^\\d+$")) + { + event_id = value; + } + } + // 有効なパラメータか + if ((service_id != NULL) && (event_id != NULL)) + { + DebugLog2("valid request"); - std::string contents; - contents = "#EXTM3U\r\n"; - contents += "\r\n"; + if (_controller->_reservation->reserve(service_id->intValue(), event_id->intValue())) + { + result = responseForSuccess(request); + } + else + { + result = responseForFailed(request); + } + } + } -/* - Dictionary *tuner_channel_to_udp = _streaming_ctrls->dictionaryForKey(KEY_MAPPING_TUNER_CHANNEL_TO_UDP); - if (tuner_channel_to_udp != NULL) - { - Tuner::Type types[] = {Tuner::ISDB_T, Tuner::ISDB_S}; - for (int t = 0; t < sizeof(types) / sizeof(Tuner::Type); ++t) - { - for (int i = 0; i < _tunerCount; ++i) - { - if (isTunerInitialized(i) && (_tuners[i]->type() == types[t])) + // パラメータ数が9か + else if (params->count() == 9) { - uint ch_max = ((types[t] == Tuner::ISDB_T) ? Tuner::MAX_CHANNELS_ISDB_T : Tuner::MAX_CHANNELS_ISDB_S); - for (uint ch = 0; ch <= ch_max; ++ch) + // パラメータのチェック + String *service_id = NULL; + String *year = NULL; + String *month = NULL; + String *day = NULL; + String *start_hour = NULL; + String *start_min = NULL; + String *end_hour = NULL; + String *end_min = NULL; + String *repeat = NULL; + + struct { + const char *name; + String **variable; + const char *regex; + } + cgi[] = + { + {"service_id", &service_id, "^\\d+$"}, + {"year", &year, "^\\d{4}$"}, + {"month", &month, "^([1-9]|1[0-2])$"}, + {"day", &day, "^([1-9]|[12][0-9]|3[01])$"}, + {"start_hour", &start_hour, "^\\d{2}$"}, + {"start_min", &start_min, "^\\d{2}$"}, + {"end_hour", &end_hour, "^\\d{2}$"}, + {"end_min", &end_min, "^\\d{2}$"}, + {"repeat", &repeat, "^(off|everyday|weekly|weekday)$"}, + {NULL, NULL, NULL} + }; + + for (uint i = 0; cgi[i].name != NULL; ++i) { - if (isChannelEnabled(i, ch)) + for (uint j = 0; j < params->count(); ++j) { - char tuner_and_channel[10]; - sprintf_s(tuner_and_channel, "%d,%d", i, ch); - char *chstr = strchr(tuner_and_channel, ','); - if (chstr != NULL) + Dictionary *param = (Dictionary *)params->objectAtIndex(j); + String *value = param->stringForKey(cgi[i].name); + if ((value != NULL) && value->isMatch(cgi[i].regex)) { - ++chstr; + *(cgi[i].variable) = value; + break; } + } + } - NSString *udp_str = tuner_channel_to_udp->stringForKey(tuner_and_channel); - if (udp_str != NULL) - { - contents += "#EXTINF:-1 tvg-id=\""; - contents += tuner_and_channel; - contents += "\" tvg-logo=\""; - contents += ((types[t] == Tuner::ISDB_T) ? "t_" : "s_"); - if (chstr != NULL) - { - contents += chstr; - } - else - { - contents += "ffff"; - } - contents += "\" group-title=\""; - contents += _tuners[i]->name(); - contents += "\", "; - NSString *station_name = stationName(types[t], ch); - if (station_name != NULL) - { - contents += station_name->cString(); - } - else - { - contents += tuner_and_channel; - } - contents += "\r\n"; - contents += "udp://0.0.0.0:"; - contents += udp_str->cString(); - contents += "\r\n"; - } + // 有効なパラメータか + if ((service_id != NULL) && (year != NULL) && (month != NULL) && (day != NULL) && + (start_hour != NULL) && (start_min != NULL) && (end_hour != NULL) && (end_min != NULL) && (repeat != NULL)) + { + // + DebugLog1("valid param"); + + Dictionary *epg = Dictionary::dictionaryWithCapacity(0); + + // 日付 + epg->setString(String::stringWithFormat("%s/%02d/%02d", year->cString(), month->intValue(), day->intValue()), KEY_EPG_DATE); + + // 開始時刻 + epg->setString(String::stringWithFormat("%s:%s:00", start_hour->cString(), start_min->cString()), KEY_EPG_START); + + // 終了時刻 + epg->setString(String::stringWithFormat("%s:%s:00", end_hour->cString(), end_min->cString()), KEY_EPG_END); + + // 繰り返し + epg->setString(repeat, KEY_EPG_REPEAT); + + // Service ID + epg->setString(service_id, KEY_EPG_SERVICE_ID); + + // Status + epg->setString("ready", KEY_EPG_STATUS); + + if (_controller->_reservation->reserve(epg)) + { + result = responseForSuccess(request); + } + else + { + result = responseForFailed(request); } } } } } - } -*/ + + return result; +} + + +HTTPResponse *HTTPD::responseForPlaylist(HTTPRequest *request, SOCKADDR_IN *client) +{ + HTTPResponse *result = NULL; + + std::string contents; + contents = "#EXTM3U\r\n"; + contents += "\r\n"; + + contents += "#EXTINF:-1, video\r\n"; + contents += "http://172.19.29.9:50080/iptv/video.m3u8\r\n"; + contents += "#EXTINF:-1, TV\r\n"; + contents += "http://172.19.29.9:50080/iptv/tv.m3u8\r\n"; + String *text = String::stringWithUTF8String(contents.c_str()); if (text != NULL) { diff --git a/src/ry0/iPTd/HTTPD.h b/src/ry0/iPTd/HTTPD.h index c55af0c..2f9644d 100644 --- a/src/ry0/iPTd/HTTPD.h +++ b/src/ry0/iPTd/HTTPD.h @@ -40,6 +40,7 @@ public: NET::HTTPResponse *request(NET::HTTPRequest *request, struct sockaddr_in *client); NET::HTTPResponse *requestTunerControl(NET::HTTPRequest *request, struct sockaddr_in *client, int tuner); + NET::HTTPResponse *responseForRegistCGI(NET::HTTPRequest *request, struct sockaddr_in *client); NET::HTTPResponse *responseForPlaylist(NET::HTTPRequest *request, struct sockaddr_in *client); diff --git a/src/ry0/iPTd/Reservation.cpp b/src/ry0/iPTd/Reservation.cpp index c08bcd4..5d47374 100644 --- a/src/ry0/iPTd/Reservation.cpp +++ b/src/ry0/iPTd/Reservation.cpp @@ -246,6 +246,150 @@ void Reservation::systemResumed() } // +// 録画予約:サービスID/イベントID指定 +// EPGデータから指定のサービスID/イベントIDのEPGを取り出し、EPG指定の録画予約をコール +// +bool Reservation::reserve(int service_id, int event_id) +{ + DebugLog2("Reservation::reserve(service_id, event_id)"); + + bool result = false; + + RaymLock(_controller); + + if (_epgs != NULL) + { + Dictionary *events = _epgs->dictionaryForKey(String::stringWithFormat("%d", service_id)); + if (events != NULL) + { + Dictionary *epg = events->dictionaryForKey(String::stringWithFormat("%d", event_id)); + if (epg != NULL) + { + result = reserve(epg); + } + } + } + + RaymUnlock(_controller); + + return result; +} + +// +// 録画予約:EPG指定 +// EPGからサービスIDを取り出し、チューナ情報を検索して一致するサービスIDがあったらチューナ/EPG指定の録画予約を試行 +// +bool Reservation::reserve(Dictionary *in_epg) +{ + DebugLog2("Reservation::reserve(epg)"); + + bool result = false; + + RaymLock(_controller); + + while (in_epg != NULL) + { + // EPGを複製 + Dictionary *epg = Dictionary::dictionaryWithDictionary(in_epg); + if (epg == NULL) + { + DebugLog3("Dictionary::dictionaryWithDictionary() ng."); + break; + } + + // サービスID取得 + String *service_id = epg->stringForKey(KEY_EPG_SERVICE_ID); + if (service_id == NULL) + { + DebugLog3("epg->stringForKey(KEY_EPG_SERVICE_ID) ng."); + break; + } + DebugLog3("service_id: %s\n", service_id->cString()); + + // 全チューナ情報取得 + Dictionary *tunerInfos = _controller->_props->dictionaryForKey(KEY_TUNERS); + if (tunerInfos == NULL) + { + DebugLog3("_props->dictionaryForKey(KEY_TUNERS) ng."); + break; + } + + // チューナを検索 + for (int i = 0; (!result) && (i < _controller->_tuner_count); ++i) + { + // チューナ情報取得 + Dictionary *tunerInfo = tunerInfos->dictionaryForKey(_tuners[i]->name()); + if (tunerInfo == NULL) + { + DebugLog3("tunerInfos->dictionaryForKey(_tuners[%d]->name()) ng.", i); + continue; + } + + // 全チャンネル情報取得 + Dictionary *channels = tunerInfo->dictionaryForKey(KEY_CHANNELS); + if (channels == NULL) + { + DebugLog3("tunerInfo->dictionaryForKey(KEY_CHANNELS) ng."); + continue; + } + + // キー取得 + Array *chkeys = channels->allKeys(); + for (uint ch = 0; ch < chkeys->count(); ++ch) + { + // チャンネル情報取得 + Dictionary *channel = channels->dictionaryForKey((String *)chkeys->objectAtIndex(ch)); + if (channel == NULL) + { + DebugLog3("channels->dictionaryForKey() ng."); + continue; + } + + // 全サービス情報取得 + Array *services = (Array *)channel->objectForKey(KEY_SERVICES); + if (services == NULL) + { + DebugLog3("channel->objectForKey() ng."); + continue; + } + + for (uint s = 0; s < services->count(); ++s) + { + // サービス情報取得 + Dictionary *service = (Dictionary *)services->objectAtIndex(s); + if (service == NULL) + { + DebugLog3("service->objectAtIndex() ng."); + continue; + } + + // サービスIDを比較 + String *sid = service->stringForKey(KEY_SERVICE_ID); + if ((sid != NULL) && sid->isEqualToString(service_id)) + { + // チャンネルを設定 + epg->setString((String *)chkeys->objectAtIndex(ch), KEY_EPG_CHANNEL); + + // 録画予約 + result = reserve(i, epg); + + // チャンネルループのカウンタを更新(=ループを終了させる) + ch = chkeys->count(); + break; + } + } + } + } + + break; + } + + RaymUnlock(_controller); + + return result; +} + +// // 録画予約:チューナ/EPG指定 // bool Reservation::reserve(int tuner, Dictionary *in_epg) @@ -749,14 +893,13 @@ bool Reservation::collectEPGs(Tuner::Type type) // EPG取集 collectEPGsForTuner(tuner, ((type == Tuner::ISDB_S) ? DEF_COLLECT_EPG_LIMIT_S : DEF_COLLECT_EPG_LIMIT_T)); - // キャンセル確認 - EnterCriticalSection(&_cs); + RaymLock(_controller); if (_cancel_epg_collect) { ch = Tuner::MAX_CHANNELS_ISDB_T + 1; canceled = true; } - LeaveCriticalSection(&_cs); + RaymUnlock(_controller); // キャンセル確認 // 終了不可 -> 録画待機中/録画中 なので、収集は諦める @@ -772,14 +915,12 @@ bool Reservation::collectEPGs(Tuner::Type type) // 元のチャンネルに戻す _tuners[tuner]->setChannel(channel); - // lock - EnterCriticalSection(&_cs); + RaymLock(_controller); // チューナをアンロック _tuners[tuner]->unlock(); - // unlock - LeaveCriticalSection(&_cs); + RaymUnlock(_controller); if (canceled) { diff --git a/src/ry0/iPTd/Streaming.cpp b/src/ry0/iPTd/Streaming.cpp index 6fe7748..da4f53d 100644 --- a/src/ry0/iPTd/Streaming.cpp +++ b/src/ry0/iPTd/Streaming.cpp @@ -255,8 +255,7 @@ void Streaming::timerExpired(Timer *timer, void *user_info) int channel = tuner_and_channel->substringFromIndex(r.location + 1)->intValue(); DebugLog3("tuner: %d, channel: %d", tuner, channel); - // lock - EnterCriticalSection(&_cs); + RaymLock(_controller); // 非ストリーミング中 かつ 非レコーディング中 または チャンネルが同じ 場合 if (!_tuners[tuner]->isStreaming() && (!_tuners[tuner]->isRecording() || _tuners[tuner]->channel() == channel)) @@ -289,8 +288,7 @@ void Streaming::timerExpired(Timer *timer, void *user_info) } } - // unlock - LeaveCriticalSection(&_cs); + RaymUnlock(_controller); } } }