1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <limits.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <sys/poll.h>
25 #include <sys/ioctl.h>
26 #include <linux/dvb/dmx.h>
27 #include <linux/dvb/frontend.h>
28 
29 #define LOG_TAG "DvbManager"
30 #include "logging.h"
31 
32 #include "DvbManager.h"
33 
currentTimeMillis()34 static double currentTimeMillis() {
35     struct timeval tv;
36     gettimeofday(&tv, (struct timezone *) NULL);
37     return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
38 }
39 
DvbManager(JNIEnv * env,jobject)40 DvbManager::DvbManager(JNIEnv *env, jobject)
41         : mFeFd(-1),
42           mDvrFd(-1),
43           mPatFilterFd(-1),
44           mDvbApiVersion(DVB_API_VERSION_UNDEFINED),
45           mFeHasLock(false),
46           mHasPendingTune(false) {
47   jclass clazz = env->FindClass("com/android/tv/tuner/TunerHal");
48   mOpenDvbFrontEndMethodID =
49       env->GetMethodID(clazz, "openDvbFrontEndFd", "()I");
50   mOpenDvbDemuxMethodID = env->GetMethodID(clazz, "openDvbDemuxFd", "()I");
51   mOpenDvbDvrMethodID = env->GetMethodID(clazz, "openDvbDvrFd", "()I");
52   memset(&mDeliverySystemTypes, DELIVERY_SYSTEM_UNDEFINED,
53       sizeof(mDeliverySystemTypes));
54 }
55 
~DvbManager()56 DvbManager::~DvbManager() {
57     reset();
58 }
59 
isFeLocked()60 bool DvbManager::isFeLocked() {
61     if (mDvbApiVersion == DVB_API_VERSION5) {
62         fe_status_t status;
63         if (ioctl(mFeFd, FE_READ_STATUS, &status) < 0) {
64             return false;
65         }
66         if (status & FE_HAS_LOCK) {
67             return true;
68         }
69     } else {
70         struct pollfd pollFd;
71         pollFd.fd = mFeFd;
72         pollFd.events = POLLIN;
73         pollFd.revents = 0;
74         int poll_result = poll(&pollFd, NUM_POLLFDS, FE_POLL_TIMEOUT_MS);
75         if (poll_result > 0 && (pollFd.revents & POLLIN)) {
76             struct dvb_frontend_event kevent;
77             memset(&kevent, 0, sizeof(kevent));
78             if (ioctl(mFeFd, FE_GET_EVENT, &kevent) == 0) {
79                 return (kevent.status & FE_HAS_LOCK);
80             }
81         }
82     }
83     return false;
84 }
85 
86 // This function gets the signal strength from tuner.
87 // Output can be:
88 // -3 means File Descriptor invalid,
89 //    or DVB version is not supported,
90 //    or ERROR while communicate with hardware via ioctl.
91 // int signal returns the raw signal strength value.
getSignalStrength()92 int DvbManager::getSignalStrength() {
93     // TODO(b/74197177): add support for DVB V5.
94     if (mFeFd == -1 || mDvbApiVersion != DVB_API_VERSION3) {
95         return -3;
96     }
97     uint16_t strength = 0;
98     // ERROR code from ioctl can be:
99     // EBADF means fd is not a valid open file descriptor
100     // EFAULT means status points to invalid address
101     // ENOSIGNAL means there is no signal, thus no meaningful signal strength
102     // ENOSYS means function not available for this device
103     //
104     // The function used to communicate with tuner in DVB v3 is
105     // ioctl(fd, request, &strength)
106     // int fd is the File Descriptor, can't be -1
107     // int request is the request type,
108     // FE_READ_SIGNAL_STRENGTH for getting signal strength
109     // uint16_t *strength stores the strength value returned from tuner
110     if (ioctl(mFeFd, FE_READ_SIGNAL_STRENGTH, &strength) == -1) {
111         ALOGD("FE_READ_SIGNAL_STRENGTH failed, %s", strerror(errno));
112         return -3;
113     }
114     return strength;
115 }
116 
tune(JNIEnv * env,jobject thiz,const int frequency,const char * modulationStr,int timeout_ms)117 int DvbManager::tune(JNIEnv *env, jobject thiz,
118         const int frequency, const char *modulationStr, int timeout_ms) {
119     return tuneInternal(env, thiz, DELIVERY_SYSTEM_UNDEFINED, frequency,
120                modulationStr, timeout_ms);
121 }
122 
tune(JNIEnv * env,jobject thiz,const int deliverySystemType,const int frequency,const char * modulationStr,int timeout_ms)123 int DvbManager::tune(JNIEnv *env, jobject thiz,
124         const int deliverySystemType, const int frequency,
125         const char *modulationStr, int timeout_ms) {
126     return tuneInternal(env, thiz, deliverySystemType, frequency,
127                modulationStr, timeout_ms);
128 }
129 
tuneInternal(JNIEnv * env,jobject thiz,const int deliverySystemType,const int frequency,const char * modulationStr,int timeout_ms)130 int DvbManager::tuneInternal(JNIEnv *env, jobject thiz,
131         const int deliverySystemType, const int frequency,
132         const char *modulationStr, int timeout_ms) {
133     resetExceptFe();
134 
135     if (openDvbFe(env, thiz) != 0) {
136         return -1;
137     }
138 
139     if (frequency < 0) {
140         return -1;
141     }
142 
143     if (mDvbApiVersion == DVB_API_VERSION_UNDEFINED) {
144         struct dtv_property testProps[1] = {
145             { .cmd = DTV_DELIVERY_SYSTEM }
146         };
147         struct dtv_properties feProp = {
148             .num = 1, .props = testProps
149         };
150         // On fugu, DVB_API_VERSION is 5 but it doesn't support FE_SET_PROPERTY. Checking the device
151         // support FE_GET_PROPERTY or not to determine the DVB API version is greater than 5 or not.
152         if (ioctl(mFeFd, FE_GET_PROPERTY, &feProp) == -1) {
153             ALOGD("FE_GET_PROPERTY failed, %s", strerror(errno));
154             mDvbApiVersion = DVB_API_VERSION3;
155         } else {
156             mDvbApiVersion = DVB_API_VERSION5;
157         }
158     }
159 
160     if (mDvbApiVersion == DVB_API_VERSION5) {
161         struct dtv_property deliverySystemProperty = {
162             .cmd = DTV_DELIVERY_SYSTEM
163         };
164         switch (deliverySystemType) {
165             case DELIVERY_SYSTEM_DVBT:
166                 deliverySystemProperty.u.data = SYS_DVBT;
167                 break;
168             case DELIVERY_SYSTEM_DVBT2:
169                 deliverySystemProperty.u.data = SYS_DVBT2;
170                 break;
171             case DELIVERY_SYSTEM_DVBS:
172                 deliverySystemProperty.u.data = SYS_DVBS;
173                 break;
174             case DELIVERY_SYSTEM_DVBS2:
175                 deliverySystemProperty.u.data = SYS_DVBS2;
176                 break;
177             case DELIVERY_SYSTEM_DVBC:
178                 deliverySystemProperty.u.data = SYS_DVBC_ANNEX_A;
179                 break;
180             case DELIVERY_SYSTEM_ATSC:
181             case DELIVERY_SYSTEM_UNDEFINED:
182                 deliverySystemProperty.u.data = SYS_ATSC;
183                 break;
184             default:
185                 ALOGE("Unrecognized delivery system type");
186                 return -1;
187         }
188         struct dtv_property frequencyProperty = {
189             .cmd = DTV_FREQUENCY
190         };
191         struct dtv_property bandwidthProperty = {
192              .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000
193         };
194         frequencyProperty.u.data = static_cast<__u32>(frequency);
195         struct dtv_property modulationProperty = { .cmd = DTV_MODULATION };
196         if (strncmp(modulationStr, "QAM", 3) == 0) {
197             modulationProperty.u.data = QAM_AUTO;
198         } else if (strcmp(modulationStr, "8VSB") == 0) {
199             modulationProperty.u.data = VSB_8;
200         } else {
201             ALOGE("Unrecognized modulation mode : %s", modulationStr);
202             return -1;
203         }
204         struct dtv_property tuneProperty = { .cmd = DTV_TUNE };
205 
206         struct dtv_property props[] = {
207                 deliverySystemProperty, frequencyProperty, modulationProperty,
208                 bandwidthProperty, tuneProperty
209         };
210         struct dtv_properties dtvProperty = {
211             .num = sizeof(props)/sizeof(dtv_property), .props = props
212         };
213 
214         if (mHasPendingTune) {
215             return -1;
216         }
217         if (ioctl(mFeFd, FE_SET_PROPERTY, &dtvProperty) != 0) {
218             ALOGD("Can't set Frontend : %s", strerror(errno));
219             return -1;
220         }
221     } else {
222         struct dvb_frontend_parameters feParams;
223         memset(&feParams, 0, sizeof(struct dvb_frontend_parameters));
224         feParams.frequency = frequency;
225         feParams.inversion = INVERSION_AUTO;
226         /* Check frontend capability */
227         struct dvb_frontend_info feInfo;
228         if (ioctl(mFeFd, FE_GET_INFO, &feInfo) != -1) {
229             if (!(feInfo.caps & FE_CAN_INVERSION_AUTO)) {
230                 // FE can't do INVERSION_AUTO, trying INVERSION_OFF instead
231                 feParams.inversion = INVERSION_OFF;
232             }
233         }
234         switch (feInfo.type) {
235             case FE_ATSC:
236                 if (strcmp(modulationStr, "8VSB") == 0) {
237                     feParams.u.vsb.modulation = VSB_8;
238                 } else if (strncmp(modulationStr, "QAM", 3) == 0) {
239                     feParams.u.vsb.modulation = QAM_AUTO;
240                 } else {
241                     ALOGE("Unrecognized modulation mode : %s", modulationStr);
242                     return -1;
243                 }
244                 break;
245             case FE_OFDM:
246                 if (strcmp(modulationStr, "8VSB") == 0) {
247                     feParams.u.ofdm.constellation = VSB_8;
248                 } else if (strcmp(modulationStr, "QAM16") == 0) {
249                     feParams.u.ofdm.constellation = QAM_16;
250                 } else if (strcmp(modulationStr, "QAM64") == 0) {
251                     feParams.u.ofdm.constellation = QAM_64;
252                 } else if (strcmp(modulationStr, "QAM256") == 0) {
253                     feParams.u.ofdm.constellation = QAM_256;
254                 } else if (strcmp(modulationStr, "QPSK") == 0) {
255                     feParams.u.ofdm.constellation = QPSK;
256                 } else {
257                     ALOGE("Unrecognized modulation mode : %s", modulationStr);
258                     return -1;
259                 }
260                 feParams.u.ofdm.code_rate_HP = FEC_AUTO;
261                 feParams.u.ofdm.code_rate_LP = FEC_AUTO;
262                 feParams.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
263                 break;
264             default:
265                 ALOGE("Unsupported delivery system.");
266                 return -1;
267         }
268 
269         if (mHasPendingTune) {
270             return -1;
271         }
272 
273         if (ioctl(mFeFd, FE_SET_FRONTEND, &feParams) != 0) {
274             ALOGD("Can't set Frontend : %s", strerror(errno));
275             return -1;
276         }
277     }
278 
279     int lockSuccessCount = 0;
280     double tuneClock = currentTimeMillis();
281     while (currentTimeMillis() - tuneClock < timeout_ms) {
282         if (mHasPendingTune) {
283             // Return 0 here since we already call FE_SET_FRONTEND, and return due to having pending
284             // tune request. And the frontend setting could be successful.
285             mFeHasLock = true;
286             return 0;
287         }
288         bool lockStatus = isFeLocked();
289         if (lockStatus) {
290             lockSuccessCount++;
291         } else {
292             lockSuccessCount = 0;
293         }
294         ALOGI("Lock status : %s", lockStatus ? "true" : "false");
295         if (lockSuccessCount >= FE_CONSECUTIVE_LOCK_SUCCESS_COUNT) {
296             mFeHasLock = true;
297             openDvbDvr(env, thiz);
298             return 0;
299         }
300     }
301 
302     return -1;
303 }
304 
stopTune()305 int DvbManager::stopTune() {
306     reset();
307     usleep(DVB_TUNE_STOP_DELAY_MS);
308     return 0;
309 }
310 
openDvbFeFromSystemApi(JNIEnv * env,jobject thiz)311 int DvbManager::openDvbFeFromSystemApi(JNIEnv *env, jobject thiz) {
312     int fd = (int) env->CallIntMethod(thiz, mOpenDvbFrontEndMethodID);
313     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
314     return fd;
315 }
316 
openDvbDemuxFromSystemApi(JNIEnv * env,jobject thiz)317 int DvbManager::openDvbDemuxFromSystemApi(JNIEnv *env, jobject thiz) {
318     int fd = (int) env->CallIntMethod(thiz, mOpenDvbDemuxMethodID);
319     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
320     return fd;
321 }
322 
openDvbDvrFromSystemApi(JNIEnv * env,jobject thiz)323 int DvbManager::openDvbDvrFromSystemApi(JNIEnv *env, jobject thiz) {
324     int fd = (int) env->CallIntMethod(thiz, mOpenDvbDvrMethodID);
325     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
326     return fd;
327 }
328 
openDvbFe(JNIEnv * env,jobject thiz)329 int DvbManager::openDvbFe(JNIEnv *env, jobject thiz) {
330     if (mFeFd == -1) {
331         if ((mFeFd = openDvbFeFromSystemApi(env, thiz)) < 0) {
332             ALOGD("Can't open FE file : %s", strerror(errno));
333             return -1;
334         }
335     }
336 
337     struct dvb_frontend_info info;
338     if (ioctl(mFeFd, FE_GET_INFO, &info) == 0) {
339         const char *types;
340         switch (info.type) {
341             case FE_QPSK:
342                 types = "DVB-S";
343                 break;
344             case FE_QAM:
345                 types = "DVB-C";
346                 break;
347             case FE_OFDM:
348                 types = "DVB-T";
349                 break;
350             case FE_ATSC:
351                 types = "ATSC";
352                 break;
353             default:
354                 types = "Unknown";
355         }
356         ALOGI("Using frontend \"%s\", type %s", info.name, types);
357     }
358     return 0;
359 }
360 
startTsPidFilter(JNIEnv * env,jobject thiz,int pid,int filterType)361 int DvbManager::startTsPidFilter(JNIEnv *env, jobject thiz, int pid, int filterType) {
362     Mutex::Autolock autoLock(mFilterLock);
363 
364     if (mPidFilters.find(pid) != mPidFilters.end() || (mPatFilterFd != -1 && pid == PAT_PID)) {
365         return 0;
366     }
367 
368     if (mHasPendingTune) {
369         return -1;
370     }
371 
372     int demuxFd;
373     if ((demuxFd = openDvbDemuxFromSystemApi(env, thiz)) < 0) {
374         ALOGD("Can't open DEMUX file : %s", strerror(errno));
375         return -1;
376     }
377 
378     struct dmx_pes_filter_params filter;
379     memset(&filter, 0, sizeof(filter));
380     filter.pid = pid;
381     filter.input = DMX_IN_FRONTEND;
382     switch (filterType) {
383         case FILTER_TYPE_AUDIO:
384             filter.pes_type = DMX_PES_AUDIO;
385             break;
386         case FILTER_TYPE_VIDEO:
387             filter.pes_type = DMX_PES_VIDEO;
388             break;
389         case FILTER_TYPE_PCR:
390             filter.pes_type = DMX_PES_PCR;
391             break;
392         default:
393             filter.pes_type = DMX_PES_OTHER;
394             break;
395     }
396     filter.output = DMX_OUT_TS_TAP;
397     filter.flags |= (DMX_CHECK_CRC | DMX_IMMEDIATE_START);
398 
399     // create a pes filter
400     if (ioctl(demuxFd, DMX_SET_PES_FILTER, &filter)) {
401         close(demuxFd);
402         return -1;
403     }
404 
405     if (mDvbApiVersion == DVB_API_VERSION5) {
406         ioctl(demuxFd, DMX_START, 0);
407     }
408 
409     if (pid != PAT_PID) {
410         mPidFilters.insert(std::pair<int, int>(pid, demuxFd));
411     } else {
412         mPatFilterFd = demuxFd;
413     }
414 
415     return 0;
416 }
417 
closeAllDvbPidFilter()418 void DvbManager::closeAllDvbPidFilter() {
419     // Close all dvb pid filters except PAT filter to maintain the opening status of the device.
420     Mutex::Autolock autoLock(mFilterLock);
421 
422     for (std::map<int, int>::iterator it(mPidFilters.begin());
423                 it != mPidFilters.end(); it++) {
424         close(it->second);
425     }
426     mPidFilters.clear();
427     // Close mDvrFd to make sure there is not buffer from previous channel left.
428     closeDvbDvr();
429 }
430 
closePatFilter()431 void DvbManager::closePatFilter() {
432     Mutex::Autolock autoLock(mFilterLock);
433 
434     if (mPatFilterFd != -1) {
435         close(mPatFilterFd);
436         mPatFilterFd = -1;
437     }
438 }
439 
openDvbDvr(JNIEnv * env,jobject thiz)440 int DvbManager::openDvbDvr(JNIEnv *env, jobject thiz) {
441     if ((mDvrFd = openDvbDvrFromSystemApi(env, thiz)) < 0) {
442         ALOGD("Can't open DVR file : %s", strerror(errno));
443         return -1;
444     }
445     return 0;
446 }
447 
closeDvbFe()448 void DvbManager::closeDvbFe() {
449     if (mFeFd != -1) {
450         close(mFeFd);
451         mFeFd = -1;
452     }
453 }
454 
closeDvbDvr()455 void DvbManager::closeDvbDvr() {
456     if (mDvrFd != -1) {
457         close(mDvrFd);
458         mDvrFd = -1;
459     }
460 }
461 
reset()462 void DvbManager::reset() {
463     mFeHasLock = false;
464     closeDvbDvr();
465     closeAllDvbPidFilter();
466     closePatFilter();
467     closeDvbFe();
468 }
469 
resetExceptFe()470 void DvbManager::resetExceptFe() {
471     mFeHasLock = false;
472     closeDvbDvr();
473     closeAllDvbPidFilter();
474     closePatFilter();
475 }
476 
readTsStream(JNIEnv * env,jobject thiz,uint8_t * tsBuffer,int tsBufferSize,int timeout_ms)477 int DvbManager::readTsStream(JNIEnv *env, jobject thiz,
478         uint8_t *tsBuffer, int tsBufferSize, int timeout_ms) {
479     if (!mFeHasLock) {
480         usleep(DVB_ERROR_RETRY_INTERVAL_MS);
481         return -1;
482     }
483 
484     if (mDvrFd == -1) {
485         openDvbDvr(env, thiz);
486     }
487 
488     struct pollfd pollFd;
489     pollFd.fd = mDvrFd;
490     pollFd.events = POLLIN|POLLPRI|POLLERR;
491     pollFd.revents = 0;
492     int poll_result = poll(&pollFd, NUM_POLLFDS, timeout_ms);
493     if (poll_result == 0) {
494         return 0;
495     } else if (poll_result == -1 || pollFd.revents & POLLERR) {
496         ALOGD("Can't read DVR : %s", strerror(errno));
497         // TODO: Find how to recover this situation correctly.
498         closeDvbDvr();
499         usleep(DVB_ERROR_RETRY_INTERVAL_MS);
500         return -1;
501     }
502     return read(mDvrFd, tsBuffer, tsBufferSize);
503 }
504 
setHasPendingTune(bool hasPendingTune)505 void DvbManager::setHasPendingTune(bool hasPendingTune) {
506     mHasPendingTune = hasPendingTune;
507 }
508 
getDeliverySystemType(JNIEnv * env,jobject thiz)509 int DvbManager::getDeliverySystemType(JNIEnv *env, jobject thiz) {
510     getDeliverySystemTypes(env, thiz);
511     return mDeliverySystemTypes[0];
512 }
513 
getDeliverySystemTypes(JNIEnv * env,jobject thiz)514 int* DvbManager::getDeliverySystemTypes(JNIEnv *env, jobject thiz) {
515     ALOGE("getDeliverySystemTypes");
516     if (mDeliverySystemTypes[0] != DELIVERY_SYSTEM_UNDEFINED) {
517         return mDeliverySystemTypes;
518     }
519     if (mFeFd == -1) {
520         if ((mFeFd = openDvbFeFromSystemApi(env, thiz)) < 0) {
521             ALOGD("Can't open FE file : %s", strerror(errno));
522             return mDeliverySystemTypes;
523         }
524     }
525     struct dtv_property testProps[1] = {
526         { .cmd = DTV_ENUM_DELSYS }
527     };
528     struct dtv_properties feProp = {
529         .num = 1, .props = testProps
530     };
531     if (ioctl(mFeFd, FE_GET_PROPERTY, &feProp) == -1) {
532         mDvbApiVersion = DVB_API_VERSION3;
533         if (openDvbFe(env, thiz) == 0) {
534             struct dvb_frontend_info info;
535             if (ioctl(mFeFd, FE_GET_INFO, &info) == 0) {
536                 switch (info.type) {
537                     case FE_QPSK:
538                         mDeliverySystemTypes[0] = DELIVERY_SYSTEM_DVBS;
539                         break;
540                     case FE_QAM:
541                         mDeliverySystemTypes[0] = DELIVERY_SYSTEM_DVBC;
542                         break;
543                     case FE_OFDM:
544                         mDeliverySystemTypes[0] = DELIVERY_SYSTEM_DVBT;
545                         break;
546                     case FE_ATSC:
547                         mDeliverySystemTypes[0] = DELIVERY_SYSTEM_ATSC;
548                         break;
549                     default:
550                         mDeliverySystemTypes[0] = DELIVERY_SYSTEM_UNDEFINED;
551                         break;
552                 }
553             }
554         }
555     } else {
556         mDvbApiVersion = DVB_API_VERSION5;
557         for (unsigned int i = 0; i < feProp.props[0].u.buffer.len; i++) {
558             switch (feProp.props[0].u.buffer.data[i]) {
559                 case SYS_DVBT:
560                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBT;
561                     break;
562                 case SYS_DVBT2:
563                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBT2;
564                     break;
565                 case SYS_DVBS:
566                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBS;
567                     break;
568                 case SYS_DVBS2:
569                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBS2;
570                     break;
571                 case SYS_DVBC_ANNEX_A:
572                 case SYS_DVBC_ANNEX_B:
573                 case SYS_DVBC_ANNEX_C:
574                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_DVBC;
575                     break;
576                 case SYS_ATSC:
577                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_ATSC;
578                     break;
579                 default:
580                     mDeliverySystemTypes[i] = DELIVERY_SYSTEM_UNDEFINED;
581                     break;
582             }
583         }
584     }
585     return mDeliverySystemTypes;
586 }
587