1 /*
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
20 #include <media/audiohal/hidl/HalDeathHandler.h>
21 #include <utils/Log.h>
22 #include <utils/misc.h>
23 #include <system/RadioMetadataWrapper.h>
24 #include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
25
26 #include "RadioHalHidl.h"
27 #include "HidlUtils.h"
28
29 namespace android {
30
31 using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
32 using android::hardware::broadcastradio::V1_0::Class;
33 using android::hardware::broadcastradio::V1_0::Direction;
34 using android::hardware::broadcastradio::V1_0::Properties;
35
36
37 /* static */
connectModule(radio_class_t classId)38 sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
39 {
40 return new RadioHalHidl(classId);
41 }
42
getProperties(radio_hal_properties_t * properties)43 int 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;
51 Result halResult = Result::NOT_INITIALIZED;
52 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
60 if (halResult == Result::OK) {
61 HidlUtils::convertPropertiesFromHal(properties, &halProperties);
62 }
63 return HidlUtils::convertHalResult(halResult);
64 }
65
openTuner(const radio_hal_band_config_t * config,bool audio,sp<TunerCallbackInterface> callback,sp<TunerInterface> & tuner)66 int 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;
78 Result halResult = Result::NOT_INITIALIZED;
79 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
91 if (halResult == Result::OK) {
92 tunerImpl->setHalTuner(halTuner);
93 tuner = tunerImpl;
94 }
95
96 return HidlUtils::convertHalResult(halResult);
97 }
98
closeTuner(sp<TunerInterface> & tuner)99 int 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
RadioHalHidl(radio_class_t classId)107 RadioHalHidl::RadioHalHidl(radio_class_t classId)
108 : mClassId(classId)
109 {
110 }
111
~RadioHalHidl()112 RadioHalHidl::~RadioHalHidl()
113 {
114 }
115
getService()116 sp<IBroadcastRadio> RadioHalHidl::getService()
117 {
118 if (mHalModule == 0) {
119 sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService();
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
clearService()133 void RadioHalHidl::clearService()
134 {
135 ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get());
136 mHalModule.clear();
137 }
138
139
setConfiguration(const radio_hal_band_config_t * config)140 int 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);
151 return HidlUtils::convertHalResult(hidlResult);
152 }
153
getConfiguration(radio_hal_band_config_t * config)154 int 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 });
169 if (hidlReturn.isOk() && halResult == Result::OK) {
170 HidlUtils::convertBandConfigFromHal(config, &halConfig);
171 }
172 return HidlUtils::convertHalResult(halResult);
173 }
174
scan(radio_direction_t direction,bool skip_sub_channel)175 int 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);
183 return HidlUtils::convertHalResult(hidlResult);
184 }
185
step(radio_direction_t direction,bool skip_sub_channel)186 int 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);
194 return HidlUtils::convertHalResult(hidlResult);
195 }
196
tune(unsigned int channel,unsigned int sub_channel)197 int 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);
205 return HidlUtils::convertHalResult(hidlResult);
206 }
207
cancel()208 int 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();
215 return HidlUtils::convertHalResult(hidlResult);
216 }
217
getProgramInformation(radio_program_info_t * info)218 int 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 }
224 if (info == nullptr || info->metadata == nullptr) {
225 return BAD_VALUE;
226 }
227 ProgramInfo halInfo;
228 Result halResult;
229 Return<void> hidlReturn = mHalTuner->getProgramInformation(
230 [&](Result result, const ProgramInfo& info) {
231 halResult = result;
232 if (result == Result::OK) {
233 halInfo = info;
234 }
235 });
236 if (hidlReturn.isOk() && halResult == Result::OK) {
237 HidlUtils::convertProgramInfoFromHal(info, &halInfo);
238 }
239 return HidlUtils::convertHalResult(halResult);
240 }
241
hardwareFailure()242 Return<void> RadioHalHidl::Tuner::hardwareFailure()
243 {
244 ALOGV("%s IN", __FUNCTION__);
245 handleHwFailure();
246 return Return<void>();
247 }
248
configChange(Result result,const BandConfig & config)249 Return<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
tuneComplete(Result result,const ProgramInfo & info)261 Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
262 {
263 ALOGV("%s IN", __FUNCTION__);
264 radio_hal_event_t event = {};
265 RadioMetadataWrapper metadataWrapper(&event.info.metadata);
266
267 event.type = RADIO_EVENT_TUNED;
268 event.status = HidlUtils::convertHalResult(result);
269 HidlUtils::convertProgramInfoFromHal(&event.info, &info);
270 onCallback(&event);
271 return Return<void>();
272 }
273
afSwitch(const ProgramInfo & info)274 Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
275 {
276 ALOGV("%s IN", __FUNCTION__);
277 radio_hal_event_t event = {};
278 RadioMetadataWrapper metadataWrapper(&event.info.metadata);
279
280 event.type = RADIO_EVENT_AF_SWITCH;
281 HidlUtils::convertProgramInfoFromHal(&event.info, &info);
282 onCallback(&event);
283 return Return<void>();
284 }
285
antennaStateChange(bool connected)286 Return<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 }
trafficAnnouncement(bool active)296 Return<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 }
emergencyAnnouncement(bool active)306 Return<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 }
newMetadata(uint32_t channel,uint32_t subChannel,const::android::hardware::hidl_vec<MetaData> & metadata)316 Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
317 const ::android::hardware::hidl_vec<MetaData>& metadata)
318 {
319 ALOGV("%s IN", __FUNCTION__);
320 radio_hal_event_t event = {};
321 RadioMetadataWrapper metadataWrapper(&event.metadata);
322
323 event.type = RADIO_EVENT_METADATA;
324 HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
325 onCallback(&event);
326 return Return<void>();
327 }
328
329
Tuner(sp<TunerCallbackInterface> callback,sp<RadioHalHidl> module)330 RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
331 : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
332 {
333 // 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(); });
338 }
339
340
~Tuner()341 RadioHalHidl::Tuner::~Tuner()
342 {
343 HalDeathHandler::getInstance()->unregisterAtExitHandler(this);
344 }
345
setHalTuner(sp<ITuner> & halTuner)346 void 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 }
354 }
355
handleHwFailure()356 void RadioHalHidl::Tuner::handleHwFailure()
357 {
358 ALOGV("%s IN", __FUNCTION__);
359 sp<RadioHalHidl> parentModule = mParentModule.promote();
360 if (parentModule != 0) {
361 parentModule->clearService();
362 }
363 sendHwFailureEvent();
364 mHalTuner.clear();
365 }
366
sendHwFailureEvent() const367 void RadioHalHidl::Tuner::sendHwFailureEvent() const
368 {
369 radio_hal_event_t event;
370 memset(&event, 0, sizeof(radio_hal_event_t));
371 event.type = RADIO_EVENT_HW_FAILURE;
372 onCallback(&event);
373 }
374
onCallback(radio_hal_event_t * halEvent) const375 void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent) const
376 {
377 if (mCallback != 0) {
378 mCallback->onEvent(halEvent);
379 }
380 }
381
382 } // namespace android
383