blob: 5fa6a1f033290cb50a4d1cbb240f774054236c29 [file] [log] [blame]
shubang8ab43b12019-10-18 15:55:55 -07001/*
2 * Copyright 2019 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#define LOG_TAG "TvTuner-JNI"
18#include <utils/Log.h>
19
20#include "android_media_tv_Tuner.h"
21#include "android_runtime/AndroidRuntime.h"
22
23#include <android/hardware/tv/tuner/1.0/ITuner.h>
24#include <media/stagefright/foundation/ADebug.h>
25
26#pragma GCC diagnostic ignored "-Wunused-function"
27
shubang6f473d62019-11-01 15:42:21 -070028using ::android::hardware::Void;
shubang7e849b02019-10-18 19:36:25 -070029using ::android::hardware::hidl_vec;
shubang030afb52019-11-27 16:09:02 -080030using ::android::hardware::tv::tuner::V1_0::DataFormat;
shubang6f473d62019-11-01 15:42:21 -070031using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
shubang75c87082019-11-15 11:26:56 -080032using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
33using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
shubang13f15e02019-11-04 17:51:02 -080034using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
shubang964e6132019-11-26 15:05:22 -080035using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
shubang13f15e02019-11-04 17:51:02 -080036using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
shubang75c87082019-11-15 11:26:56 -080037using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
shubang6f473d62019-11-01 15:42:21 -070038using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
shubang030afb52019-11-27 16:09:02 -080039using ::android::hardware::tv::tuner::V1_0::DvrSettings;
shubang74bfd482019-10-29 19:10:22 -070040using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings;
41using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
42using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType;
shubang8ab43b12019-10-18 15:55:55 -070043using ::android::hardware::tv::tuner::V1_0::ITuner;
shubang030afb52019-11-27 16:09:02 -080044using ::android::hardware::tv::tuner::V1_0::PlaybackSettings;
45using ::android::hardware::tv::tuner::V1_0::RecordSettings;
shubang7e849b02019-10-18 19:36:25 -070046using ::android::hardware::tv::tuner::V1_0::Result;
shubang8ab43b12019-10-18 15:55:55 -070047
48struct fields_t {
shubang13f15e02019-11-04 17:51:02 -080049 jfieldID tunerContext;
shubangcdf30de2019-11-06 17:28:38 -080050 jfieldID filterContext;
shubang13f15e02019-11-04 17:51:02 -080051 jfieldID descramblerContext;
shubang4a0eddf2019-11-08 17:10:18 -080052 jfieldID dvrContext;
shubang7e849b02019-10-18 19:36:25 -070053 jmethodID frontendInitID;
shubang6f473d62019-11-01 15:42:21 -070054 jmethodID filterInitID;
shubang4a0eddf2019-11-08 17:10:18 -080055 jmethodID dvrInitID;
shubang4b8c5402019-10-24 17:49:53 -070056 jmethodID onFrontendEventID;
shubangcdf30de2019-11-06 17:28:38 -080057 jmethodID onFilterStatusID;
shubang760f0312019-11-12 17:11:28 -080058 jmethodID lnbInitID;
59 jmethodID onLnbEventID;
shubang13f15e02019-11-04 17:51:02 -080060 jmethodID descramblerInitID;
shubang8ab43b12019-10-18 15:55:55 -070061};
62
63static fields_t gFields;
64
65namespace android {
shubang760f0312019-11-12 17:11:28 -080066/////////////// LnbCallback ///////////////////////
67LnbCallback::LnbCallback(jweak tunerObj, LnbId id) : mObject(tunerObj), mId(id) {}
68
69Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) {
70 ALOGD("LnbCallback::onEvent, type=%d", lnbEventType);
71 JNIEnv *env = AndroidRuntime::getJNIEnv();
72 env->CallVoidMethod(
73 mObject,
74 gFields.onLnbEventID,
75 (jint)lnbEventType);
76 return Void();
77}
78Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) {
79 ALOGD("LnbCallback::onDiseqcMessage");
80 return Void();
81}
82
shubang4a0eddf2019-11-08 17:10:18 -080083/////////////// DvrCallback ///////////////////////
84Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) {
85 ALOGD("DvrCallback::onRecordStatus");
86 return Void();
87}
88
89Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) {
90 ALOGD("DvrCallback::onPlaybackStatus");
91 return Void();
92}
93
94void DvrCallback::setDvr(const jobject dvr) {
95 ALOGD("FilterCallback::setDvr");
96 JNIEnv *env = AndroidRuntime::getJNIEnv();
97 mDvr = env->NewWeakGlobalRef(dvr);
98}
99
shubang6f473d62019-11-01 15:42:21 -0700100/////////////// FilterCallback ///////////////////////
101//TODO: implement filter callback
shubangcdf30de2019-11-06 17:28:38 -0800102Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) {
shubang6f473d62019-11-01 15:42:21 -0700103 ALOGD("FilterCallback::onFilterEvent");
104 return Void();
105}
shubangcdf30de2019-11-06 17:28:38 -0800106
107Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
108 ALOGD("FilterCallback::onFilterStatus");
109 JNIEnv *env = AndroidRuntime::getJNIEnv();
110 env->CallVoidMethod(
111 mFilter,
112 gFields.onFilterStatusID,
113 (jint)status);
shubang6f473d62019-11-01 15:42:21 -0700114 return Void();
115}
shubang8ab43b12019-10-18 15:55:55 -0700116
shubangcdf30de2019-11-06 17:28:38 -0800117void FilterCallback::setFilter(const jobject filter) {
118 ALOGD("FilterCallback::setFilter");
119 JNIEnv *env = AndroidRuntime::getJNIEnv();
120 mFilter = env->NewWeakGlobalRef(filter);
121}
122
shubang7648a3c2019-11-25 18:16:45 -0800123/////////////// Filter ///////////////////////
124
125Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {}
126
shubang964e6132019-11-26 15:05:22 -0800127Filter::~Filter() {
128 EventFlag::deleteEventFlag(&mFilterMQEventFlag);
129}
130
131int Filter::close() {
132 Result r = mFilterSp->close();
133 if (r == Result::SUCCESS) {
134 EventFlag::deleteEventFlag(&mFilterMQEventFlag);
135 }
136 return (int)r;
137}
138
shubang7648a3c2019-11-25 18:16:45 -0800139sp<IFilter> Filter::getIFilter() {
140 return mFilterSp;
141}
142
shubang4b8c5402019-10-24 17:49:53 -0700143/////////////// FrontendCallback ///////////////////////
144
145FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
146
147Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
148 ALOGD("FrontendCallback::onEvent, type=%d", frontendEventType);
149 JNIEnv *env = AndroidRuntime::getJNIEnv();
150 env->CallVoidMethod(
151 mObject,
152 gFields.onFrontendEventID,
153 (jint)frontendEventType);
154 return Void();
155}
156Return<void> FrontendCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) {
157 ALOGD("FrontendCallback::onDiseqcMessage");
158 return Void();
159}
160
161Return<void> FrontendCallback::onScanMessage(
162 FrontendScanMessageType type, const FrontendScanMessage& /*message*/) {
163 ALOGD("FrontendCallback::onScanMessage, type=%d", type);
164 return Void();
165}
166
shubang6f473d62019-11-01 15:42:21 -0700167/////////////// Tuner ///////////////////////
shubang4b8c5402019-10-24 17:49:53 -0700168
shubang8ab43b12019-10-18 15:55:55 -0700169sp<ITuner> JTuner::mTuner;
170
171JTuner::JTuner(JNIEnv *env, jobject thiz)
172 : mClass(NULL) {
173 jclass clazz = env->GetObjectClass(thiz);
174 CHECK(clazz != NULL);
175
176 mClass = (jclass)env->NewGlobalRef(clazz);
177 mObject = env->NewWeakGlobalRef(thiz);
178 if (mTuner == NULL) {
179 mTuner = getTunerService();
180 }
181}
182
183JTuner::~JTuner() {
184 JNIEnv *env = AndroidRuntime::getJNIEnv();
185
186 env->DeleteGlobalRef(mClass);
187 mTuner = NULL;
188 mClass = NULL;
189 mObject = NULL;
190}
191
192sp<ITuner> JTuner::getTunerService() {
193 if (mTuner == nullptr) {
194 mTuner = ITuner::getService();
195
196 if (mTuner == nullptr) {
197 ALOGW("Failed to get tuner service.");
198 }
199 }
200 return mTuner;
201}
202
shubang7e849b02019-10-18 19:36:25 -0700203jobject JTuner::getFrontendIds() {
204 ALOGD("JTuner::getFrontendIds()");
shubang7e849b02019-10-18 19:36:25 -0700205 mTuner->getFrontendIds([&](Result, const hidl_vec<FrontendId>& frontendIds) {
shubang4b8c5402019-10-24 17:49:53 -0700206 mFeIds = frontendIds;
shubang7e849b02019-10-18 19:36:25 -0700207 });
shubang4b8c5402019-10-24 17:49:53 -0700208 if (mFeIds.size() == 0) {
shubang7e849b02019-10-18 19:36:25 -0700209 ALOGW("Frontend isn't available");
210 return NULL;
211 }
212
213 JNIEnv *env = AndroidRuntime::getJNIEnv();
214 jclass arrayListClazz = env->FindClass("java/util/ArrayList");
215 jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
216 jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
217
218 jclass integerClazz = env->FindClass("java/lang/Integer");
219 jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
220
shubang4b8c5402019-10-24 17:49:53 -0700221 for (int i=0; i < mFeIds.size(); i++) {
222 jobject idObj = env->NewObject(integerClazz, intInit, mFeIds[i]);
shubang7e849b02019-10-18 19:36:25 -0700223 env->CallBooleanMethod(obj, arrayListAdd, idObj);
224 }
225 return obj;
226}
227
228jobject JTuner::openFrontendById(int id) {
shubang4b8c5402019-10-24 17:49:53 -0700229 sp<IFrontend> fe;
shubang7e849b02019-10-18 19:36:25 -0700230 mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) {
shubang4b8c5402019-10-24 17:49:53 -0700231 fe = frontend;
shubang7e849b02019-10-18 19:36:25 -0700232 });
shubang4b8c5402019-10-24 17:49:53 -0700233 if (fe == nullptr) {
shubang7e849b02019-10-18 19:36:25 -0700234 ALOGE("Failed to open frontend");
235 return NULL;
236 }
shubang4b8c5402019-10-24 17:49:53 -0700237 mFe = fe;
238 sp<FrontendCallback> feCb = new FrontendCallback(mObject, id);
239 fe->setCallback(feCb);
shubang7e849b02019-10-18 19:36:25 -0700240
241 jint jId = (jint) id;
shubang964e6132019-11-26 15:05:22 -0800242
shubang7e849b02019-10-18 19:36:25 -0700243 JNIEnv *env = AndroidRuntime::getJNIEnv();
244 // TODO: add more fields to frontend
245 return env->NewObject(
246 env->FindClass("android/media/tv/tuner/Tuner$Frontend"),
247 gFields.frontendInitID,
shubang4b8c5402019-10-24 17:49:53 -0700248 mObject,
shubang7e849b02019-10-18 19:36:25 -0700249 (jint) jId);
250}
251
shubang760f0312019-11-12 17:11:28 -0800252jobject JTuner::getLnbIds() {
253 ALOGD("JTuner::getLnbIds()");
254 mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) {
255 mLnbIds = lnbIds;
256 });
257 if (mLnbIds.size() == 0) {
258 ALOGW("Lnb isn't available");
259 return NULL;
260 }
261
262 JNIEnv *env = AndroidRuntime::getJNIEnv();
263 jclass arrayListClazz = env->FindClass("java/util/ArrayList");
264 jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
265 jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
266
267 jclass integerClazz = env->FindClass("java/lang/Integer");
268 jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
269
270 for (int i=0; i < mLnbIds.size(); i++) {
271 jobject idObj = env->NewObject(integerClazz, intInit, mLnbIds[i]);
272 env->CallBooleanMethod(obj, arrayListAdd, idObj);
273 }
274 return obj;
275}
276
277jobject JTuner::openLnbById(int id) {
278 sp<ILnb> lnbSp;
279 mTuner->openLnbById(id, [&](Result, const sp<ILnb>& lnb) {
280 lnbSp = lnb;
281 });
282 if (lnbSp == nullptr) {
283 ALOGE("Failed to open lnb");
284 return NULL;
285 }
286 mLnb = lnbSp;
287 sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
288 mLnb->setCallback(lnbCb);
289
290 JNIEnv *env = AndroidRuntime::getJNIEnv();
291 return env->NewObject(
292 env->FindClass("android/media/tv/tuner/Tuner$Lnb"),
293 gFields.lnbInitID,
294 mObject,
295 id);
296}
297
shubang74bfd482019-10-29 19:10:22 -0700298int JTuner::tune(const FrontendSettings& settings) {
299 if (mFe == NULL) {
300 ALOGE("frontend is not initialized");
301 return (int)Result::INVALID_STATE;
302 }
303 Result result = mFe->tune(settings);
304 return (int)result;
305}
306
shubang6f473d62019-11-01 15:42:21 -0700307bool JTuner::openDemux() {
308 if (mTuner == nullptr) {
309 return false;
310 }
311 if (mDemux != nullptr) {
312 return true;
313 }
314 mTuner->openDemux([&](Result, uint32_t demuxId, const sp<IDemux>& demux) {
315 mDemux = demux;
316 mDemuxId = demuxId;
317 ALOGD("open demux, id = %d", demuxId);
318 });
319 if (mDemux == nullptr) {
320 return false;
321 }
322 return true;
323}
324
shubang13f15e02019-11-04 17:51:02 -0800325jobject JTuner::openDescrambler() {
326 ALOGD("JTuner::openDescrambler");
327 if (mTuner == nullptr) {
328 return NULL;
329 }
330 sp<IDescrambler> descramblerSp;
331 mTuner->openDescrambler([&](Result, const sp<IDescrambler>& descrambler) {
332 descramblerSp = descrambler;
333 });
334
335 if (descramblerSp == NULL) {
336 return NULL;
337 }
338
339 JNIEnv *env = AndroidRuntime::getJNIEnv();
340 jobject descramblerObj =
341 env->NewObject(
342 env->FindClass("android/media/tv/tuner/Tuner$Descrambler"),
343 gFields.descramblerInitID,
344 mObject);
345
346 descramblerSp->incStrong(descramblerObj);
347 env->SetLongField(descramblerObj, gFields.descramblerContext, (jlong)descramblerSp.get());
348
349 return descramblerObj;
350}
351
shubang6f473d62019-11-01 15:42:21 -0700352jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
353 if (mDemux == NULL) {
354 if (!openDemux()) {
355 return NULL;
356 }
357 }
358
shubang7648a3c2019-11-25 18:16:45 -0800359 sp<IFilter> iFilterSp;
shubangcdf30de2019-11-06 17:28:38 -0800360 sp<FilterCallback> callback = new FilterCallback();
361 mDemux->openFilter(type, bufferSize, callback,
shubang6f473d62019-11-01 15:42:21 -0700362 [&](Result, const sp<IFilter>& filter) {
shubang7648a3c2019-11-25 18:16:45 -0800363 iFilterSp = filter;
shubang6f473d62019-11-01 15:42:21 -0700364 });
shubang7648a3c2019-11-25 18:16:45 -0800365 if (iFilterSp == NULL) {
shubang6f473d62019-11-01 15:42:21 -0700366 ALOGD("Failed to open filter, type = %d", type.mainType);
367 return NULL;
368 }
369 int fId;
shubang7648a3c2019-11-25 18:16:45 -0800370 iFilterSp->getId([&](Result, uint32_t filterId) {
shubang6f473d62019-11-01 15:42:21 -0700371 fId = filterId;
372 });
shubang6f473d62019-11-01 15:42:21 -0700373
374 JNIEnv *env = AndroidRuntime::getJNIEnv();
shubangcdf30de2019-11-06 17:28:38 -0800375 jobject filterObj =
376 env->NewObject(
377 env->FindClass("android/media/tv/tuner/Tuner$Filter"),
378 gFields.filterInitID,
379 mObject,
380 (jint) fId);
381
shubang7648a3c2019-11-25 18:16:45 -0800382 sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
shubangcdf30de2019-11-06 17:28:38 -0800383 filterSp->incStrong(filterObj);
384 env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
385
386 callback->setFilter(filterObj);
387
388 return filterObj;
shubang6f473d62019-11-01 15:42:21 -0700389}
390
shubang4a0eddf2019-11-08 17:10:18 -0800391jobject JTuner::openDvr(DvrType type, int bufferSize) {
392 ALOGD("JTuner::openDvr");
393 if (mDemux == NULL) {
394 if (!openDemux()) {
395 return NULL;
396 }
397 }
398 sp<IDvr> dvrSp;
399 sp<DvrCallback> callback = new DvrCallback();
400 mDemux->openDvr(type, bufferSize, callback,
401 [&](Result, const sp<IDvr>& dvr) {
402 dvrSp = dvr;
403 });
404
405 if (dvrSp == NULL) {
406 return NULL;
407 }
408
409 JNIEnv *env = AndroidRuntime::getJNIEnv();
410 jobject dvrObj =
411 env->NewObject(
412 env->FindClass("android/media/tv/tuner/Tuner$Dvr"),
413 gFields.dvrInitID,
414 mObject);
415
416 dvrSp->incStrong(dvrObj);
417 env->SetLongField(dvrObj, gFields.dvrContext, (jlong)dvrSp.get());
418
419 callback->setDvr(dvrObj);
420
421 return dvrObj;
422}
423
shubang8ab43b12019-10-18 15:55:55 -0700424} // namespace android
425
426////////////////////////////////////////////////////////////////////////////////
427
428using namespace android;
429
430static sp<JTuner> setTuner(JNIEnv *env, jobject thiz, const sp<JTuner> &tuner) {
shubang13f15e02019-11-04 17:51:02 -0800431 sp<JTuner> old = (JTuner *)env->GetLongField(thiz, gFields.tunerContext);
shubang8ab43b12019-10-18 15:55:55 -0700432
433 if (tuner != NULL) {
434 tuner->incStrong(thiz);
435 }
436 if (old != NULL) {
437 old->decStrong(thiz);
438 }
shubang13f15e02019-11-04 17:51:02 -0800439 env->SetLongField(thiz, gFields.tunerContext, (jlong)tuner.get());
shubang8ab43b12019-10-18 15:55:55 -0700440
441 return old;
442}
443
444static sp<JTuner> getTuner(JNIEnv *env, jobject thiz) {
shubang13f15e02019-11-04 17:51:02 -0800445 return (JTuner *)env->GetLongField(thiz, gFields.tunerContext);
446}
447
448static sp<IDescrambler> getDescrambler(JNIEnv *env, jobject descrambler) {
449 return (IDescrambler *)env->GetLongField(descrambler, gFields.descramblerContext);
450}
451
452static DemuxPid getDemuxPid(int pidType, int pid) {
453 DemuxPid demuxPid;
454 if ((int)pidType == 1) {
455 demuxPid.tPid(static_cast<DemuxTpid>(pid));
456 } else if ((int)pidType == 2) {
457 demuxPid.mmtpPid(static_cast<DemuxMmtpPid>(pid));
458 }
459 return demuxPid;
shubang8ab43b12019-10-18 15:55:55 -0700460}
461
shubang74bfd482019-10-29 19:10:22 -0700462static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) {
463 FrontendSettings frontendSettings;
464 jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings");
shubang964e6132019-11-26 15:05:22 -0800465 jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I");
shubang74bfd482019-10-29 19:10:22 -0700466 uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField));
467
468 // TODO: handle the other 8 types of settings
469 if (type == 1) {
470 // analog
471 clazz = env->FindClass("android/media/tv/tuner/FrontendSettings$FrontendAnalogSettings");
472 FrontendAnalogType analogType =
473 static_cast<FrontendAnalogType>(
474 env->GetIntField(settings, env->GetFieldID(clazz, "mAnalogType", "I")));
475 FrontendAnalogSifStandard sifStandard =
476 static_cast<FrontendAnalogSifStandard>(
477 env->GetIntField(settings, env->GetFieldID(clazz, "mSifStandard", "I")));
478 FrontendAnalogSettings frontendAnalogSettings {
479 .frequency = freq,
480 .type = analogType,
481 .sifStandard = sifStandard,
482 };
483 frontendSettings.analog(frontendAnalogSettings);
484 }
485 return frontendSettings;
486}
487
shubang7648a3c2019-11-25 18:16:45 -0800488static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
489 return (Filter *)env->GetLongField(filter, gFields.filterContext);
shubangcdf30de2019-11-06 17:28:38 -0800490}
491
shubang030afb52019-11-27 16:09:02 -0800492static DvrSettings getDvrSettings(JNIEnv *env, jobject settings) {
493 DvrSettings dvrSettings;
494 jclass clazz = env->FindClass("android/media/tv/tuner/DvrSettings");
495 uint32_t statusMask =
496 static_cast<uint32_t>(env->GetIntField(
497 settings, env->GetFieldID(clazz, "mStatusMask", "I")));
498 uint32_t lowThreshold =
499 static_cast<uint32_t>(env->GetIntField(
500 settings, env->GetFieldID(clazz, "mLowThreshold", "I")));
501 uint32_t highThreshold =
502 static_cast<uint32_t>(env->GetIntField(
503 settings, env->GetFieldID(clazz, "mHighThreshold", "I")));
504 uint8_t packetSize =
505 static_cast<uint8_t>(env->GetIntField(
506 settings, env->GetFieldID(clazz, "mPacketSize", "I")));
507 DataFormat dataFormat =
508 static_cast<DataFormat>(env->GetIntField(
509 settings, env->GetFieldID(clazz, "mDataFormat", "I")));
510 DvrType type =
511 static_cast<DvrType>(env->GetIntField(
512 settings, env->GetFieldID(clazz, "mType", "I")));
513 if (type == DvrType::RECORD) {
514 RecordSettings recordSettings {
515 .statusMask = static_cast<unsigned char>(statusMask),
516 .lowThreshold = lowThreshold,
517 .highThreshold = highThreshold,
518 .dataFormat = dataFormat,
519 .packetSize = packetSize,
520 };
521 dvrSettings.record(recordSettings);
522 } else if (type == DvrType::PLAYBACK) {
523 PlaybackSettings PlaybackSettings {
524 .statusMask = statusMask,
525 .lowThreshold = lowThreshold,
526 .highThreshold = highThreshold,
527 .dataFormat = dataFormat,
528 .packetSize = packetSize,
529 };
530 dvrSettings.playback(PlaybackSettings);
531 }
532 return dvrSettings;
533}
534
shubang4a0eddf2019-11-08 17:10:18 -0800535static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) {
536 return (IDvr *)env->GetLongField(dvr, gFields.dvrContext);
537}
538
shubang8ab43b12019-10-18 15:55:55 -0700539static void android_media_tv_Tuner_native_init(JNIEnv *env) {
540 jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
541 CHECK(clazz != NULL);
542
shubang13f15e02019-11-04 17:51:02 -0800543 gFields.tunerContext = env->GetFieldID(clazz, "mNativeContext", "J");
544 CHECK(gFields.tunerContext != NULL);
shubang7e849b02019-10-18 19:36:25 -0700545
shubang4b8c5402019-10-24 17:49:53 -0700546 gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V");
547
shubang760f0312019-11-12 17:11:28 -0800548 gFields.onLnbEventID = env->GetMethodID(clazz, "onLnbEvent", "(I)V");
549
shubang7e849b02019-10-18 19:36:25 -0700550 jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
shubang4b8c5402019-10-24 17:49:53 -0700551 gFields.frontendInitID =
552 env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
shubang6f473d62019-11-01 15:42:21 -0700553
shubang760f0312019-11-12 17:11:28 -0800554 jclass lnbClazz = env->FindClass("android/media/tv/tuner/Tuner$Lnb");
555 gFields.lnbInitID =
556 env->GetMethodID(lnbClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
557
shubang6f473d62019-11-01 15:42:21 -0700558 jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter");
shubangcdf30de2019-11-06 17:28:38 -0800559 gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
shubang6f473d62019-11-01 15:42:21 -0700560 gFields.filterInitID =
561 env->GetMethodID(filterClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
shubangcdf30de2019-11-06 17:28:38 -0800562 gFields.onFilterStatusID =
563 env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
shubang13f15e02019-11-04 17:51:02 -0800564
565 jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Tuner$Descrambler");
566 gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J");
567 gFields.descramblerInitID =
568 env->GetMethodID(descramblerClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;)V");
shubang4a0eddf2019-11-08 17:10:18 -0800569
570 jclass dvrClazz = env->FindClass("android/media/tv/tuner/Tuner$Dvr");
571 gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J");
572 gFields.dvrInitID = env->GetMethodID(dvrClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;)V");
shubang8ab43b12019-10-18 15:55:55 -0700573}
574
575static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
576 sp<JTuner> tuner = new JTuner(env, thiz);
577 setTuner(env,thiz, tuner);
578}
579
shubang7e849b02019-10-18 19:36:25 -0700580static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz) {
581 sp<JTuner> tuner = getTuner(env, thiz);
582 return tuner->getFrontendIds();
583}
584
585static jobject android_media_tv_Tuner_open_frontend_by_id(JNIEnv *env, jobject thiz, jint id) {
586 sp<JTuner> tuner = getTuner(env, thiz);
587 return tuner->openFrontendById(id);
588}
589
shubang74bfd482019-10-29 19:10:22 -0700590static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
591 sp<JTuner> tuner = getTuner(env, thiz);
592 return tuner->tune(getFrontendSettings(env, type, settings));
593}
594
shubang760f0312019-11-12 17:11:28 -0800595static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
596 sp<JTuner> tuner = getTuner(env, thiz);
597 return tuner->getLnbIds();
598}
599
600static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, jint id) {
601 sp<JTuner> tuner = getTuner(env, thiz);
602 return tuner->openLnbById(id);
603}
604
shubang6f473d62019-11-01 15:42:21 -0700605static jobject android_media_tv_Tuner_open_filter(
606 JNIEnv *env, jobject thiz, jint type, jint subType, jint bufferSize) {
607 sp<JTuner> tuner = getTuner(env, thiz);
608 DemuxFilterType filterType {
609 .mainType = static_cast<DemuxFilterMainType>(type),
610 };
611
612 // TODO: other sub types
613 filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
614
615 return tuner->openFilter(filterType, bufferSize);
616}
617
shubang75c87082019-11-15 11:26:56 -0800618static DemuxFilterSettings getFilterSettings(
619 JNIEnv *env, int type, int subtype, jobject filterSettingsObj) {
620 DemuxFilterSettings filterSettings;
621 // TODO: more setting types
622 jobject settingsObj =
623 env->GetObjectField(
624 filterSettingsObj,
625 env->GetFieldID(
626 env->FindClass("android/media/tv/tuner/FilterSettings"),
627 "mSettings",
628 "Landroid/media/tv/tuner/FilterSettings$Settings;"));
629 if (type == (int)DemuxFilterMainType::TS) {
630 // DemuxTsFilterSettings
631 jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings");
632 int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I"));
633 if (subtype == (int)DemuxTsFilterType::PES) {
634 // DemuxFilterPesDataSettings
635 jclass settingClazz =
636 env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings");
637 int streamId = env->GetIntField(
638 settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I"));
639 bool isRaw = (bool)env->GetBooleanField(
640 settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z"));
641 DemuxFilterPesDataSettings filterPesDataSettings {
642 .streamId = static_cast<uint16_t>(streamId),
643 .isRaw = isRaw,
644 };
645 DemuxTsFilterSettings tsFilterSettings {
646 .tpid = static_cast<uint16_t>(tpid),
647 };
648 tsFilterSettings.filterSettings.pesData(filterPesDataSettings);
649 filterSettings.ts(tsFilterSettings);
650 }
651 }
652 return filterSettings;
653}
654
shubang964e6132019-11-26 15:05:22 -0800655static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) {
656 ALOGD("copyData, size=%d, offset=%d", size, offset);
657
658 int available = filter->mFilterMQ->availableToRead();
659 ALOGD("copyData, available=%d", available);
660 size = std::min(size, available);
661
662 jboolean isCopy;
663 jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
664 ALOGD("copyData, isCopy=%d", isCopy);
665 if (dst == nullptr) {
666 ALOGD("Failed to GetByteArrayElements");
667 return 0;
668 }
669
670 if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) {
671 env->ReleaseByteArrayElements(buffer, dst, 0);
672 filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
673 } else {
674 ALOGD("Failed to read FMQ");
675 env->ReleaseByteArrayElements(buffer, dst, 0);
676 return 0;
677 }
678 return size;
679}
680
shubang75c87082019-11-15 11:26:56 -0800681static int android_media_tv_Tuner_configure_filter(
682 JNIEnv *env, jobject filter, int type, int subtype, jobject settings) {
683 ALOGD("configure filter type=%d, subtype=%d", type, subtype);
shubang964e6132019-11-26 15:05:22 -0800684 sp<Filter> filterSp = getFilter(env, filter);
685 sp<IFilter> iFilterSp = filterSp->getIFilter();
686 if (iFilterSp == NULL) {
shubang75c87082019-11-15 11:26:56 -0800687 ALOGD("Failed to configure filter: filter not found");
688 return (int)Result::INVALID_STATE;
689 }
690 DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings);
shubang964e6132019-11-26 15:05:22 -0800691 Result res = iFilterSp->configure(filterSettings);
692 MQDescriptorSync<uint8_t> filterMQDesc;
693 if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) {
694 Result getQueueDescResult = Result::UNKNOWN_ERROR;
695 iFilterSp->getQueueDesc(
696 [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
697 filterMQDesc = desc;
698 getQueueDescResult = r;
699 ALOGD("getFilterQueueDesc");
700 });
701 if (getQueueDescResult == Result::SUCCESS) {
702 filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true);
703 EventFlag::createEventFlag(
704 filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag));
705 }
706 }
shubang75c87082019-11-15 11:26:56 -0800707 return (int)res;
708}
709
shubangd0977902019-11-07 18:58:43 -0800710static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
shubang7648a3c2019-11-25 18:16:45 -0800711 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubangd0977902019-11-07 18:58:43 -0800712 if (filterSp == NULL) {
713 ALOGD("Failed to start filter: filter not found");
714 return false;
715 }
716 return filterSp->start() == Result::SUCCESS;
717}
718
719static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
shubang7648a3c2019-11-25 18:16:45 -0800720 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubangd0977902019-11-07 18:58:43 -0800721 if (filterSp == NULL) {
722 ALOGD("Failed to stop filter: filter not found");
723 return false;
724 }
725 return filterSp->stop() == Result::SUCCESS;
726}
727
728static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
shubang7648a3c2019-11-25 18:16:45 -0800729 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubangd0977902019-11-07 18:58:43 -0800730 if (filterSp == NULL) {
731 ALOGD("Failed to flush filter: filter not found");
732 return false;
733 }
734 return filterSp->flush() == Result::SUCCESS;
735}
736
shubang964e6132019-11-26 15:05:22 -0800737static int android_media_tv_Tuner_read_filter_fmq(
738 JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) {
739 sp<Filter> filterSp = getFilter(env, filter);
740 if (filterSp == NULL) {
741 ALOGD("Failed to read filter FMQ: filter not found");
742 return 0;
743 }
744 return copyData(env, filterSp, buffer, offset, size);
745}
746
shubang13f15e02019-11-04 17:51:02 -0800747static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
748 sp<JTuner> tuner = getTuner(env, thiz);
749 return tuner->openDescrambler();
750}
751
752static bool android_media_tv_Tuner_add_pid(
753 JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) {
754 sp<IDescrambler> descramblerSp = getDescrambler(env, descrambler);
755 if (descramblerSp == NULL) {
756 return false;
757 }
shubang7648a3c2019-11-25 18:16:45 -0800758 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubang13f15e02019-11-04 17:51:02 -0800759 Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp);
760 return result == Result::SUCCESS;
761}
762
763static bool android_media_tv_Tuner_remove_pid(
764 JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) {
765 sp<IDescrambler> descramblerSp = getDescrambler(env, descrambler);
766 if (descramblerSp == NULL) {
767 return false;
768 }
shubang7648a3c2019-11-25 18:16:45 -0800769 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubang13f15e02019-11-04 17:51:02 -0800770 Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp);
771 return result == Result::SUCCESS;
772}
773
shubang4a0eddf2019-11-08 17:10:18 -0800774static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint type, jint bufferSize) {
775 sp<JTuner> tuner = getTuner(env, thiz);
776 return tuner->openDvr(static_cast<DvrType>(type), bufferSize);
777}
778
779static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
780 sp<IDvr> dvrSp = getDvr(env, dvr);
shubang7648a3c2019-11-25 18:16:45 -0800781 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubang4a0eddf2019-11-08 17:10:18 -0800782 if (dvrSp == NULL || filterSp == NULL) {
783 return false;
784 }
785 Result result = dvrSp->attachFilter(filterSp);
786 return result == Result::SUCCESS;
787}
788
789static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
790 sp<IDvr> dvrSp = getDvr(env, dvr);
shubang7648a3c2019-11-25 18:16:45 -0800791 sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
shubang4a0eddf2019-11-08 17:10:18 -0800792 if (dvrSp == NULL || filterSp == NULL) {
793 return false;
794 }
795 Result result = dvrSp->detachFilter(filterSp);
796 return result == Result::SUCCESS;
797}
798
shubang030afb52019-11-27 16:09:02 -0800799static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
800 sp<IDvr> dvrSp = getDvr(env, dvr);
801 if (dvrSp == NULL) {
802 ALOGD("Failed to configure dvr: dvr not found");
803 return (int)Result::INVALID_STATE;
804 }
805 Result result = dvrSp->configure(getDvrSettings(env, settings));
806 return (int)result;
807}
808
shubang4a0eddf2019-11-08 17:10:18 -0800809static bool android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
810 sp<IDvr> dvrSp = getDvr(env, dvr);
811 if (dvrSp == NULL) {
812 ALOGD("Failed to start dvr: dvr not found");
813 return false;
814 }
815 return dvrSp->start() == Result::SUCCESS;
816}
817
818static bool android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
819 sp<IDvr> dvrSp = getDvr(env, dvr);
820 if (dvrSp == NULL) {
821 ALOGD("Failed to stop dvr: dvr not found");
822 return false;
823 }
824 return dvrSp->stop() == Result::SUCCESS;
825}
826
827static bool android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
828 sp<IDvr> dvrSp = getDvr(env, dvr);
829 if (dvrSp == NULL) {
830 ALOGD("Failed to flush dvr: dvr not found");
831 return false;
832 }
833 return dvrSp->flush() == Result::SUCCESS;
834}
835
shubangd0977902019-11-07 18:58:43 -0800836static const JNINativeMethod gTunerMethods[] = {
shubang8ab43b12019-10-18 15:55:55 -0700837 { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
838 { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
shubang7e849b02019-10-18 19:36:25 -0700839 { "nativeGetFrontendIds", "()Ljava/util/List;",
840 (void *)android_media_tv_Tuner_get_frontend_ids },
841 { "nativeOpenFrontendById", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
842 (void *)android_media_tv_Tuner_open_frontend_by_id },
shubang74bfd482019-10-29 19:10:22 -0700843 { "nativeTune", "(ILandroid/media/tv/tuner/FrontendSettings;)I",
844 (void *)android_media_tv_Tuner_tune },
shubang6f473d62019-11-01 15:42:21 -0700845 { "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
846 (void *)android_media_tv_Tuner_open_filter },
shubang760f0312019-11-12 17:11:28 -0800847 { "nativeGetLnbIds", "()Ljava/util/List;",
848 (void *)android_media_tv_Tuner_get_lnb_ids },
849 { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Tuner$Lnb;",
850 (void *)android_media_tv_Tuner_open_lnb_by_id },
shubang13f15e02019-11-04 17:51:02 -0800851 { "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Tuner$Descrambler;",
852 (void *)android_media_tv_Tuner_open_descrambler },
shubang4a0eddf2019-11-08 17:10:18 -0800853 { "nativeOpenDvr", "(II)Landroid/media/tv/tuner/Tuner$Dvr;",
854 (void *)android_media_tv_Tuner_open_dvr },
shubang8ab43b12019-10-18 15:55:55 -0700855};
856
shubangd0977902019-11-07 18:58:43 -0800857static const JNINativeMethod gFilterMethods[] = {
shubang75c87082019-11-15 11:26:56 -0800858 { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I",
859 (void *)android_media_tv_Tuner_configure_filter },
shubangd0977902019-11-07 18:58:43 -0800860 { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter },
861 { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter },
862 { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter },
shubang964e6132019-11-26 15:05:22 -0800863 { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq },
shubangd0977902019-11-07 18:58:43 -0800864};
865
shubang13f15e02019-11-04 17:51:02 -0800866static const JNINativeMethod gDescramblerMethods[] = {
867 { "nativeAddPid", "(IILandroid/media/tv/tuner/Tuner$Filter;)Z",
868 (void *)android_media_tv_Tuner_add_pid },
869 { "nativeRemovePid", "(IILandroid/media/tv/tuner/Tuner$Filter;)Z",
870 (void *)android_media_tv_Tuner_remove_pid },
871};
872
shubang4a0eddf2019-11-08 17:10:18 -0800873static const JNINativeMethod gDvrMethods[] = {
874 { "nativeAttachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
875 (void *)android_media_tv_Tuner_attach_filter },
876 { "nativeDetachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
877 (void *)android_media_tv_Tuner_detach_filter },
shubang030afb52019-11-27 16:09:02 -0800878 { "nativeConfigureDvr", "(Landroid/media/tv/tuner/DvrSettings;)I",
879 (void *)android_media_tv_Tuner_configure_dvr },
shubang4a0eddf2019-11-08 17:10:18 -0800880 { "nativeStartDvr", "()Z", (void *)android_media_tv_Tuner_start_dvr },
881 { "nativeStopDvr", "()Z", (void *)android_media_tv_Tuner_stop_dvr },
882 { "nativeFlushDvr", "()Z", (void *)android_media_tv_Tuner_flush_dvr },
883};
884
shubangd0977902019-11-07 18:58:43 -0800885static bool register_android_media_tv_Tuner(JNIEnv *env) {
886 if (AndroidRuntime::registerNativeMethods(
887 env, "android/media/tv/tuner/Tuner", gTunerMethods, NELEM(gTunerMethods)) != JNI_OK) {
888 ALOGE("Failed to register tuner native methods");
889 return false;
890 }
891 if (AndroidRuntime::registerNativeMethods(
892 env, "android/media/tv/tuner/Tuner$Filter",
893 gFilterMethods,
894 NELEM(gFilterMethods)) != JNI_OK) {
895 ALOGE("Failed to register filter native methods");
896 return false;
897 }
shubang13f15e02019-11-04 17:51:02 -0800898 if (AndroidRuntime::registerNativeMethods(
899 env, "android/media/tv/tuner/Tuner$Descrambler",
900 gDescramblerMethods,
901 NELEM(gDescramblerMethods)) != JNI_OK) {
902 ALOGE("Failed to register descrambler native methods");
903 return false;
904 }
shubang4a0eddf2019-11-08 17:10:18 -0800905 if (AndroidRuntime::registerNativeMethods(
906 env, "android/media/tv/tuner/Tuner$Dvr",
907 gDvrMethods,
908 NELEM(gDvrMethods)) != JNI_OK) {
909 ALOGE("Failed to register dvr native methods");
910 return false;
911 }
shubangd0977902019-11-07 18:58:43 -0800912 return true;
shubang8ab43b12019-10-18 15:55:55 -0700913}
914
915jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
916{
917 JNIEnv* env = NULL;
918 jint result = -1;
919
920 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
921 ALOGE("ERROR: GetEnv failed\n");
922 return result;
923 }
924 assert(env != NULL);
925
shubangd0977902019-11-07 18:58:43 -0800926 if (!register_android_media_tv_Tuner(env)) {
shubang8ab43b12019-10-18 15:55:55 -0700927 ALOGE("ERROR: Tuner native registration failed\n");
928 return result;
929 }
930 return JNI_VERSION_1_4;
931}