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 
32 static int sTotalBytesFetched = 0;
33 static std::map<jlong, DvbManager *> sDvbManagers;
34 
35 /*
36  * Class:     com_android_tv_tuner_TunerHal
37  * Method:    nativeFinalize
38  * Signature: (J)V
39  */
Java_com_android_tv_tuner_TunerHal_nativeFinalize(JNIEnv *,jobject,jlong deviceId)40 JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeFinalize(
41     JNIEnv *, jobject, jlong deviceId) {
42   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
43   if (it != sDvbManagers.end()) {
44     delete it->second;
45     sDvbManagers.erase(it);
46   }
47 }
48 
49 /*
50  * Class:     com_android_tv_tuner_TunerHal
51  * Method:    nativeTune
52  * Signature: (JILjava/lang/String;I)Z
53  */
54 JNIEXPORT jboolean JNICALL
Java_com_android_tv_tuner_TunerHal_nativeTune__JILjava_lang_String_2I(JNIEnv * env,jobject thiz,jlong deviceId,jint frequency,jstring modulation,jint timeout_ms)55     Java_com_android_tv_tuner_TunerHal_nativeTune__JILjava_lang_String_2I(
56         JNIEnv *env, jobject thiz, jlong deviceId, jint frequency,
57         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, frequency,
67                              env->GetStringUTFChars(modulation, 0), timeout_ms);
68   return (res == 0);
69 }
70 
71 /*
72  * Class:     com_android_tv_tuner_TunerHal
73  * Method:    nativeTune
74  * Signature: (JIILjava/lang/String;I)Z
75  */
76 JNIEXPORT jboolean JNICALL
Java_com_android_tv_tuner_TunerHal_nativeTune__JIILjava_lang_String_2I(JNIEnv * env,jobject thiz,jlong deviceId,jint deliverySystemType,jint frequency,jstring modulation,jint timeout_ms)77     Java_com_android_tv_tuner_TunerHal_nativeTune__JIILjava_lang_String_2I(
78         JNIEnv *env, jobject thiz, jlong deviceId, jint deliverySystemType,
79         jint frequency, jstring modulation, jint timeout_ms) {
80     std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
81     DvbManager *dvbManager;
82     if (it == sDvbManagers.end()) {
83         dvbManager = new DvbManager(env, thiz);
84         sDvbManagers.insert(
85             std::pair<jlong, DvbManager *>(deviceId, dvbManager));
86     } else {
87         dvbManager = it->second;
88     }
89     int res = dvbManager->tune(env, thiz, deliverySystemType, frequency,
90                 env->GetStringUTFChars(modulation, 0), timeout_ms);
91     return (res == 0);
92 }
93 
94 /*
95  * Class:     com_android_tv_tuner_TunerHal
96  * Method:    nativeCloseAllPidFilters
97  * Signature: (J)V
98  */
99 JNIEXPORT void JNICALL
Java_com_android_tv_tuner_TunerHal_nativeCloseAllPidFilters(JNIEnv *,jobject,jlong deviceId)100 Java_com_android_tv_tuner_TunerHal_nativeCloseAllPidFilters(JNIEnv *, jobject,
101                                                             jlong deviceId) {
102   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
103   if (it != sDvbManagers.end()) {
104     it->second->closeAllDvbPidFilter();
105   }
106 }
107 
108 /*
109  * Class:     com_android_tv_tuner_TunerHal
110  * Method:    nativeStopTune
111  * Signature: (J)V
112  */
Java_com_android_tv_tuner_TunerHal_nativeStopTune(JNIEnv *,jobject,jlong deviceId)113 JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeStopTune(
114     JNIEnv *, jobject, jlong deviceId) {
115   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
116   if (it != sDvbManagers.end()) {
117     it->second->stopTune();
118   }
119 }
120 
121 /*
122  * Class:     com_android_tv_tuner_TunerHal
123  * Method:    nativeGetSignalStrength
124  * Signature: (J)V
125  */
126 JNIEXPORT int JNICALL
Java_com_android_tv_tuner_TunerHal_nativeGetSignalStrength(JNIEnv *,jobject,jlong deviceId)127 Java_com_android_tv_tuner_TunerHal_nativeGetSignalStrength(
128     JNIEnv *, jobject, jlong deviceId) {
129   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
130   if (it != sDvbManagers.end()) {
131     return it->second->getSignalStrength();
132   }
133   // If DvbManager can't be found,
134   // return -3 as signal strength not supported.
135   return -3;
136 }
137 
138 /*
139  * Class:     com_android_tv_tuner_TunerHal
140  * Method:    nativeAddPidFilter
141  * Signature: (JII)V
142  */
Java_com_android_tv_tuner_TunerHal_nativeAddPidFilter(JNIEnv * env,jobject thiz,jlong deviceId,jint pid,jint filterType)143 JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeAddPidFilter(
144     JNIEnv *env, jobject thiz, jlong deviceId, jint pid, jint filterType) {
145   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
146   if (it != sDvbManagers.end()) {
147     it->second->startTsPidFilter(env, thiz, pid, filterType);
148   }
149 }
150 
151 /*
152  * Class:     com_android_tv_tuner_TunerHal
153  * Method:    nativeWriteInBuffer
154  * Signature: (J[BI)I
155  */
Java_com_android_tv_tuner_TunerHal_nativeWriteInBuffer(JNIEnv * env,jobject thiz,jlong deviceId,jbyteArray javaBuffer,jint javaBufferSize)156 JNIEXPORT jint JNICALL Java_com_android_tv_tuner_TunerHal_nativeWriteInBuffer(
157     JNIEnv *env, jobject thiz, jlong deviceId, jbyteArray javaBuffer,
158     jint javaBufferSize) {
159   uint8_t tsBuffer[TS_PAYLOAD_SIZE];
160   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
161   if (it == sDvbManagers.end()) {
162     return -1;
163   }
164   DvbManager *dvbManager = it->second;
165 
166   // Always read multiple of TS_PACKET_SIZE
167   javaBufferSize = (javaBufferSize / TS_PACKET_SIZE) * TS_PACKET_SIZE;
168   int readBufferSize =
169       (javaBufferSize < TS_PAYLOAD_SIZE) ? javaBufferSize : TS_PAYLOAD_SIZE;
170 
171   int dataSize = dvbManager->readTsStream(env, thiz, tsBuffer, readBufferSize,
172                                           READ_TIMEOUT_MS);
173   if (dataSize == 0) {
174     ALOGD("No data to read DVR");
175     return 0;
176   } else if (dataSize < 0) {
177     return -1;
178   }
179 
180   sTotalBytesFetched += dataSize;
181 
182   env->SetByteArrayRegion(javaBuffer, 0, dataSize, (jbyte *)tsBuffer);
183   return dataSize;
184 }
185 
186 /*
187  * Class:     com_android_tv_tuner_TunerHal
188  * Method:    nativeSetHasPendingTune
189  * Signature: (JZ)V
190  */
191 JNIEXPORT void JNICALL
Java_com_android_tv_tuner_TunerHal_nativeSetHasPendingTune(JNIEnv *,jobject,jlong deviceId,jboolean hasPendingTune)192 Java_com_android_tv_tuner_TunerHal_nativeSetHasPendingTune(
193     JNIEnv *, jobject, jlong deviceId, jboolean hasPendingTune) {
194   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
195   if (it != sDvbManagers.end()) {
196     it->second->setHasPendingTune(hasPendingTune);
197   }
198 }
199 
200 /*
201  * Class:     com_android_tv_tuner_TunerHal
202  * Method:    nativeGetDeliverySystemType
203  * Signature: (J)I
204  */
205 JNIEXPORT int JNICALL
Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemType(JNIEnv * env,jobject thiz,jlong deviceId)206 Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemType(JNIEnv *env,
207                                                                jobject thiz,
208                                                                jlong deviceId) {
209   std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
210   if (it != sDvbManagers.end()) {
211     return it->second->getDeliverySystemType(env, thiz);
212   } else {
213     DvbManager *dvbManager = new DvbManager(env, thiz);
214     sDvbManagers.insert(std::pair<jlong, DvbManager *>(deviceId, dvbManager));
215     return dvbManager->getDeliverySystemType(env, thiz);
216   }
217 }
218 
219 /*
220  * Class:     com_android_tv_tuner_TunerHal
221  * Method:    nativeGetDeliverySystemTypes
222  * Signature: (J)I
223  */
224 JNIEXPORT jintArray JNICALL
Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemTypes(JNIEnv * env,jobject thiz,jlong deviceId)225 Java_com_android_tv_tuner_TunerHal_nativeGetDeliverySystemTypes(JNIEnv *env,
226                                                                jobject thiz,
227                                                                jlong deviceId) {
228     jintArray deliverySystemTypes = env->NewIntArray(8);
229     if (deliverySystemTypes == NULL) {
230         ALOGE("Out of memory!");
231         return NULL;
232     }
233     std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
234     if (it != sDvbManagers.end()) {
235         env->SetIntArrayRegion(deliverySystemTypes, 0, 8,
236         it->second->getDeliverySystemTypes(env, thiz));
237     } else {
238         DvbManager *dvbManager = new DvbManager(env, thiz);
239         sDvbManagers.insert(
240             std::pair<jlong, DvbManager *>(deviceId, dvbManager));
241         env->SetIntArrayRegion(deliverySystemTypes, 0, 8,
242         dvbManager->getDeliverySystemTypes(env, thiz));
243     }
244     return deliverySystemTypes;
245 }
246