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