follow enigma2 pvr channel allocation api change
[enigma2-plugins.git] / vlcplayer / src / servicets / servicets.cpp
1 /*******************************************************************************
2  VLC Player Plugin by A. Lätsch 2007
3
4  This is free software; you can redistribute it and/or modify it under
5  the terms of the GNU General Public License as published by the Free
6  Software Foundation; either version 2, or (at your option) any later
7  version.
8 ********************************************************************************/
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <string>
14 #include <sys/socket.h>
15 #include <netdb.h>
16 #include <signal.h>
17 #include <time.h>
18 #include "servicets.h"
19 #include <lib/base/eerror.h>
20 #include <lib/base/object.h>
21 #include <lib/base/ebase.h>
22 #include <servicets.h>
23 #include <lib/service/service.h>
24 #include <lib/base/init_num.h>
25 #include <lib/base/init.h>
26 #include <lib/dvb/decoder.h>
27
28 #include <lib/dvb/pmt.h>
29
30 #define MAX(a,b) ((a) > (b) ? (a) : (b))
31
32 /********************************************************************/
33 /* eServiceFactoryTS                                                */
34 /********************************************************************/
35
36 eServiceFactoryTS::eServiceFactoryTS()
37 {
38         ePtr<eServiceCenter> sc;
39
40         eServiceCenter::getPrivInstance(sc);
41         if (sc)
42         {
43                 std::list<std::string> extensions;
44                 sc->addServiceFactory(eServiceFactoryTS::id, this, extensions);
45         }
46 }
47
48 eServiceFactoryTS::~eServiceFactoryTS()
49 {
50         ePtr<eServiceCenter> sc;
51
52         eServiceCenter::getPrivInstance(sc);
53         if (sc)
54                 sc->removeServiceFactory(eServiceFactoryTS::id);
55 }
56
57 DEFINE_REF(eServiceFactoryTS)
58
59 // iServiceHandler
60 RESULT eServiceFactoryTS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
61 {
62         ptr = new eServiceTS(ref);
63         return 0;
64 }
65
66 RESULT eServiceFactoryTS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
67 {
68         ptr=0;
69         return -1;
70 }
71
72 RESULT eServiceFactoryTS::list(const eServiceReference &, ePtr<iListableService> &ptr)
73 {
74         ptr=0;
75         return -1;
76 }
77
78 RESULT eServiceFactoryTS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
79 {
80         ptr = 0;
81         return -1;
82 }
83
84 RESULT eServiceFactoryTS::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
85 {
86         ptr = 0;
87         return -1;
88 }
89
90
91 /********************************************************************/
92 /* TSAudioInfo                                            */
93 /********************************************************************/
94 DEFINE_REF(TSAudioInfo);
95
96 void TSAudioInfo::addAudio(int pid, std::string lang, std::string desc, int type) {
97         StreamInfo as;
98         as.description = desc;
99         as.language = lang;
100         as.pid = pid;
101         as.type = type;
102         audioStreams.push_back(as);
103 }
104
105
106 /********************************************************************/
107 /* eServiceTS                                                       */
108 /********************************************************************/
109
110 eServiceTS::eServiceTS(const eServiceReference &url): m_pump(eApp, 1)
111 {
112         eDebug("ServiceTS construct!");
113         m_filename = url.path.c_str();
114         m_vpid = url.getData(0) == 0 ? 0x44 : url.getData(0);
115         m_apid = url.getData(1) == 0 ? 0x45 : url.getData(1);
116         m_audioInfo = 0;
117         m_destfd = -1;
118 }
119
120 eServiceTS::~eServiceTS()
121 {
122         eDebug("ServiceTS destruct!");
123         stop();
124 }
125
126 DEFINE_REF(eServiceTS);
127
128 size_t crop(char *buf)
129 {
130         size_t len = strlen(buf) - 1;
131         while (len > 0 && (buf[len] == '\r' || buf[len] == '\n')) {
132                 buf[len--] = '\0';
133         }
134         return len;
135 }
136
137 static int getline(char** pbuffer, size_t* pbufsize, int fd)
138 {
139         size_t i = 0;
140         int rc;
141         while (true) {
142                 if (i >= *pbufsize) {
143                         char *newbuf = (char*)realloc(*pbuffer, (*pbufsize)+1024);
144                         if (newbuf == NULL)
145                                 return -ENOMEM;
146                         *pbuffer = newbuf;
147                         *pbufsize = (*pbufsize)+1024;
148                 }
149                 rc = ::read(fd, (*pbuffer)+i, 1);
150                 if (rc <= 0 || (*pbuffer)[i] == '\n')
151                 {
152                         (*pbuffer)[i] = '\0';
153                         return rc <= 0 ? -1 : i;
154                 }
155                 if ((*pbuffer)[i] != '\r') i++;
156         }
157 }
158
159 int eServiceTS::openHttpConnection(std::string url)
160 {
161         std::string host;
162         int port = 80;
163         std::string uri;
164
165         int slash = url.find("/", 7);
166         if (slash > 0) {
167                 host = url.substr(7, slash-7);
168                 uri = url.substr(slash, url.length()-slash);
169         } else {
170                 host = url.substr(7, url.length()-7);
171                 uri = "";
172         }
173         int dp = host.find(":");
174         if (dp == 0) {
175                 port = atoi(host.substr(1, host.length()-1).c_str());
176                 host = "localhost";
177         } else if (dp > 0) {
178                 port = atoi(host.substr(dp+1, host.length()-dp-1).c_str());
179                 host = host.substr(0, dp);
180         }
181
182         struct hostent* h = gethostbyname(host.c_str());
183         if (h == NULL || h->h_addr_list == NULL)
184                 return -1;
185         int fd = socket(PF_INET, SOCK_STREAM, 0);
186         if (fd == -1)
187                 return -1;
188
189         struct sockaddr_in addr;
190         addr.sin_family = AF_INET;
191         addr.sin_addr.s_addr = *((in_addr_t*)h->h_addr_list[0]);
192         addr.sin_port = htons(port);
193
194         eDebug("connecting to %s", url.c_str());
195
196         if (connect(fd, (sockaddr*)&addr, sizeof(addr)) == -1) {
197                 std::string msg = "connect failed for: " + url;
198                 eDebug(msg.c_str());
199                 return -1;
200         }
201
202         std::string request = "GET ";
203         request.append(uri).append(" HTTP/1.1\n");
204         request.append("Host: ").append(host).append("\n");
205         request.append("Accept: */*\n");
206         request.append("Connection: close\n");
207         request.append("\n");
208         //eDebug(request.c_str());
209         write(fd, request.c_str(), request.length());
210
211         int rc;
212         size_t buflen = 1000;
213         char* linebuf = (char*)malloc(1000);
214
215         rc = getline(&linebuf, &buflen, fd);
216         //eDebug("RECV(%d): %s", rc, linebuf);
217         if (rc <= 0)
218         {
219                 close(fd);
220                 free(linebuf);
221                 return -1;
222         }
223
224         char proto[100];
225         int statuscode = 0;
226         char statusmsg[100];
227         rc = sscanf(linebuf, "%99s %d %99s", proto, &statuscode, statusmsg);
228         if (rc != 3 || statuscode != 200) {
229                 eDebug("wrong response: \"200 OK\" expected.");
230                 free(linebuf);
231                 close(fd);
232                 return -1;
233         }
234         eDebug("proto=%s, code=%d, msg=%s", proto, statuscode, statusmsg);
235         while (rc > 0)
236         {
237                 rc = getline(&linebuf, &buflen, fd);
238                 //eDebug("RECV(%d): %s", rc, linebuf);
239         }
240         free(linebuf);
241
242         return fd;
243 }
244
245 RESULT eServiceTS::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
246 {
247         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
248         return 0;
249 }
250
251 RESULT eServiceTS::start()
252 {
253         ePtr<eDVBResourceManager> rmgr;
254         eDVBResourceManager::getInstance(rmgr);
255         // FIXMEE hardcoded chid... this only works for one eServiceWebTS
256         eDVBChannelID chid;
257         chid.dvbnamespace = eDVBNamespace(0);
258         chid.transport_stream_id = eTransportStreamID(0);
259         chid.original_network_id = eOriginalNetworkID(0);
260         chid.pvr_source = "/eServiceTS";
261         if (rmgr->allocateChannel(chid, m_channel)) {
262                 eDebug("Cannot allocate pvr channel");
263                 return -1;
264         }
265         if (m_channel->getDemux(m_decodedemux, iDVBChannel::capDecode) != 0) {
266                 eDebug("Cannot allocate decode-demux");
267                 return -1;
268         }
269         if (m_decodedemux->getMPEGDecoder(m_decoder, 1) != 0) {
270                 eDebug("Cannot allocate MPEGDecoder");
271                 return -1;
272         }
273         if (m_destfd == -1)
274         {
275                 m_destfd = m_decodedemux->openDVR(O_WRONLY);
276                 if (m_destfd < 0)
277                 {
278                         eDebug("openDVR failed");
279                         return -1;
280                 }
281         }
282         m_decoder->setVideoPID(m_vpid, eDVBVideo::MPEG2);
283         m_decoder->setAudioPID(m_apid, eDVBAudio::aMPEG);
284         m_streamthread = new eStreamThread();
285         CONNECT(m_streamthread->m_event, eServiceTS::recv_event);
286         m_decoder->pause();
287         if (unpause() != 0) 
288                 return -1;
289         m_event(this, evStart);
290         return 0;
291 }
292
293 RESULT eServiceTS::stop()
294 {
295         if (m_destfd >= 0)
296         {
297                 ::close(m_destfd);
298                 m_destfd = -1;
299         }
300         printf("TS: %s stop\n", m_filename.c_str());
301         m_streamthread->stop();
302         m_decodedemux->flush();
303         m_audioInfo = 0;
304         m_channel = 0;
305         return 0;
306 }
307
308 void eServiceTS::recv_event(int evt)
309 {
310         eDebug("eServiceTS::recv_event: %d", evt);
311         switch (evt) {
312         case eStreamThread::evtEOS:
313                 m_decodedemux->flush();
314                 m_event((iPlayableService*)this, evEOF);
315                 break;
316         case eStreamThread::evtReadError:
317         case eStreamThread::evtWriteError:
318                 m_decoder->pause();
319                 m_event((iPlayableService*)this, evEOF);
320                 break;
321         case eStreamThread::evtSOS:
322                 m_event((iPlayableService*)this, evSOF);
323                 break;
324         case eStreamThread::evtStreamInfo:
325                 bool wasnull = !m_audioInfo;
326                 m_streamthread->getAudioInfo(m_audioInfo);
327                 if (m_audioInfo)
328                         eDebug("[servicets] %d audiostreams found", m_audioInfo->audioStreams.size());
329                 if (m_audioInfo && wasnull) {
330                         int sel = getCurrentTrack();
331                         if (sel < 0)
332                                 selectTrack(0);
333                         else if (m_audioInfo->audioStreams[sel].type != eDVBAudio::aMPEG)
334                                 selectTrack(sel);
335                 }
336                 break;
337         }
338 }
339
340 RESULT eServiceTS::pause(ePtr<iPauseableService> &ptr)
341 {
342         ptr = this;
343         return 0;
344 }
345
346 // iPausableService
347 RESULT eServiceTS::pause()
348 {
349         m_streamthread->stop();
350         m_decoder->pause();
351         return 0;
352 }
353
354 RESULT eServiceTS::unpause()
355 {
356         if (!m_streamthread->running())
357         {
358                 int is_streaming = !strncmp(m_filename.c_str(), "http://", 7);
359                 int srcfd = -1;
360
361                 if (is_streaming)
362                         srcfd = openHttpConnection(m_filename);
363                 else
364                         srcfd = ::open(m_filename.c_str(), O_RDONLY);
365
366                 if (srcfd < 0) {
367                         eDebug("Cannot open source stream: %s", m_filename.c_str());
368                         return 1;
369                 }
370
371                 m_decodedemux->flush();
372                 m_streamthread->start(srcfd, m_destfd);
373                 m_decoder->play();
374         }
375         else
376                 eDebug("unpause but thread already running!");
377         return 0;
378 }
379
380 // iSeekableService
381 RESULT eServiceTS::seek(ePtr<iSeekableService> &ptr)
382 {
383         ptr = this;
384         return 0;
385 }
386
387 RESULT eServiceTS::getLength(pts_t &pts)
388 {
389         return 0;
390 }
391
392 RESULT eServiceTS::seekTo(pts_t to)
393 {
394         return 0;
395 }
396
397 RESULT eServiceTS::seekRelative(int direction, pts_t to)
398 {
399         return 0;
400 }
401
402 RESULT eServiceTS::getPlayPosition(pts_t &pts)
403 {
404         return 0;
405 }
406
407 RESULT eServiceTS::setTrickmode(int trick)
408 {
409         return -1;
410 }
411
412 RESULT eServiceTS::isCurrentlySeekable()
413 {
414         return 1;
415 }
416
417 RESULT eServiceTS::info(ePtr<iServiceInformation>&i)
418 {
419         i = this;
420         return 0;
421 }
422
423 RESULT eServiceTS::getName(std::string &name)
424 {
425         name = m_filename;
426         size_t n = name.rfind('/');
427         if (n != std::string::npos)
428                 name = name.substr(n + 1);
429         return 0;
430 }
431
432 int eServiceTS::getInfo(int w)
433 {
434         return resNA;
435 }
436
437 std::string eServiceTS::getInfoString(int w)
438 {
439         return "";
440 }
441
442 int eServiceTS::getNumberOfTracks() {
443         if (m_audioInfo)
444                 return (int)m_audioInfo->audioStreams.size();
445         else
446                 return 0;
447 }
448
449 RESULT eServiceTS::selectTrack(unsigned int i) {
450         if (m_audioInfo) {
451                 m_apid = m_audioInfo->audioStreams[i].pid;
452                 eDebug("[servicets] audio track %d PID 0x%02x type %d\n", i, m_apid, m_audioInfo->audioStreams[i].type);
453                 m_decoder->setAudioPID(m_apid, m_audioInfo->audioStreams[i].type);
454                 m_decoder->set();
455                 return 0;
456         } else {
457                 return -1;
458         }
459 }
460
461 RESULT eServiceTS::getTrackInfo(struct iAudioTrackInfo &info, unsigned int n) {
462         if (m_audioInfo) {
463                 info.m_pid = m_audioInfo->audioStreams[n].pid;
464                 info.m_description = m_audioInfo->audioStreams[n].description;
465                 info.m_language = m_audioInfo->audioStreams[n].language;
466                 return 0;
467         } else {
468                 return -1;
469         }
470 }
471
472 int eServiceTS::getCurrentTrack() {
473         if (m_audioInfo) {
474                 for (size_t i = 0; i < m_audioInfo->audioStreams.size(); i++) {
475                         if (m_apid == m_audioInfo->audioStreams[i].pid) {
476                                 return i;
477                         }
478                 }
479         }
480         return -1;
481 }
482
483 /********************************************************************/
484 /* eStreamThread                                                       */
485 /********************************************************************/
486
487 DEFINE_REF(eStreamThread)
488
489 eStreamThread::eStreamThread(): m_messagepump(eApp, 0) {
490         CONNECT(m_messagepump.recv_msg, eStreamThread::recvEvent);
491         m_running = false;
492 }
493
494 eStreamThread::~eStreamThread() {
495 }
496
497 void eStreamThread::start(int srcfd, int destfd) {
498         m_srcfd = srcfd;
499         m_destfd = destfd;
500         m_stop = false;
501         m_audioInfo = 0;
502         run(IOPRIO_CLASS_RT);
503 }
504
505 void eStreamThread::stop() {
506         m_stop = true;
507         kill();
508 }
509
510 void eStreamThread::recvEvent(const int &evt)
511 {
512         m_event(evt);
513 }
514
515 RESULT eStreamThread::getAudioInfo(ePtr<TSAudioInfo> &ptr)
516 {
517         ptr = m_audioInfo;
518         return 0;
519 }
520
521 #define REGISTRATION_DESCRIPTOR 5
522 #define LANGUAGE_DESCRIPTOR 10
523
524 std::string eStreamThread::getDescriptor(unsigned char buf[], int buflen, int type)
525 {
526         int desc_len;
527         while (buflen > 1) {
528                 desc_len = buf[1];
529                 if (buf[0] == type) {
530                         char str[21];
531                         if (desc_len > 20) desc_len = 20;
532                         strncpy(str, (char*)buf+2, desc_len);
533                         str[desc_len] = '\0';
534                         return std::string(str);
535                 } else {
536                         buflen -= desc_len+2;
537                         buf += desc_len+2;
538                 }
539         }
540         return "";
541 }
542
543 bool eStreamThread::scanAudioInfo(unsigned char buf[], int len)
544 {
545         if (len < 1880)
546                 return false;
547
548         int adaptfield, pmtpid, offset;
549         unsigned char pmt[1188];
550         int pmtsize = 0;
551
552         for (int a=0; a < len - 188*4; a++) {
553                 if ( buf[a] != 0x47 || buf[a + 188] != 0x47 || buf[a + 376] != 0x47 )
554                         continue; // TS Header
555
556                 if ((0x40 & buf[a + 1]) == 0) // start
557                         continue;
558
559                 if ((0xC0 & buf[a + 3]) != 0) // scrambling
560                         continue;
561
562                 adaptfield = (0x30 & buf[a + 3]) >> 4;
563
564                 if ((adaptfield & 1) == 0) // adapt - no payload
565                         continue;
566
567                 offset = adaptfield == 3 ? 1 + (0xFF & buf[a + 4]) : 0; //adaptlength
568
569                 if (buf[a + offset + 4] != 0 || buf[a + offset + 5] != 2 || (0xF0 & buf[a + offset + 6]) != 0xB0)
570                 {
571                         a += 187;
572                         continue;
573                 }
574
575                 pmtpid = (0x1F & buf[a + 1])<<8 | (0xFF & buf[a + 2]);
576                 memcpy(pmt + pmtsize, buf + a + 4 + offset, 184 - offset);
577                 pmtsize += 184 - offset;
578
579                 if (pmtsize >= 1000)
580                         break;
581         }
582
583         if (pmtsize == 0) return false;
584
585         int pmtlen = (0x0F & pmt[2]) << 8 | (0xFF & pmt[3]);
586         std::string lang;
587         std::string pd_type;
588         ePtr<TSAudioInfo> ainfo = new TSAudioInfo();
589
590         for (int b=8; b < pmtlen-4 && b < pmtsize-6; b++)
591         {
592                 if ( (0xe0 & pmt[b+1]) != 0xe0 )
593                         continue;
594
595                 int pid = (0x1F & pmt[b+1])<<8 | (0xFF & pmt[b+2]);
596
597                 switch(pmt[b])
598                 {
599                 case 1:
600                 case 2: // MPEG Video
601                         //addVideo(pid, "MPEG2");
602                         break;
603
604                 case 0x1B: // H.264 Video
605                         //addVideo(pid, "H.264");
606                         break;
607
608                 case 3:
609                 case 4: // MPEG Audio
610                         lang = getDescriptor(pmt+b+5, pmt[b+4], LANGUAGE_DESCRIPTOR);
611                         ainfo->addAudio(pid, lang, "MPEG", eDVBAudio::aMPEG);
612                         break;
613
614                 case 0x80:
615                 case 0x81:  //private data of AC3 in ATSC
616                 case 0x82:
617                 case 0x83:
618                 case 6:
619                         lang = getDescriptor(pmt+b+5, pmt[b+4], LANGUAGE_DESCRIPTOR);
620                         pd_type = getDescriptor(pmt+b+5, pmt[b+4], REGISTRATION_DESCRIPTOR);
621                         if (pd_type == "AC-3")
622                                 ainfo->addAudio(pid, lang, pd_type, eDVBAudio::aAC3);
623                         break;
624                 }
625                 b += 4 + pmt[b+4];
626         }
627         if (ainfo->audioStreams.size() > 0) {
628                 m_audioInfo = ainfo;
629                 return true;
630         } else {
631                 return false;
632         }
633 }
634
635 void eStreamThread::thread() {
636         const int bufsize = 40000;
637         unsigned char buf[bufsize];
638         bool eof = false;
639         fd_set rfds;
640         fd_set wfds;
641         struct timeval timeout;
642         int rc,r,w,maxfd;
643         time_t next_scantime = 0;
644         bool sosSend = false;
645         m_running = true;
646
647         r = w = 0;
648         hasStarted();
649         eDebug("eStreamThread started");
650         while (!m_stop) {
651                 pthread_testcancel();
652                 FD_ZERO(&rfds);
653                 FD_ZERO(&wfds);
654                 maxfd = 0;
655                 timeout.tv_sec = 1;
656                 timeout.tv_usec = 0;
657                 if (r < bufsize) {
658                         FD_SET(m_srcfd, &rfds);
659                         maxfd = MAX(maxfd, m_srcfd);
660                 }
661                 if (w < r) {
662                         FD_SET(m_destfd, &wfds);
663                         maxfd = MAX(maxfd, m_destfd);
664                 }
665                 rc = select(maxfd+1, &rfds, &wfds, NULL, &timeout);
666                 if (rc == 0) {
667                         eDebug("eStreamThread::thread: timeout!");
668                         continue;
669                 }
670                 if (rc < 0) {
671                         eDebug("eStreamThread::thread: error in select (%d)", errno);
672                         break;
673                 }
674                 if (FD_ISSET(m_srcfd, &rfds)) {
675                         rc = ::read(m_srcfd, buf+r, bufsize - r);
676                         if (rc < 0) {
677                                 eDebug("eStreamThread::thread: error in read (%d)", errno);
678                                 m_messagepump.send(evtReadError);
679                                 break;
680                         } else if (rc == 0) {
681                                 eof = true;
682                         } else {
683                                 if (!sosSend) {
684                                         sosSend = true;
685                                         m_messagepump.send(evtSOS);
686                                 }
687                                 r += rc;
688                                 if (r == bufsize) eDebug("eStreamThread::thread: buffer full");
689                         }
690                 }
691                 if (FD_ISSET(m_destfd, &wfds) && (w < r) && ((r > bufsize/4) || eof)) {
692                         rc = ::write(m_destfd, buf+w, r-w);
693                         if (rc < 0) {
694                                 eDebug("eStreamThread::thread: error in write (%d)", errno);
695                                 m_messagepump.send(evtWriteError);
696                                 break;
697                         }
698                         w += rc;
699                         //eDebug("eStreamThread::thread: buffer r=%d w=%d",r,w);
700                         if (w == r) {
701                                 if (time(0) >= next_scantime) {
702                                         if (scanAudioInfo(buf, r)) {
703                                                 m_messagepump.send(evtStreamInfo);
704                                                 next_scantime = time(0) + 1;
705                                         }
706                                 }
707                                 w = r = 0;
708                         }
709                 }
710                 if (eof && (r==w)) {
711                         m_messagepump.send(evtEOS);
712                         break;
713                 }
714         }
715         eDebug("eStreamThread end");
716 }
717
718 void eStreamThread::thread_finished() {
719         if (m_srcfd >= 0)
720                 ::close(m_srcfd);
721         eDebug("eStreamThread closed");
722         m_running = false;
723 }
724
725 eAutoInitPtr<eServiceFactoryTS> init_eServiceFactoryTS(eAutoInitNumbers::service+1, "eServiceFactoryTS");
726
727 PyMODINIT_FUNC
728 initservicets(void)
729 {
730         Py_InitModule("servicets", NULL);
731 }