blob: 42eb8739c9e7dd890250b1e95790dc05676c2b37 [file] [log] [blame]
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -07001/**
2 * Copyright (C) 2017 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
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070017#define LOG_TAG "BroadcastRadioService.Tuner.jni"
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070018#define LOG_NDEBUG 0
19
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070020#include "Tuner.h"
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070021
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070022#include "convert.h"
23#include "TunerCallback.h"
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070024
Tomasz Wasilczyk20eef7d2017-09-14 09:42:54 -070025#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -070026#include <binder/IPCThreadState.h>
Tomasz Wasilczyk8e67a332017-12-04 09:54:56 -080027#include <broadcastradio-utils-1x/Utils.h>
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070028#include <core_jni_helpers.h>
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -070029#include <media/AudioSystem.h>
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -070030#include <nativehelper/JNIHelp.h>
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070031#include <utils/Log.h>
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070032
33namespace android {
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070034namespace server {
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -070035namespace BroadcastRadio {
Tomasz Wasilczyk21348172017-04-20 14:02:42 -070036namespace Tuner {
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070037
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -070038using std::lock_guard;
39using std::mutex;
40
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070041using hardware::Return;
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -070042using hardware::hidl_death_recipient;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070043using hardware::hidl_vec;
44
45namespace V1_0 = hardware::broadcastradio::V1_0;
46namespace V1_1 = hardware::broadcastradio::V1_1;
Tomasz Wasilczyk20eef7d2017-09-14 09:42:54 -070047namespace V1_2 = hardware::broadcastradio::V1_2;
48namespace utils = hardware::broadcastradio::utils;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070049
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -070050using V1_0::Band;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070051using V1_0::BandConfig;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070052using V1_0::MetaData;
53using V1_0::Result;
Tomasz Wasilczyk3ccddd62017-11-17 00:21:21 +000054using V1_1::ProgramListResult;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000055using V1_1::VendorKeyValue;
56using V1_2::ITunerCallback;
Tomasz Wasilczyk20eef7d2017-09-14 09:42:54 -070057using utils::HalRevision;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070058
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -070059static mutex gContextMutex;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070060
Tomasz Wasilczyk31c8df02017-04-26 14:47:08 -070061static struct {
62 struct {
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -070063 jclass clazz;
64 jmethodID cstor;
65 jmethodID add;
66 } ArrayList;
67 struct {
Tomasz Wasilczyk31c8df02017-04-26 14:47:08 -070068 jfieldID nativeContext;
69 jfieldID region;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -070070 jfieldID tunerCallback;
Tomasz Wasilczyk31c8df02017-04-26 14:47:08 -070071 } Tuner;
72} gjni;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070073
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -070074static const char* const kAudioDeviceName = "Radio tuner source";
75
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -070076class HalDeathRecipient : public hidl_death_recipient {
77 wp<V1_1::ITunerCallback> mTunerCallback;
78
79public:
80 HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback):mTunerCallback(tunerCallback) {}
81
82 virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who);
83};
84
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070085struct TunerContext {
86 TunerContext() {}
87
Tomasz Wasilczyke8f4b342017-06-19 10:48:16 -070088 bool mIsClosed = false;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -070089 HalRevision mHalRev;
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -070090 bool mWithAudio;
Tomasz Wasilczykb1a6fea2017-09-12 10:21:16 -070091 bool mIsAudioConnected = false;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -070092 Band mBand;
Tomasz Wasilczyk4482b142017-07-17 13:57:12 -070093 wp<V1_0::IBroadcastRadio> mHalModule;
94 wp<V1_1::IBroadcastRadio> mHalModule11;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -070095 sp<V1_0::ITuner> mHalTuner;
96 sp<V1_1::ITuner> mHalTuner11;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +000097 sp<V1_2::ITuner> mHalTuner12;
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -070098 sp<HalDeathRecipient> mHalDeathRecipient;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -070099
100private:
101 DISALLOW_COPY_AND_ASSIGN(TunerContext);
102};
103
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700104static TunerContext& getNativeContext(jlong nativeContextHandle) {
105 auto nativeContext = reinterpret_cast<TunerContext*>(nativeContextHandle);
106 LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
107 return *nativeContext;
108}
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700109
110/**
111 * Always lock gContextMutex when using native context.
112 */
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700113static TunerContext& getNativeContext(JNIEnv *env, JavaRef<jobject> const &jTuner) {
114 return getNativeContext(env->GetLongField(jTuner.get(), gjni.Tuner.nativeContext));
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700115}
116
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700117static jlong nativeInit(JNIEnv *env, jobject obj, jint halRev, bool withAudio, jint band) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700118 ALOGV("%s", __func__);
119 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700120
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700121 auto ctx = new TunerContext();
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700122 ctx->mHalRev = static_cast<HalRevision>(halRev);
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700123 ctx->mWithAudio = withAudio;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700124 ctx->mBand = static_cast<Band>(band);
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700125
126 static_assert(sizeof(jlong) >= sizeof(ctx), "jlong is smaller than a pointer");
127 return reinterpret_cast<jlong>(ctx);
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700128}
129
130static void nativeFinalize(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700131 ALOGV("%s", __func__);
132 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700133
134 auto ctx = reinterpret_cast<TunerContext*>(nativeContext);
135 delete ctx;
136}
137
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -0700138void HalDeathRecipient::serviceDied(uint64_t cookie __unused,
139 const wp<hidl::base::V1_0::IBase>& who __unused) {
140 ALOGW("HAL Tuner died unexpectedly");
141
142 auto tunerCallback = mTunerCallback.promote();
143 if (tunerCallback == nullptr) return;
144
145 tunerCallback->hardwareFailure();
146}
147
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700148// TODO(b/62713378): implement support for multiple tuners open at the same time
149static void notifyAudioService(TunerContext& ctx, bool connected) {
150 if (!ctx.mWithAudio) return;
Tomasz Wasilczykb1a6fea2017-09-12 10:21:16 -0700151 if (ctx.mIsAudioConnected == connected) return;
152 ctx.mIsAudioConnected = connected;
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700153
154 ALOGD("Notifying AudioService about new state: %d", connected);
155 auto token = IPCThreadState::self()->clearCallingIdentity();
156 AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
157 connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
158 nullptr, kAudioDeviceName);
159 IPCThreadState::self()->restoreCallingIdentity(token);
160}
161
Tomasz Wasilczyk4482b142017-07-17 13:57:12 -0700162void assignHalInterfaces(JNIEnv *env, JavaRef<jobject> const &jTuner,
163 sp<V1_0::IBroadcastRadio> halModule, sp<V1_0::ITuner> halTuner) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700164 ALOGV("%s(%p)", __func__, halTuner.get());
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700165 ALOGE_IF(halTuner == nullptr, "HAL tuner is a nullptr");
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700166 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700167 auto& ctx = getNativeContext(env, jTuner);
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700168
Tomasz Wasilczyke8f4b342017-06-19 10:48:16 -0700169 if (ctx.mIsClosed) {
Tomasz Wasilczyk14752372017-06-21 11:58:21 -0700170 ALOGD("Tuner was closed during initialization");
Tomasz Wasilczyke8f4b342017-06-19 10:48:16 -0700171 // dropping the last reference will close HAL tuner
172 return;
173 }
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -0700174 if (ctx.mHalTuner != nullptr) {
175 ALOGE("HAL tuner is already set.");
176 return;
177 }
Tomasz Wasilczyke8f4b342017-06-19 10:48:16 -0700178
Tomasz Wasilczyk4482b142017-07-17 13:57:12 -0700179 ctx.mHalModule = halModule;
180 ctx.mHalModule11 = V1_1::IBroadcastRadio::castFrom(halModule).withDefault(nullptr);
181
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700182 ctx.mHalTuner = halTuner;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700183 ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000184 ctx.mHalTuner12 = V1_2::ITuner::castFrom(halTuner).withDefault(nullptr);
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700185 ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr,
186 "Provided tuner does not implement 1.1 HAL");
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000187 ALOGW_IF(ctx.mHalRev >= HalRevision::V1_2 && ctx.mHalTuner12 == nullptr,
188 "Provided tuner does not implement 1.2 HAL");
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700189
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -0700190 ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner));
191 halTuner->linkToDeath(ctx.mHalDeathRecipient, 0);
192
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700193 notifyAudioService(ctx, true);
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700194}
195
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700196static sp<V1_0::ITuner> getHalTuner(const TunerContext& ctx) {
197 auto tuner = ctx.mHalTuner;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700198 LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner is not open");
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700199 return tuner;
200}
201
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000202static sp<V1_0::ITuner> getHalTuner(jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700203 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700204 return getHalTuner(getNativeContext(nativeContext));
205}
206
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000207static sp<V1_1::ITuner> getHalTuner11(jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700208 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700209 return getNativeContext(nativeContext).mHalTuner11;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700210}
211
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000212static sp<V1_2::ITuner> getHalTuner12(jlong nativeContext) {
213 lock_guard<mutex> lk(gContextMutex);
214 return getNativeContext(nativeContext).mHalTuner12;
215}
216
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700217sp<ITunerCallback> getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner) {
218 return TunerCallback::getNativeCallback(env,
219 env->GetObjectField(tuner.get(), gjni.Tuner.tunerCallback));
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700220}
221
Tomasz Wasilczyk31c8df02017-04-26 14:47:08 -0700222Region getRegion(JNIEnv *env, jobject obj) {
223 return static_cast<Region>(env->GetIntField(obj, gjni.Tuner.region));
224}
225
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700226static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700227 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700228 auto& ctx = getNativeContext(nativeContext);
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700229
Tomasz Wasilczyke8f4b342017-06-19 10:48:16 -0700230 if (ctx.mIsClosed) return;
231 ctx.mIsClosed = true;
232
233 if (ctx.mHalTuner == nullptr) {
234 ALOGI("Tuner closed during initialization");
235 return;
236 }
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700237
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700238 ALOGI("Closing tuner %p", ctx.mHalTuner.get());
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -0700239
Tomasz Wasilczykb0b98fe2017-06-16 14:07:33 -0700240 notifyAudioService(ctx, false);
Tomasz Wasilczyk2e5a23c2017-06-19 14:47:03 -0700241
242 ctx.mHalTuner->unlinkToDeath(ctx.mHalDeathRecipient);
243 ctx.mHalDeathRecipient = nullptr;
244
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700245 ctx.mHalTuner11 = nullptr;
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000246 ctx.mHalTuner12 = nullptr;
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700247 ctx.mHalTuner = nullptr;
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700248}
249
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700250static void nativeSetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext, jobject config) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700251 ALOGV("%s", __func__);
252 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700253 auto& ctx = getNativeContext(nativeContext);
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700254
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700255 auto halTuner = getHalTuner(ctx);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700256 if (halTuner == nullptr) return;
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700257
258 Region region_unused;
259 BandConfig bandConfigHal = convert::BandConfigToHal(env, config, region_unused);
260
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700261 if (convert::ThrowIfFailed(env, halTuner->setConfiguration(bandConfigHal))) return;
262
263 ctx.mBand = bandConfigHal.type;
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700264}
265
266static jobject nativeGetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext,
267 Region region) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700268 ALOGV("%s", __func__);
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700269 auto halTuner = getHalTuner(nativeContext);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700270 if (halTuner == nullptr) return nullptr;
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700271
272 BandConfig halConfig;
273 Result halResult;
274 auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
275 halResult = result;
276 halConfig = config;
277 });
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700278 if (convert::ThrowIfFailed(env, hidlResult, halResult)) {
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700279 return nullptr;
280 }
281
282 return convert::BandConfigFromHal(env, halConfig, region).release();
283}
284
Tomasz Wasilczykb1a6fea2017-09-12 10:21:16 -0700285static void nativeSetMuted(JNIEnv *env, jobject obj, jlong nativeContext, bool mute) {
286 ALOGV("%s(%d)", __func__, mute);
287 lock_guard<mutex> lk(gContextMutex);
288 auto& ctx = getNativeContext(nativeContext);
289
290 notifyAudioService(ctx, !mute);
291}
292
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700293static void nativeStep(JNIEnv *env, jobject obj, jlong nativeContext,
294 bool directionDown, bool skipSubChannel) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700295 ALOGV("%s", __func__);
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700296 auto halTuner = getHalTuner(nativeContext);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700297 if (halTuner == nullptr) return;
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700298
299 auto dir = convert::DirectionToHal(directionDown);
300 convert::ThrowIfFailed(env, halTuner->step(dir, skipSubChannel));
301}
302
303static void nativeScan(JNIEnv *env, jobject obj, jlong nativeContext,
304 bool directionDown, bool skipSubChannel) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700305 ALOGV("%s", __func__);
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700306 auto halTuner = getHalTuner(nativeContext);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700307 if (halTuner == nullptr) return;
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700308
309 auto dir = convert::DirectionToHal(directionDown);
310 convert::ThrowIfFailed(env, halTuner->scan(dir, skipSubChannel));
311}
312
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700313static void nativeTune(JNIEnv *env, jobject obj, jlong nativeContext, jobject jSelector) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700314 ALOGV("%s", __func__);
315 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700316 auto& ctx = getNativeContext(nativeContext);
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700317
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700318 auto halTuner10 = getHalTuner(ctx);
319 auto halTuner11 = ctx.mHalTuner11;
320 if (halTuner10 == nullptr) return;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700321
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700322 auto selector = convert::ProgramSelectorToHal(env, jSelector);
323 if (halTuner11 != nullptr) {
Tomasz Wasilczyk83162912017-08-01 10:52:58 -0700324 convert::ThrowIfFailed(env, halTuner11->tuneByProgramSelector(selector));
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700325 } else {
326 uint32_t channel, subChannel;
Tomasz Wasilczyk20eef7d2017-09-14 09:42:54 -0700327 if (!utils::getLegacyChannel(selector, &channel, &subChannel)) {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700328 jniThrowException(env, "java/lang/IllegalArgumentException",
329 "Can't tune to non-AM/FM channel with HAL<1.1");
330 return;
331 }
332 convert::ThrowIfFailed(env, halTuner10->tune(channel, subChannel));
333 }
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700334}
335
336static void nativeCancel(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700337 ALOGV("%s", __func__);
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700338 auto halTuner = getHalTuner(nativeContext);
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700339 if (halTuner == nullptr) return;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700340
341 convert::ThrowIfFailed(env, halTuner->cancel());
342}
343
Tomasz Wasilczykc4cd8232017-07-14 10:46:15 -0700344static void nativeCancelAnnouncement(JNIEnv *env, jobject obj, jlong nativeContext) {
345 ALOGV("%s", __func__);
346 auto halTuner = getHalTuner11(nativeContext);
347 if (halTuner == nullptr) {
348 ALOGI("cancelling announcements is not supported with HAL < 1.1");
349 return;
350 }
351
352 convert::ThrowIfFailed(env, halTuner->cancelAnnouncement());
353}
354
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700355static jobject nativeGetProgramInformation(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700356 ALOGV("%s", __func__);
357 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700358 auto& ctx = getNativeContext(nativeContext);
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700359
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700360 auto halTuner10 = getHalTuner(ctx);
361 auto halTuner11 = ctx.mHalTuner11;
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700362 if (halTuner10 == nullptr) return nullptr;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700363
Tomasz Wasilczykbad4cd22017-05-15 13:40:56 -0700364 JavaRef<jobject> jInfo;
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700365 Result halResult;
366 Return<void> hidlResult;
367 if (halTuner11 != nullptr) {
368 hidlResult = halTuner11->getProgramInformation_1_1([&](Result result,
369 const V1_1::ProgramInfo& info) {
370 halResult = result;
Tomasz Wasilczykbad4cd22017-05-15 13:40:56 -0700371 if (result != Result::OK) return;
372 jInfo = convert::ProgramInfoFromHal(env, info);
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700373 });
374 } else {
375 hidlResult = halTuner10->getProgramInformation([&](Result result,
376 const V1_0::ProgramInfo& info) {
377 halResult = result;
Tomasz Wasilczykbad4cd22017-05-15 13:40:56 -0700378 if (result != Result::OK) return;
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700379 jInfo = convert::ProgramInfoFromHal(env, info, ctx.mBand);
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700380 });
381 }
382
Tomasz Wasilczykbad4cd22017-05-15 13:40:56 -0700383 if (jInfo != nullptr) return jInfo.release();
384 convert::ThrowIfFailed(env, hidlResult, halResult);
385 return nullptr;
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700386}
387
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700388static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700389 ALOGV("%s", __func__);
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700390 auto halTuner = getHalTuner11(nativeContext);
391 if (halTuner == nullptr) {
392 ALOGI("Background scan is not supported with HAL < 1.1");
393 return false;
394 }
395
396 auto halResult = halTuner->startBackgroundScan();
397
398 if (halResult.isOk() && halResult == ProgramListResult::UNAVAILABLE) return false;
399 return !convert::ThrowIfFailed(env, halResult);
400}
401
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700402static jobject nativeGetProgramList(JNIEnv *env, jobject obj, jlong nativeContext, jobject jVendorFilter) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700403 ALOGV("%s", __func__);
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700404 auto halTuner = getHalTuner11(nativeContext);
405 if (halTuner == nullptr) {
406 ALOGI("Program list is not supported with HAL < 1.1");
407 return nullptr;
408 }
409
410 JavaRef<jobject> jList;
411 ProgramListResult halResult = ProgramListResult::NOT_INITIALIZED;
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700412 auto filter = convert::VendorInfoToHal(env, jVendorFilter);
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700413 auto hidlResult = halTuner->getProgramList(filter,
414 [&](ProgramListResult result, const hidl_vec<V1_1::ProgramInfo>& programList) {
415 halResult = result;
416 if (halResult != ProgramListResult::OK) return;
417
Tomasz Wasilczykcc0b4792017-06-16 10:29:27 -0700418 jList = make_javaref(env, env->NewObject(gjni.ArrayList.clazz, gjni.ArrayList.cstor));
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700419 for (auto& program : programList) {
420 auto jProgram = convert::ProgramInfoFromHal(env, program);
421 env->CallBooleanMethod(jList.get(), gjni.ArrayList.add, jProgram.get());
422 }
423 });
424
425 if (convert::ThrowIfFailed(env, hidlResult, halResult)) return nullptr;
426
427 return jList.release();
428}
429
Tomasz Wasilczyk4482b142017-07-17 13:57:12 -0700430static jbyteArray nativeGetImage(JNIEnv *env, jobject obj, jlong nativeContext, jint id) {
431 ALOGV("%s(%x)", __func__, id);
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700432 lock_guard<mutex> lk(gContextMutex);
Tomasz Wasilczyk4482b142017-07-17 13:57:12 -0700433 auto& ctx = getNativeContext(nativeContext);
434
435 if (ctx.mHalModule11 == nullptr) {
436 jniThrowException(env, "java/lang/IllegalStateException",
437 "Out-of-band images are not supported with HAL < 1.1");
438 return nullptr;
439 }
440
441 auto halModule = ctx.mHalModule11.promote();
442 if (halModule == nullptr) {
443 ALOGE("HAL module is gone");
444 return nullptr;
445 }
446
447 JavaRef<jbyteArray> jRawImage = nullptr;
448
449 auto hidlResult = halModule->getImage(id, [&](hidl_vec<uint8_t> rawImage) {
450 auto len = rawImage.size();
451 if (len == 0) return;
452
453 jRawImage = make_javaref(env, env->NewByteArray(len));
454 if (jRawImage == nullptr) {
455 ALOGE("Failed to allocate byte array of len %zu", len);
456 return;
457 }
458
459 env->SetByteArrayRegion(jRawImage.get(), 0, len,
460 reinterpret_cast<const jbyte*>(rawImage.data()));
461 });
462
463 if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
464
465 return jRawImage.get();
466}
467
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700468static bool nativeIsAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700469 ALOGV("%s", __func__);
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700470 auto halTuner = getHalTuner11(nativeContext);
471 if (halTuner == nullptr) {
472 jniThrowException(env, "java/lang/IllegalStateException",
473 "Forced analog switch is not supported with HAL < 1.1");
474 return false;
475 }
476
477 bool isForced;
478 Result halResult;
479 auto hidlResult = halTuner->isAnalogForced([&](Result result, bool isForcedRet) {
480 halResult = result;
481 isForced = isForcedRet;
482 });
483
484 if (convert::ThrowIfFailed(env, hidlResult, halResult)) return false;
485
486 return isForced;
487}
488
489static void nativeSetAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext, bool isForced) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700490 ALOGV("%s(%d)", __func__, isForced);
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700491 auto halTuner = getHalTuner11(nativeContext);
492 if (halTuner == nullptr) {
493 jniThrowException(env, "java/lang/IllegalStateException",
494 "Forced analog switch is not supported with HAL < 1.1");
495 return;
496 }
497
498 auto halResult = halTuner->setAnalogForced(isForced);
499 convert::ThrowIfFailed(env, halResult);
500}
501
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000502static jobject nativeSetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jParameters) {
503 ALOGV("%s", __func__);
504
505 auto halTuner = getHalTuner12(nativeContext);
506 if (halTuner == nullptr) {
507 ALOGI("Parameters are not supported with HAL < 1.2");
508 return nullptr;
509 }
510
511 JavaRef<jobject> jResults = nullptr;
512 auto parameters = convert::VendorInfoToHal(env, jParameters);
513 auto hidlResult = halTuner->setParameters(parameters,
514 [&](const hidl_vec<VendorKeyValue> results) {
515 jResults = convert::VendorInfoFromHal(env, results);
516 });
517
518 if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
519
520 return jResults.release();
521}
522
523static jobject nativeGetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jKeys) {
524 ALOGV("%s", __func__);
525
526 auto halTuner = getHalTuner12(nativeContext);
527 if (halTuner == nullptr) {
528 ALOGI("Parameters are not supported with HAL < 1.2");
529 return nullptr;
530 }
531
532 JavaRef<jobject> jResults = nullptr;
533 auto keys = convert::StringListToHal(env, jKeys);
534 auto hidlResult = halTuner->getParameters(keys,
535 [&](const hidl_vec<VendorKeyValue> parameters) {
536 jResults = convert::VendorInfoFromHal(env, parameters);
537 });
538
539 if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
540
541 return jResults.release();
542}
543
Tomasz Wasilczyk39ac2142017-05-17 14:55:17 -0700544static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) {
Tomasz Wasilczyke3e8f902017-07-26 09:11:05 -0700545 ALOGV("%s", __func__);
Tomasz Wasilczyk39ac2142017-05-17 14:55:17 -0700546 auto halTuner = getHalTuner(nativeContext);
547 if (halTuner == nullptr) return false;
548
549 bool isConnected = false;
550 Result halResult;
551 auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
552 halResult = result;
553 isConnected = config.antennaConnected;
554 });
555 convert::ThrowIfFailed(env, hidlResult, halResult);
556 return isConnected;
557}
558
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700559static const JNINativeMethod gTunerMethods[] = {
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700560 { "nativeInit", "(IZI)J", (void*)nativeInit },
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700561 { "nativeFinalize", "(J)V", (void*)nativeFinalize },
Tomasz Wasilczyk8b6db4f2017-05-01 09:28:36 -0700562 { "nativeClose", "(J)V", (void*)nativeClose },
563 { "nativeSetConfiguration", "(JLandroid/hardware/radio/RadioManager$BandConfig;)V",
564 (void*)nativeSetConfiguration },
565 { "nativeGetConfiguration", "(JI)Landroid/hardware/radio/RadioManager$BandConfig;",
566 (void*)nativeGetConfiguration },
Tomasz Wasilczykb1a6fea2017-09-12 10:21:16 -0700567 { "nativeSetMuted", "(JZ)V", (void*)nativeSetMuted },
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700568 { "nativeStep", "(JZZ)V", (void*)nativeStep },
569 { "nativeScan", "(JZZ)V", (void*)nativeScan },
Tomasz Wasilczyk8cfb0e82017-07-12 13:59:20 -0700570 { "nativeTune", "(JLandroid/hardware/radio/ProgramSelector;)V", (void*)nativeTune },
Tomasz Wasilczyk23837932017-05-05 08:42:10 -0700571 { "nativeCancel", "(J)V", (void*)nativeCancel },
Tomasz Wasilczykc4cd8232017-07-14 10:46:15 -0700572 { "nativeCancelAnnouncement", "(J)V", (void*)nativeCancelAnnouncement },
Tomasz Wasilczyk37d986d2017-05-08 10:41:32 -0700573 { "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;",
574 (void*)nativeGetProgramInformation },
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700575 { "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan },
Tomasz Wasilczyk0f1776d2017-08-03 11:03:49 -0700576 { "nativeGetProgramList", "(JLjava/util/Map;)Ljava/util/List;",
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700577 (void*)nativeGetProgramList },
Tomasz Wasilczyk4482b142017-07-17 13:57:12 -0700578 { "nativeGetImage", "(JI)[B", (void*)nativeGetImage},
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700579 { "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },
580 { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
Tomasz Wasilczyk8e932c62017-11-17 16:18:40 +0000581 { "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters },
582 { "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters },
Tomasz Wasilczyk39ac2142017-05-17 14:55:17 -0700583 { "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected },
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700584};
585
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700586} // namespace Tuner
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -0700587} // namespace BroadcastRadio
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700588} // namespace server
589
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -0700590void register_android_server_broadcastradio_Tuner(JavaVM *vm, JNIEnv *env) {
591 using namespace server::BroadcastRadio::Tuner;
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700592
Tomasz Wasilczyk6b4b6462017-07-19 10:52:28 -0700593 register_android_server_broadcastradio_TunerCallback(vm, env);
Tomasz Wasilczyk31c8df02017-04-26 14:47:08 -0700594
Tomasz Wasilczykdf013262017-12-13 11:47:20 -0800595 auto tunerClass = FindClassOrDie(env, "com/android/server/broadcastradio/hal1/Tuner");
Tomasz Wasilczyk31c8df02017-04-26 14:47:08 -0700596 gjni.Tuner.nativeContext = GetFieldIDOrDie(env, tunerClass, "mNativeContext", "J");
597 gjni.Tuner.region = GetFieldIDOrDie(env, tunerClass, "mRegion", "I");
Tomasz Wasilczykf13b8412017-05-09 11:54:35 -0700598 gjni.Tuner.tunerCallback = GetFieldIDOrDie(env, tunerClass, "mTunerCallback",
Tomasz Wasilczykdf013262017-12-13 11:47:20 -0800599 "Lcom/android/server/broadcastradio/hal1/TunerCallback;");
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700600
Tomasz Wasilczykd3d53f62017-05-15 12:55:28 -0700601 auto arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
602 gjni.ArrayList.clazz = MakeGlobalRefOrDie(env, arrayListClass);
603 gjni.ArrayList.cstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
604 gjni.ArrayList.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
605
Tomasz Wasilczykdf013262017-12-13 11:47:20 -0800606 auto res = jniRegisterNativeMethods(env, "com/android/server/broadcastradio/hal1/Tuner",
Tomasz Wasilczykd7c21d32017-04-17 17:02:06 -0700607 gTunerMethods, NELEM(gTunerMethods));
608 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
609}
610
Tomasz Wasilczyk21348172017-04-20 14:02:42 -0700611} // namespace android