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 "tunertvinput_jni.h"
18#include <map>
19
20#include "DvbManager.h"
21#define LOG_TAG "tunertvinput_jni"
22#include "logging.h"
23
24//-------------------------------------------------------------------------------
25// JNI native method implementation
26//-------------------------------------------------------------------------------
27
28#define TS_PACKET_SIZE 188
29#define TS_PAYLOAD_SIZE (TS_PACKET_SIZE * 7) // Fit Ethernet MTU (1500)
30#define READ_TIMEOUT_MS 100
31
32static int sTotalBytesFetched = 0;
33static std::map<jlong, DvbManager *> sDvbManagers;
34
35/*
36 * Class:     com_android_usbtuner_TunerHal
37 * Method:    nativeFinalize
38 * Signature: (J)V
39 */
40JNIEXPORT void JNICALL
41Java_com_android_usbtuner_TunerHal_nativeFinalize
42(JNIEnv *, jobject, jlong deviceId) {
43    std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
44    if (it != sDvbManagers.end()) {
45        delete it->second;
46        sDvbManagers.erase(it);
47    }
48}
49
50/*
51 * Class:     com_android_usbtuner_TunerHal
52 * Method:    nativeTune
53 * Signature: (JILjava/lang/String;)Z
54 */
55JNIEXPORT jboolean JNICALL
56Java_com_android_usbtuner_TunerHal_nativeTune
57(JNIEnv *env, jobject thiz, jlong deviceId, jint frequency, jstring modulation, jint timeout_ms) {
58    std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
59    DvbManager *dvbManager;
60    if (it == sDvbManagers.end()) {
61        dvbManager = new DvbManager(env, thiz);
62        sDvbManagers.insert(std::pair<jlong, DvbManager *>(deviceId, dvbManager));
63    } else {
64        dvbManager = it->second;
65    }
66    int res = dvbManager->tune(env, thiz,
67            frequency, env->GetStringUTFChars(modulation, 0), timeout_ms);
68    return (res == 0);
69}
70
71/*
72 * Class:     com_android_usbtuner_TunerHal
73 * Method:    nativeCloseAllPidFilters
74 * Signature: (J)V
75 */
76JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeCloseAllPidFilters
77  (JNIEnv *, jobject, jlong deviceId) {
78    std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
79    if (it != sDvbManagers.end()) {
80        it->second->closeAllDvbPidFilter();
81    }
82}
83
84/*
85 * Class:     com_android_usbtuner_TunerHal
86 * Method:    nativeStopTune
87 * Signature: (J)V
88 */
89JNIEXPORT void JNICALL
90Java_com_android_usbtuner_TunerHal_nativeStopTune
91(JNIEnv *, jobject, jlong deviceId) {
92    std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
93    if (it != sDvbManagers.end()) {
94        it->second->stopTune();
95    }
96}
97
98/*
99 * Class:     com_android_usbtuner_TunerHal
100 * Method:    nativeAddPidFilter
101 * Signature: (JII)V
102 */
103JNIEXPORT void JNICALL
104Java_com_android_usbtuner_TunerHal_nativeAddPidFilter
105(JNIEnv *env, jobject thiz, jlong deviceId, jint pid, jint filterType) {
106    std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
107    if (it != sDvbManagers.end()) {
108        it->second->startTsPidFilter(env, thiz, pid, filterType);
109    }
110}
111
112/*
113 * Class:     com_android_usbtuner_TunerHal
114 * Method:    nativeWriteInBuffer
115 * Signature: (J[BI)I
116 */
117JNIEXPORT jint JNICALL
118Java_com_android_usbtuner_TunerHal_nativeWriteInBuffer
119(JNIEnv *env, jobject thiz, jlong deviceId, jbyteArray javaBuffer, jint javaBufferSize) {
120    uint8_t tsBuffer[TS_PAYLOAD_SIZE];
121    std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
122    if (it == sDvbManagers.end()) {
123        return -1;
124    }
125    DvbManager *dvbManager = it->second;
126
127    // Always read multiple of TS_PACKET_SIZE
128    javaBufferSize = (javaBufferSize / TS_PACKET_SIZE) * TS_PACKET_SIZE;
129    int readBufferSize = (javaBufferSize < TS_PAYLOAD_SIZE) ? javaBufferSize : TS_PAYLOAD_SIZE;
130
131    int dataSize = dvbManager->readTsStream(env, thiz, tsBuffer, readBufferSize, READ_TIMEOUT_MS);
132    if (dataSize == 0) {
133        ALOGD("No data to read DVR");
134        return 0;
135    } else if (dataSize < 0) {
136        return -1;
137    }
138
139    sTotalBytesFetched += dataSize;
140
141    env->SetByteArrayRegion(javaBuffer, 0, dataSize, (jbyte *) tsBuffer);
142    return dataSize;
143}
144