aboutsummaryrefslogtreecommitdiff
path: root/jni
diff options
context:
space:
mode:
Diffstat (limited to 'jni')
-rw-r--r--jni/Android.mk12
-rw-r--r--jni/DvbManager.cpp339
-rw-r--r--jni/DvbManager.h84
-rwxr-xr-xjni/gen_jni.sh3
-rw-r--r--jni/logging.h32
-rw-r--r--jni/mutex.h61
-rw-r--r--jni/tunertvinput_jni.cpp157
-rw-r--r--jni/tunertvinput_jni.h98
8 files changed, 786 insertions, 0 deletions
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100644
index 00000000..684830c9
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+# --------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libtunertvinput_jni
+LOCAL_SRC_FILES += tunertvinput_jni.cpp DvbManager.cpp
+LOCAL_SDK_VERSION := 21
+LOCAL_NDK_STL_VARIANT := stlport_static
+LOCAL_LDLIBS := -llog
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/jni/DvbManager.cpp b/jni/DvbManager.cpp
new file mode 100644
index 00000000..aa4ed530
--- /dev/null
+++ b/jni/DvbManager.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend.h>
+
+#define LOG_TAG "DvbManager"
+#include "logging.h"
+
+#include "DvbManager.h"
+
+static double currentTimeMillis() {
+ struct timeval tv;
+ gettimeofday(&tv, (struct timezone *) NULL);
+ return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
+}
+
+DvbManager::DvbManager(JNIEnv *env, jobject)
+ : mFeFd(-1),
+ mDemuxFd(-1),
+ mDvrFd(-1),
+ mPatFilterFd(-1),
+ mFeHasLock(false),
+ mHasPendingTune(false) {
+ jclass clazz = env->FindClass(
+ "com/android/tv/tuner/TunerHal");
+ mOpenDvbFrontEndMethodID = env->GetMethodID(
+ clazz, "openDvbFrontEndFd", "()I");
+ mOpenDvbDemuxMethodID = env->GetMethodID(
+ clazz, "openDvbDemuxFd", "()I");
+ mOpenDvbDvrMethodID = env->GetMethodID(
+ clazz, "openDvbDvrFd", "()I");
+}
+
+DvbManager::~DvbManager() {
+ reset();
+}
+
+bool DvbManager::isFeLocked() {
+ struct pollfd pollFd;
+ pollFd.fd = mFeFd;
+ pollFd.events = POLLIN;
+ pollFd.revents = 0;
+ int poll_result = poll(&pollFd, NUM_POLLFDS, FE_POLL_TIMEOUT_MS);
+ if (poll_result > 0 && (pollFd.revents & POLLIN)) {
+ struct dvb_frontend_event kevent;
+ memset(&kevent, 0, sizeof(kevent));
+ if (ioctl(mFeFd, FE_GET_EVENT, &kevent) == 0) {
+ return (kevent.status & FE_HAS_LOCK);
+ }
+ }
+ return false;
+}
+
+int DvbManager::tune(JNIEnv *env, jobject thiz,
+ const int frequency, const char *modulationStr, int timeout_ms) {
+ resetExceptFe();
+
+ struct dvb_frontend_parameters feParams;
+ memset(&feParams, 0, sizeof(struct dvb_frontend_parameters));
+ feParams.frequency = frequency;
+ if (strcmp(modulationStr, "8VSB") == 0) {
+ feParams.u.vsb.modulation = VSB_8;
+ } else if (strcmp(modulationStr, "QAM256") == 0) {
+ feParams.u.vsb.modulation = QAM_256;
+ } else {
+ ALOGE("Unrecognized modulation mode : %s", modulationStr);
+ return -1;
+ }
+
+ if (mHasPendingTune) {
+ return -1;
+ }
+ if (openDvbFe(env, thiz) != 0) {
+ return -1;
+ }
+
+ feParams.inversion = INVERSION_AUTO;
+ /* Check frontend capability */
+ struct dvb_frontend_info feInfo;
+ if (ioctl(mFeFd, FE_GET_INFO, &feInfo) != -1) {
+ if (!(feInfo.caps & FE_CAN_INVERSION_AUTO)) {
+ // FE can't do INVERSION_AUTO, trying INVERSION_OFF instead
+ feParams.inversion = INVERSION_OFF;
+ }
+ }
+
+ if (ioctl(mFeFd, FE_SET_FRONTEND, &feParams) != 0) {
+ ALOGD("Can't set Frontend : %s", strerror(errno));
+ return -1;
+ }
+
+ int lockSuccessCount = 0;
+ double tuneClock = currentTimeMillis();
+ while (currentTimeMillis() - tuneClock < timeout_ms) {
+ if (mHasPendingTune) {
+ // Return 0 here since we already call FE_SET_FRONTEND, and return due to having pending
+ // tune request. And the frontend setting could be successful.
+ mFeHasLock = true;
+ return 0;
+ }
+ bool lockStatus = isFeLocked();
+ if (lockStatus) {
+ lockSuccessCount++;
+ } else {
+ lockSuccessCount = 0;
+ }
+ ALOGI("Lock status : %s", lockStatus ? "true" : "false");
+ if (lockSuccessCount >= FE_CONSECUTIVE_LOCK_SUCCESS_COUNT) {
+ mFeHasLock = true;
+ openDvbDvr(env, thiz);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int DvbManager::stopTune() {
+ reset();
+ usleep(DVB_TUNE_STOP_DELAY_MS);
+ return 0;
+}
+
+int DvbManager::openDvbFeFromSystemApi(JNIEnv *env, jobject thiz) {
+ int fd = (int) env->CallIntMethod(thiz, mOpenDvbFrontEndMethodID);
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+ return fd;
+}
+
+int DvbManager::openDvbDemuxFromSystemApi(JNIEnv *env, jobject thiz) {
+ int fd = (int) env->CallIntMethod(thiz, mOpenDvbDemuxMethodID);
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+ return fd;
+}
+
+int DvbManager::openDvbDvrFromSystemApi(JNIEnv *env, jobject thiz) {
+ int fd = (int) env->CallIntMethod(thiz, mOpenDvbDvrMethodID);
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+ return fd;
+}
+
+int DvbManager::openDvbFe(JNIEnv *env, jobject thiz) {
+ if (mFeFd == -1) {
+ if ((mFeFd = openDvbFeFromSystemApi(env, thiz)) < 0) {
+ ALOGD("Can't open FE file : %s", strerror(errno));
+ return -1;
+ }
+ }
+
+ struct dvb_frontend_info info;
+ if (ioctl(mFeFd, FE_GET_INFO, &info) == 0) {
+ const char *types;
+ switch (info.type) {
+ case FE_QPSK:
+ types = "DVB-S";
+ break;
+ case FE_QAM:
+ types = "DVB-C";
+ break;
+ case FE_OFDM:
+ types = "DVB-T";
+ break;
+ case FE_ATSC:
+ types = "ATSC";
+ break;
+ default:
+ types = "Unknown";
+ }
+ ALOGI("Using frontend \"%s\", type %s", info.name, types);
+ }
+ return 0;
+}
+
+int DvbManager::startTsPidFilter(JNIEnv *env, jobject thiz, int pid, int filterType) {
+ Mutex::Autolock autoLock(mFilterLock);
+
+ if (mPidFilters.find(pid) != mPidFilters.end() || (mPatFilterFd != -1 && pid == PAT_PID)) {
+ return 0;
+ }
+
+ if (mHasPendingTune) {
+ return -1;
+ }
+
+ int demuxFd;
+ if ((demuxFd = openDvbDemuxFromSystemApi(env, thiz)) < 0) {
+ ALOGD("Can't open DEMUX file : %s", strerror(errno));
+ return -1;
+ }
+
+ struct dmx_pes_filter_params filter;
+ memset(&filter, 0, sizeof(filter));
+ filter.pid = pid;
+ filter.input = DMX_IN_FRONTEND;
+ switch (filterType) {
+ case FILTER_TYPE_AUDIO:
+ filter.pes_type = DMX_PES_AUDIO;
+ break;
+ case FILTER_TYPE_VIDEO:
+ filter.pes_type = DMX_PES_VIDEO;
+ break;
+ case FILTER_TYPE_PCR:
+ filter.pes_type = DMX_PES_PCR;
+ break;
+ default:
+ filter.pes_type = DMX_PES_OTHER;
+ break;
+ }
+ filter.output = DMX_OUT_TS_TAP;
+ filter.flags |= (DMX_CHECK_CRC | DMX_IMMEDIATE_START);
+
+ // create a pes filter
+ if (ioctl(demuxFd, DMX_SET_PES_FILTER, &filter)) {
+ close(demuxFd);
+ return -1;
+ }
+
+ if (pid != PAT_PID) {
+ mPidFilters.insert(std::pair<int, int>(pid, demuxFd));
+ } else {
+ mPatFilterFd = demuxFd;
+ }
+
+ return 0;
+}
+
+void DvbManager::closeAllDvbPidFilter() {
+ // Close all dvb pid filters except PAT filter to maintain the opening status of the device.
+ Mutex::Autolock autoLock(mFilterLock);
+
+ for (std::map<int, int>::iterator it(mPidFilters.begin());
+ it != mPidFilters.end(); it++) {
+ close(it->second);
+ }
+ mPidFilters.clear();
+ // Close mDvrFd to make sure there is not buffer from previous channel left.
+ closeDvbDvr();
+}
+
+void DvbManager::closePatFilter() {
+ Mutex::Autolock autoLock(mFilterLock);
+
+ if (mPatFilterFd != -1) {
+ close(mPatFilterFd);
+ mPatFilterFd = -1;
+ }
+}
+
+int DvbManager::openDvbDvr(JNIEnv *env, jobject thiz) {
+ if ((mDvrFd = openDvbDvrFromSystemApi(env, thiz)) < 0) {
+ ALOGD("Can't open DVR file : %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+void DvbManager::closeDvbFe() {
+ if (mFeFd != -1) {
+ close(mFeFd);
+ mFeFd = -1;
+ }
+}
+
+void DvbManager::closeDvbDvr() {
+ if (mDvrFd != -1) {
+ close(mDvrFd);
+ mDvrFd = -1;
+ }
+}
+
+void DvbManager::reset() {
+ mFeHasLock = false;
+ closeDvbDvr();
+ closeAllDvbPidFilter();
+ closePatFilter();
+ closeDvbFe();
+}
+
+void DvbManager::resetExceptFe() {
+ mFeHasLock = false;
+ closeDvbDvr();
+ closeAllDvbPidFilter();
+ closePatFilter();
+}
+
+int DvbManager::readTsStream(JNIEnv *env, jobject thiz,
+ uint8_t *tsBuffer, int tsBufferSize, int timeout_ms) {
+ if (!mFeHasLock) {
+ usleep(DVB_ERROR_RETRY_INTERVAL_MS);
+ return -1;
+ }
+
+ if (mDvrFd == -1) {
+ openDvbDvr(env, thiz);
+ }
+
+ struct pollfd pollFd;
+ pollFd.fd = mDvrFd;
+ pollFd.events = POLLIN|POLLPRI|POLLERR;
+ pollFd.revents = 0;
+ int poll_result = poll(&pollFd, NUM_POLLFDS, timeout_ms);
+ if (poll_result == 0) {
+ return 0;
+ } else if (poll_result == -1 || pollFd.revents & POLLERR) {
+ ALOGD("Can't read DVR : %s", strerror(errno));
+ // TODO: Find how to recover this situation correctly.
+ closeDvbDvr();
+ usleep(DVB_ERROR_RETRY_INTERVAL_MS);
+ return -1;
+ }
+ return read(mDvrFd, tsBuffer, tsBufferSize);
+}
+
+void DvbManager::setHasPendingTune(bool hasPendingTune) {
+ mHasPendingTune = hasPendingTune;
+}
diff --git a/jni/DvbManager.h b/jni/DvbManager.h
new file mode 100644
index 00000000..7475bd41
--- /dev/null
+++ b/jni/DvbManager.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DVB_MANAGER_H_
+#define DVB_MANAGER_H_
+
+#include <jni.h>
+#include <map>
+
+#include "mutex.h"
+#include "tunertvinput_jni.h"
+
+class DvbManager {
+ static const int NUM_POLLFDS = 1;
+ static const int FE_LOCK_CHECK_INTERNAL_US = 100 * 1000;
+ static const int FE_CONSECUTIVE_LOCK_SUCCESS_COUNT = 1;
+ static const int DVB_ERROR_RETRY_INTERVAL_MS = 100 * 1000;
+ static const int DVB_TUNE_STOP_DELAY_MS = 100 * 1000;
+ static const int FE_POLL_TIMEOUT_MS = 100;
+ static const int PAT_PID = 0;
+
+ static const int FILTER_TYPE_OTHER =
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_OTHER;
+ static const int FILTER_TYPE_AUDIO =
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_AUDIO;
+ static const int FILTER_TYPE_VIDEO =
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_VIDEO;
+ static const int FILTER_TYPE_PCR =
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_PCR;
+
+ int mFeFd;
+ int mDemuxFd;
+ int mDvrFd;
+ int mPatFilterFd;
+ bool mFeHasLock;
+ // Flag for pending tune request. Used for canceling the current tune operation.
+ bool volatile mHasPendingTune;
+ std::map<int, int> mPidFilters;
+ Mutex mFilterLock;
+ jmethodID mOpenDvbFrontEndMethodID;
+ jmethodID mOpenDvbDemuxMethodID;
+ jmethodID mOpenDvbDvrMethodID;
+
+public:
+ DvbManager(JNIEnv *env, jobject thiz);
+ ~DvbManager();
+ int tune(JNIEnv *env, jobject thiz,
+ const int frequency, const char *modulationStr, int timeout_ms);
+ int stopTune();
+ int readTsStream(JNIEnv *env, jobject thiz,
+ uint8_t *tsBuffer, int tsBufferSize, int timeout_ms);
+ int startTsPidFilter(JNIEnv *env, jobject thiz, int pid, int filterType);
+ void closeAllDvbPidFilter();
+ void setHasPendingTune(bool hasPendingTune);
+
+private:
+ int openDvbFe(JNIEnv *env, jobject thiz);
+ int openDvbDvr(JNIEnv *env, jobject thiz);
+ void closePatFilter();
+ void closeDvbFe();
+ void closeDvbDvr();
+ void reset();
+ void resetExceptFe();
+ bool isFeLocked();
+ // Call to java method
+ int openDvbFeFromSystemApi(JNIEnv *env, jobject thiz);
+ int openDvbDemuxFromSystemApi(JNIEnv *env, jobject thiz);
+ int openDvbDvrFromSystemApi(JNIEnv *env, jobject thiz);
+};
+
+#endif // DVB_MANAGER_H_
diff --git a/jni/gen_jni.sh b/jni/gen_jni.sh
new file mode 100755
index 00000000..aa52b248
--- /dev/null
+++ b/jni/gen_jni.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+javah -jni -classpath ../../bin/classes:../../../../../../prebuilts/sdk/current/android.jar -o tunertvinput_jni.h com.android.tv.tuner.TunerHal
diff --git a/jni/logging.h b/jni/logging.h
new file mode 100644
index 00000000..af90961c
--- /dev/null
+++ b/jni/logging.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGGING_H_
+#define LOGGING_H_
+
+#include <android/log.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "usbtuner"
+#endif
+
+#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__)
+#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__)
+
+#endif // LOGGING_H_
diff --git a/jni/mutex.h b/jni/mutex.h
new file mode 100644
index 00000000..90527ae4
--- /dev/null
+++ b/jni/mutex.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MUTEX_H_
+#define MUTEX_H_
+
+#include "pthread.h"
+
+// Based on utils/threads.h, but tailored to build with the NDK and used unbundled.
+// This is a simple wrapper over the pthread_mutex_t type.
+class Mutex {
+public:
+ Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+ int lock() {
+ return -pthread_mutex_lock(&mMutex);
+ }
+ void unlock() {
+ pthread_mutex_unlock(&mMutex);
+ }
+ ~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+ }
+
+ // A simple class that locks a given mutex on construction
+ // and unlocks it when it goes out of scope.
+ class Autolock {
+ public:
+ Autolock(Mutex &mutex) : lock(&mutex) {
+ lock->lock();
+ }
+ ~Autolock() {
+ lock->unlock();
+ }
+ private:
+ Mutex *lock;
+ };
+
+private:
+ pthread_mutex_t mMutex;
+
+ // Disallow copy and assign.
+ Mutex(const Mutex&);
+ Mutex& operator=(const Mutex&);
+};
+
+#endif // MUTEX_H_
diff --git a/jni/tunertvinput_jni.cpp b/jni/tunertvinput_jni.cpp
new file mode 100644
index 00000000..bcbc4c29
--- /dev/null
+++ b/jni/tunertvinput_jni.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tunertvinput_jni.h"
+#include <map>
+
+#include "DvbManager.h"
+#define LOG_TAG "tunertvinput_jni"
+#include "logging.h"
+
+//-------------------------------------------------------------------------------
+// JNI native method implementation
+//-------------------------------------------------------------------------------
+
+#define TS_PACKET_SIZE 188
+#define TS_PAYLOAD_SIZE (TS_PACKET_SIZE * 7) // Fit Ethernet MTU (1500)
+#define READ_TIMEOUT_MS 100
+
+static int sTotalBytesFetched = 0;
+static std::map<jlong, DvbManager *> sDvbManagers;
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeFinalize
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeFinalize
+(JNIEnv *, jobject, jlong deviceId) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it != sDvbManagers.end()) {
+ delete it->second;
+ sDvbManagers.erase(it);
+ }
+}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeTune
+ * Signature: (JILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeTune
+(JNIEnv *env, jobject thiz, jlong deviceId, jint frequency, jstring modulation, jint timeout_ms) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ DvbManager *dvbManager;
+ if (it == sDvbManagers.end()) {
+ dvbManager = new DvbManager(env, thiz);
+ sDvbManagers.insert(std::pair<jlong, DvbManager *>(deviceId, dvbManager));
+ } else {
+ dvbManager = it->second;
+ }
+ int res = dvbManager->tune(env, thiz,
+ frequency, env->GetStringUTFChars(modulation, 0), timeout_ms);
+ return (res == 0);
+}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeCloseAllPidFilters
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeCloseAllPidFilters
+ (JNIEnv *, jobject, jlong deviceId) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it != sDvbManagers.end()) {
+ it->second->closeAllDvbPidFilter();
+ }
+}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeStopTune
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeStopTune
+(JNIEnv *, jobject, jlong deviceId) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it != sDvbManagers.end()) {
+ it->second->stopTune();
+ }
+}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeAddPidFilter
+ * Signature: (JII)V
+ */
+JNIEXPORT void JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeAddPidFilter
+(JNIEnv *env, jobject thiz, jlong deviceId, jint pid, jint filterType) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it != sDvbManagers.end()) {
+ it->second->startTsPidFilter(env, thiz, pid, filterType);
+ }
+}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeWriteInBuffer
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeWriteInBuffer
+(JNIEnv *env, jobject thiz, jlong deviceId, jbyteArray javaBuffer, jint javaBufferSize) {
+ uint8_t tsBuffer[TS_PAYLOAD_SIZE];
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it == sDvbManagers.end()) {
+ return -1;
+ }
+ DvbManager *dvbManager = it->second;
+
+ // Always read multiple of TS_PACKET_SIZE
+ javaBufferSize = (javaBufferSize / TS_PACKET_SIZE) * TS_PACKET_SIZE;
+ int readBufferSize = (javaBufferSize < TS_PAYLOAD_SIZE) ? javaBufferSize : TS_PAYLOAD_SIZE;
+
+ int dataSize = dvbManager->readTsStream(env, thiz, tsBuffer, readBufferSize, READ_TIMEOUT_MS);
+ if (dataSize == 0) {
+ ALOGD("No data to read DVR");
+ return 0;
+ } else if (dataSize < 0) {
+ return -1;
+ }
+
+ sTotalBytesFetched += dataSize;
+
+ env->SetByteArrayRegion(javaBuffer, 0, dataSize, (jbyte *) tsBuffer);
+ return dataSize;
+}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeSetHasPendingTune
+ * Signature: (JZ)V
+ */
+JNIEXPORT void JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeSetHasPendingTune
+(JNIEnv *env, jobject thiz, jlong deviceId, jboolean hasPendingTune) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it != sDvbManagers.end()) {
+ it->second->setHasPendingTune(hasPendingTune);
+ }
+}
diff --git a/jni/tunertvinput_jni.h b/jni/tunertvinput_jni.h
new file mode 100644
index 00000000..4ade29e4
--- /dev/null
+++ b/jni/tunertvinput_jni.h
@@ -0,0 +1,98 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_tv_tuner_TunerHal */
+
+#ifndef _Included_com_android_tv_tuner_TunerHal
+#define _Included_com_android_tv_tuner_TunerHal
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_android_tv_tuner_TunerHal_DEBUG
+#define com_android_tv_tuner_TunerHal_DEBUG 0L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_OTHER
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_OTHER 0L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_AUDIO
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_AUDIO 1L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_VIDEO
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_VIDEO 2L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_PCR
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_PCR 3L
+#undef com_android_tv_tuner_TunerHal_PID_PAT
+#define com_android_tv_tuner_TunerHal_PID_PAT 0L
+#undef com_android_tv_tuner_TunerHal_PID_ATSC_SI_BASE
+#define com_android_tv_tuner_TunerHal_PID_ATSC_SI_BASE 8187L
+#undef com_android_tv_tuner_TunerHal_DEFAULT_VSB_TUNE_TIMEOUT_MS
+#define com_android_tv_tuner_TunerHal_DEFAULT_VSB_TUNE_TIMEOUT_MS 2000L
+#undef com_android_tv_tuner_TunerHal_DEFAULT_QAM_TUNE_TIMEOUT_MS
+#define com_android_tv_tuner_TunerHal_DEFAULT_QAM_TUNE_TIMEOUT_MS 4000L
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeFinalize
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeFinalize
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeTune
+ * Signature: (JILjava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_android_tv_tuner_TunerHal_nativeTune
+ (JNIEnv *, jobject, jlong, jint, jstring, jint);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeAddPidFilter
+ * Signature: (JII)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeAddPidFilter
+ (JNIEnv *, jobject, jlong, jint, jint);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeCloseAllPidFilters
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeCloseAllPidFilters
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeStopTune
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeStopTune
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeWriteInBuffer
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_android_tv_tuner_TunerHal_nativeWriteInBuffer
+ (JNIEnv *, jobject, jlong, jbyteArray, jint);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeSetHasPendingTune
+ * Signature: (JZ)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeSetHasPendingTune
+ (JNIEnv *, jobject, jlong, jboolean);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class com_android_tv_tuner_TunerHal_FilterType */
+
+#ifndef _Included_com_android_tv_tuner_TunerHal_FilterType
+#define _Included_com_android_tv_tuner_TunerHal_FilterType
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif