blob: 3dcf2f3997bcfbd6ef782385dd7282c1470b2233 [file] [log] [blame]
Eric Laurent73e17f22016-11-21 10:40:36 -08001/*
2 * Copyright (C) 2016 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 "RadioHalHidl"
18//#define LOG_NDEBUG 0
19
Mikhail Naganovd621ac82017-01-12 17:17:45 -080020#include <media/audiohal/hidl/HalDeathHandler.h>
Eric Laurent73e17f22016-11-21 10:40:36 -080021#include <utils/Log.h>
22#include <utils/misc.h>
Tomasz Wasilczyka0ea70c2017-02-15 16:56:10 -080023#include <system/RadioMetadataWrapper.h>
Eric Laurent73e17f22016-11-21 10:40:36 -080024#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
25
26#include "RadioHalHidl.h"
27#include "HidlUtils.h"
28
29namespace android {
30
31using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
32using android::hardware::broadcastradio::V1_0::Class;
33using android::hardware::broadcastradio::V1_0::Direction;
34using android::hardware::broadcastradio::V1_0::Properties;
35
36
37/* static */
38sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
39{
40 return new RadioHalHidl(classId);
41}
42
43int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
44{
45 ALOGV("%s IN", __FUNCTION__);
46 sp<IBroadcastRadio> module = getService();
47 if (module == 0) {
48 return -ENODEV;
49 }
50 Properties halProperties;
Steven Morelande83be8a2017-01-06 11:06:33 -080051 Result halResult = Result::NOT_INITIALIZED;
Eric Laurent73e17f22016-11-21 10:40:36 -080052 Return<void> hidlReturn =
53 module->getProperties([&](Result result, const Properties& properties) {
54 halResult = result;
55 if (result == Result::OK) {
56 halProperties = properties;
57 }
58 });
59
Eric Laurent73e17f22016-11-21 10:40:36 -080060 if (halResult == Result::OK) {
61 HidlUtils::convertPropertiesFromHal(properties, &halProperties);
62 }
63 return HidlUtils::convertHalResult(halResult);
64}
65
66int RadioHalHidl::openTuner(const radio_hal_band_config_t *config,
67 bool audio,
68 sp<TunerCallbackInterface> callback,
69 sp<TunerInterface>& tuner)
70{
71 sp<IBroadcastRadio> module = getService();
72 if (module == 0) {
73 return -ENODEV;
74 }
75 sp<Tuner> tunerImpl = new Tuner(callback, this);
76
77 BandConfig halConfig;
Steven Morelande83be8a2017-01-06 11:06:33 -080078 Result halResult = Result::NOT_INITIALIZED;
Eric Laurent73e17f22016-11-21 10:40:36 -080079 sp<ITuner> halTuner;
80
81 HidlUtils::convertBandConfigToHal(&halConfig, config);
82 Return<void> hidlReturn =
83 module->openTuner(halConfig, audio, tunerImpl,
84 [&](Result result, const sp<ITuner>& tuner) {
85 halResult = result;
86 if (result == Result::OK) {
87 halTuner = tuner;
88 }
89 });
90
Eric Laurent73e17f22016-11-21 10:40:36 -080091 if (halResult == Result::OK) {
92 tunerImpl->setHalTuner(halTuner);
93 tuner = tunerImpl;
94 }
95
96 return HidlUtils::convertHalResult(halResult);
97}
98
99int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner)
100{
101 sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get());
102 sp<ITuner> clearTuner;
103 tunerImpl->setHalTuner(clearTuner);
104 return 0;
105}
106
107RadioHalHidl::RadioHalHidl(radio_class_t classId)
108 : mClassId(classId)
109{
110}
111
112RadioHalHidl::~RadioHalHidl()
113{
114}
115
116sp<IBroadcastRadio> RadioHalHidl::getService()
117{
118 if (mHalModule == 0) {
119 sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
120 if (factory != 0) {
121 factory->connectModule(static_cast<Class>(mClassId),
122 [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
123 if (retval == Result::OK) {
124 mHalModule = result;
125 }
126 });
127 }
128 }
129 ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get());
130 return mHalModule;
131}
132
133void RadioHalHidl::clearService()
134{
135 ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get());
136 mHalModule.clear();
137}
138
139
140int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config)
141{
142 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
143
144 if (mHalTuner == 0) {
145 return -ENODEV;
146 }
147 BandConfig halConfig;
148 HidlUtils::convertBandConfigToHal(&halConfig, config);
149
150 Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
Eric Laurent73e17f22016-11-21 10:40:36 -0800151 return HidlUtils::convertHalResult(hidlResult);
152}
153
154int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config)
155{
156 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
157 if (mHalTuner == 0) {
158 return -ENODEV;
159 }
160 BandConfig halConfig;
161 Result halResult;
162 Return<void> hidlReturn =
163 mHalTuner->getConfiguration([&](Result result, const BandConfig& config) {
164 halResult = result;
165 if (result == Result::OK) {
166 halConfig = config;
167 }
168 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800169 if (hidlReturn.isOk() && halResult == Result::OK) {
Eric Laurent73e17f22016-11-21 10:40:36 -0800170 HidlUtils::convertBandConfigFromHal(config, &halConfig);
171 }
172 return HidlUtils::convertHalResult(halResult);
173}
174
175int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
176{
177 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
178 if (mHalTuner == 0) {
179 return -ENODEV;
180 }
181 Return<Result> hidlResult =
182 mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
Eric Laurent73e17f22016-11-21 10:40:36 -0800183 return HidlUtils::convertHalResult(hidlResult);
184}
185
186int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
187{
188 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
189 if (mHalTuner == 0) {
190 return -ENODEV;
191 }
192 Return<Result> hidlResult =
193 mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
Eric Laurent73e17f22016-11-21 10:40:36 -0800194 return HidlUtils::convertHalResult(hidlResult);
195}
196
197int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel)
198{
199 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
200 if (mHalTuner == 0) {
201 return -ENODEV;
202 }
203 Return<Result> hidlResult =
204 mHalTuner->tune(channel, sub_channel);
Eric Laurent73e17f22016-11-21 10:40:36 -0800205 return HidlUtils::convertHalResult(hidlResult);
206}
207
208int RadioHalHidl::Tuner::cancel()
209{
210 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
211 if (mHalTuner == 0) {
212 return -ENODEV;
213 }
214 Return<Result> hidlResult = mHalTuner->cancel();
Eric Laurent73e17f22016-11-21 10:40:36 -0800215 return HidlUtils::convertHalResult(hidlResult);
216}
217
218int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info)
219{
220 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
221 if (mHalTuner == 0) {
222 return -ENODEV;
223 }
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800224 if (info == nullptr || info->metadata == nullptr) {
225 return BAD_VALUE;
226 }
Eric Laurent73e17f22016-11-21 10:40:36 -0800227 ProgramInfo halInfo;
228 Result halResult;
Eric Laurent73e17f22016-11-21 10:40:36 -0800229 Return<void> hidlReturn = mHalTuner->getProgramInformation(
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800230 [&](Result result, const ProgramInfo& info) {
231 halResult = result;
232 if (result == Result::OK) {
233 halInfo = info;
234 }
235 });
Steven Morelande83be8a2017-01-06 11:06:33 -0800236 if (hidlReturn.isOk() && halResult == Result::OK) {
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800237 HidlUtils::convertProgramInfoFromHal(info, &halInfo);
Eric Laurent73e17f22016-11-21 10:40:36 -0800238 }
239 return HidlUtils::convertHalResult(halResult);
240}
241
242Return<void> RadioHalHidl::Tuner::hardwareFailure()
243{
244 ALOGV("%s IN", __FUNCTION__);
245 handleHwFailure();
246 return Return<void>();
247}
248
249Return<void> RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config)
250{
251 ALOGV("%s IN", __FUNCTION__);
252 radio_hal_event_t event;
253 memset(&event, 0, sizeof(radio_hal_event_t));
254 event.type = RADIO_EVENT_CONFIG;
255 event.status = HidlUtils::convertHalResult(result);
256 HidlUtils::convertBandConfigFromHal(&event.config, &config);
257 onCallback(&event);
258 return Return<void>();
259}
260
261Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
262{
263 ALOGV("%s IN", __FUNCTION__);
Tomasz Wasilczyka0ea70c2017-02-15 16:56:10 -0800264 radio_hal_event_t event = {};
265 RadioMetadataWrapper metadataWrapper(&event.info.metadata);
266
Eric Laurent73e17f22016-11-21 10:40:36 -0800267 event.type = RADIO_EVENT_TUNED;
268 event.status = HidlUtils::convertHalResult(result);
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800269 HidlUtils::convertProgramInfoFromHal(&event.info, &info);
Eric Laurent73e17f22016-11-21 10:40:36 -0800270 onCallback(&event);
Eric Laurent73e17f22016-11-21 10:40:36 -0800271 return Return<void>();
272}
273
274Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
275{
276 ALOGV("%s IN", __FUNCTION__);
Tomasz Wasilczyka0ea70c2017-02-15 16:56:10 -0800277 radio_hal_event_t event = {};
278 RadioMetadataWrapper metadataWrapper(&event.info.metadata);
279
Eric Laurent73e17f22016-11-21 10:40:36 -0800280 event.type = RADIO_EVENT_AF_SWITCH;
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800281 HidlUtils::convertProgramInfoFromHal(&event.info, &info);
Eric Laurent73e17f22016-11-21 10:40:36 -0800282 onCallback(&event);
Eric Laurent73e17f22016-11-21 10:40:36 -0800283 return Return<void>();
284}
285
286Return<void> RadioHalHidl::Tuner::antennaStateChange(bool connected)
287{
288 ALOGV("%s IN", __FUNCTION__);
289 radio_hal_event_t event;
290 memset(&event, 0, sizeof(radio_hal_event_t));
291 event.type = RADIO_EVENT_ANTENNA;
292 event.on = connected;
293 onCallback(&event);
294 return Return<void>();
295}
296Return<void> RadioHalHidl::Tuner::trafficAnnouncement(bool active)
297{
298 ALOGV("%s IN", __FUNCTION__);
299 radio_hal_event_t event;
300 memset(&event, 0, sizeof(radio_hal_event_t));
301 event.type = RADIO_EVENT_TA;
302 event.on = active;
303 onCallback(&event);
304 return Return<void>();
305}
306Return<void> RadioHalHidl::Tuner::emergencyAnnouncement(bool active)
307{
308 ALOGV("%s IN", __FUNCTION__);
309 radio_hal_event_t event;
310 memset(&event, 0, sizeof(radio_hal_event_t));
311 event.type = RADIO_EVENT_EA;
312 event.on = active;
313 onCallback(&event);
314 return Return<void>();
315}
316Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
317 const ::android::hardware::hidl_vec<MetaData>& metadata)
318{
319 ALOGV("%s IN", __FUNCTION__);
Tomasz Wasilczyka0ea70c2017-02-15 16:56:10 -0800320 radio_hal_event_t event = {};
321 RadioMetadataWrapper metadataWrapper(&event.info.metadata);
322
Eric Laurent73e17f22016-11-21 10:40:36 -0800323 event.type = RADIO_EVENT_METADATA;
324 HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
325 onCallback(&event);
Eric Laurent73e17f22016-11-21 10:40:36 -0800326 return Return<void>();
327}
328
329
330RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
331 : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
332{
Mikhail Naganovd621ac82017-01-12 17:17:45 -0800333 // Make sure the handler we are passing in only deals with const members,
334 // as it can be called on an arbitrary thread.
335 const auto& self = this;
336 HalDeathHandler::getInstance()->registerAtExitHandler(
337 this, [&self]() { self->sendHwFailureEvent(); });
Eric Laurent73e17f22016-11-21 10:40:36 -0800338}
339
340
341RadioHalHidl::Tuner::~Tuner()
342{
Mikhail Naganovd621ac82017-01-12 17:17:45 -0800343 HalDeathHandler::getInstance()->unregisterAtExitHandler(this);
344}
345
346void RadioHalHidl::Tuner::setHalTuner(sp<ITuner>& halTuner) {
347 if (mHalTuner != 0) {
348 mHalTuner->unlinkToDeath(HalDeathHandler::getInstance());
349 }
350 mHalTuner = halTuner;
351 if (mHalTuner != 0) {
352 mHalTuner->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
353 }
Eric Laurent73e17f22016-11-21 10:40:36 -0800354}
355
356void RadioHalHidl::Tuner::handleHwFailure()
357{
358 ALOGV("%s IN", __FUNCTION__);
359 sp<RadioHalHidl> parentModule = mParentModule.promote();
360 if (parentModule != 0) {
361 parentModule->clearService();
362 }
Mikhail Naganovd621ac82017-01-12 17:17:45 -0800363 sendHwFailureEvent();
364 mHalTuner.clear();
365}
366
367void RadioHalHidl::Tuner::sendHwFailureEvent() const
368{
Eric Laurent73e17f22016-11-21 10:40:36 -0800369 radio_hal_event_t event;
370 memset(&event, 0, sizeof(radio_hal_event_t));
371 event.type = RADIO_EVENT_HW_FAILURE;
372 onCallback(&event);
Eric Laurent73e17f22016-11-21 10:40:36 -0800373}
374
Mikhail Naganovd621ac82017-01-12 17:17:45 -0800375void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent) const
Eric Laurent73e17f22016-11-21 10:40:36 -0800376{
377 if (mCallback != 0) {
378 mCallback->onEvent(halEvent);
379 }
380}
381
382} // namespace android