/*
* 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: nativeGetSignalStrength
* Signature: (J)V
*/
JNIEXPORT int JNICALL
Java_com_android_tv_tuner_TunerHal_nativeGetSignalStrength(
JNIEnv *, jobject, jlong deviceId) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
return it->second->getSignalStrength();
}
// If DvbManager can't be found,
// return -3 as signal strength not supported.
return -3;
}
/*
* 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 *, jobject, jlong deviceId, jboolean hasPendingTune) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
it->second->setHasPendingTune(hasPendingTune);
}
}
/*
* Class: com_android_tv_tuner_TunerHal
* Method: nativeGetDeliverySystemType
* Signature: (J)I
*/
JNIEXPORT int JNICALL
Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemType(JNIEnv *env,
jobject thiz,
jlong deviceId) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
return it->second->getDeliverySystemType(env, thiz);
} else {
DvbManager *dvbManager = new DvbManager(env, thiz);
sDvbManagers.insert(std::pair<jlong, DvbManager *>(deviceId, dvbManager));
return dvbManager->getDeliverySystemType(env, thiz);
}
}