blob: 07cb4d52bfd30370d480cedec862b7a145bb63a6 [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
20#include <utils/Log.h>
21#include <utils/misc.h>
22#include <system/radio_metadata.h>
23#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
24
25#include "RadioHalHidl.h"
26#include "HidlUtils.h"
27
28namespace android {
29
30using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
31using android::hardware::broadcastradio::V1_0::Class;
32using android::hardware::broadcastradio::V1_0::Direction;
33using android::hardware::broadcastradio::V1_0::Properties;
34
35
36/* static */
37sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
38{
39 return new RadioHalHidl(classId);
40}
41
42int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
43{
44 ALOGV("%s IN", __FUNCTION__);
45 sp<IBroadcastRadio> module = getService();
46 if (module == 0) {
47 return -ENODEV;
48 }
49 Properties halProperties;
50 Result halResult;
51 Return<void> hidlReturn =
52 module->getProperties([&](Result result, const Properties& properties) {
53 halResult = result;
54 if (result == Result::OK) {
55 halProperties = properties;
56 }
57 });
58
59 if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
60 clearService();
61 return -EPIPE;
62 }
63 if (halResult == Result::OK) {
64 HidlUtils::convertPropertiesFromHal(properties, &halProperties);
65 }
66 return HidlUtils::convertHalResult(halResult);
67}
68
69int RadioHalHidl::openTuner(const radio_hal_band_config_t *config,
70 bool audio,
71 sp<TunerCallbackInterface> callback,
72 sp<TunerInterface>& tuner)
73{
74 sp<IBroadcastRadio> module = getService();
75 if (module == 0) {
76 return -ENODEV;
77 }
78 sp<Tuner> tunerImpl = new Tuner(callback, this);
79
80 BandConfig halConfig;
81 Result halResult;
82 sp<ITuner> halTuner;
83
84 HidlUtils::convertBandConfigToHal(&halConfig, config);
85 Return<void> hidlReturn =
86 module->openTuner(halConfig, audio, tunerImpl,
87 [&](Result result, const sp<ITuner>& tuner) {
88 halResult = result;
89 if (result == Result::OK) {
90 halTuner = tuner;
91 }
92 });
93
94 if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
95 clearService();
96 return -EPIPE;
97 }
98 if (halResult == Result::OK) {
99 tunerImpl->setHalTuner(halTuner);
100 tuner = tunerImpl;
101 }
102
103 return HidlUtils::convertHalResult(halResult);
104}
105
106int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner)
107{
108 sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get());
109 sp<ITuner> clearTuner;
110 tunerImpl->setHalTuner(clearTuner);
111 return 0;
112}
113
114RadioHalHidl::RadioHalHidl(radio_class_t classId)
115 : mClassId(classId)
116{
117}
118
119RadioHalHidl::~RadioHalHidl()
120{
121}
122
123sp<IBroadcastRadio> RadioHalHidl::getService()
124{
125 if (mHalModule == 0) {
126 sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
127 if (factory != 0) {
128 factory->connectModule(static_cast<Class>(mClassId),
129 [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
130 if (retval == Result::OK) {
131 mHalModule = result;
132 }
133 });
134 }
135 }
136 ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get());
137 return mHalModule;
138}
139
140void RadioHalHidl::clearService()
141{
142 ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get());
143 mHalModule.clear();
144}
145
146
147int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config)
148{
149 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
150
151 if (mHalTuner == 0) {
152 return -ENODEV;
153 }
154 BandConfig halConfig;
155 HidlUtils::convertBandConfigToHal(&halConfig, config);
156
157 Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
158 checkHidlStatus(hidlResult.getStatus());
159 return HidlUtils::convertHalResult(hidlResult);
160}
161
162int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config)
163{
164 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
165 if (mHalTuner == 0) {
166 return -ENODEV;
167 }
168 BandConfig halConfig;
169 Result halResult;
170 Return<void> hidlReturn =
171 mHalTuner->getConfiguration([&](Result result, const BandConfig& config) {
172 halResult = result;
173 if (result == Result::OK) {
174 halConfig = config;
175 }
176 });
177 status_t status = checkHidlStatus(hidlReturn.getStatus());
178 if (status == NO_ERROR && halResult == Result::OK) {
179 HidlUtils::convertBandConfigFromHal(config, &halConfig);
180 }
181 return HidlUtils::convertHalResult(halResult);
182}
183
184int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
185{
186 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
187 if (mHalTuner == 0) {
188 return -ENODEV;
189 }
190 Return<Result> hidlResult =
191 mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
192 checkHidlStatus(hidlResult.getStatus());
193 return HidlUtils::convertHalResult(hidlResult);
194}
195
196int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
197{
198 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
199 if (mHalTuner == 0) {
200 return -ENODEV;
201 }
202 Return<Result> hidlResult =
203 mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
204 checkHidlStatus(hidlResult.getStatus());
205 return HidlUtils::convertHalResult(hidlResult);
206}
207
208int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel)
209{
210 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
211 if (mHalTuner == 0) {
212 return -ENODEV;
213 }
214 Return<Result> hidlResult =
215 mHalTuner->tune(channel, sub_channel);
216 checkHidlStatus(hidlResult.getStatus());
217 return HidlUtils::convertHalResult(hidlResult);
218}
219
220int RadioHalHidl::Tuner::cancel()
221{
222 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
223 if (mHalTuner == 0) {
224 return -ENODEV;
225 }
226 Return<Result> hidlResult = mHalTuner->cancel();
227 checkHidlStatus(hidlResult.getStatus());
228 return HidlUtils::convertHalResult(hidlResult);
229}
230
231int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info)
232{
233 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
234 if (mHalTuner == 0) {
235 return -ENODEV;
236 }
237 ProgramInfo halInfo;
238 Result halResult;
239 bool withMetaData = (info->metadata != NULL);
240 Return<void> hidlReturn = mHalTuner->getProgramInformation(
241 withMetaData, [&](Result result, const ProgramInfo& info) {
242 halResult = result;
243 if (result == Result::OK) {
244 halInfo = info;
245 }
246 });
247 status_t status = checkHidlStatus(hidlReturn.getStatus());
248 if (status == NO_ERROR && halResult == Result::OK) {
249 HidlUtils::convertProgramInfoFromHal(info, &halInfo, withMetaData);
250 }
251 return HidlUtils::convertHalResult(halResult);
252}
253
254Return<void> RadioHalHidl::Tuner::hardwareFailure()
255{
256 ALOGV("%s IN", __FUNCTION__);
257 handleHwFailure();
258 return Return<void>();
259}
260
261Return<void> RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config)
262{
263 ALOGV("%s IN", __FUNCTION__);
264 radio_hal_event_t event;
265 memset(&event, 0, sizeof(radio_hal_event_t));
266 event.type = RADIO_EVENT_CONFIG;
267 event.status = HidlUtils::convertHalResult(result);
268 HidlUtils::convertBandConfigFromHal(&event.config, &config);
269 onCallback(&event);
270 return Return<void>();
271}
272
273Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
274{
275 ALOGV("%s IN", __FUNCTION__);
276 radio_hal_event_t event;
277 memset(&event, 0, sizeof(radio_hal_event_t));
278 event.type = RADIO_EVENT_TUNED;
279 event.status = HidlUtils::convertHalResult(result);
280 HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
281 onCallback(&event);
282 if (event.info.metadata != NULL) {
283 radio_metadata_deallocate(event.info.metadata);
284 }
285 return Return<void>();
286}
287
288Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
289{
290 ALOGV("%s IN", __FUNCTION__);
291 radio_hal_event_t event;
292 memset(&event, 0, sizeof(radio_hal_event_t));
293 event.type = RADIO_EVENT_AF_SWITCH;
294 HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
295 onCallback(&event);
296 if (event.info.metadata != NULL) {
297 radio_metadata_deallocate(event.info.metadata);
298 }
299 return Return<void>();
300}
301
302Return<void> RadioHalHidl::Tuner::antennaStateChange(bool connected)
303{
304 ALOGV("%s IN", __FUNCTION__);
305 radio_hal_event_t event;
306 memset(&event, 0, sizeof(radio_hal_event_t));
307 event.type = RADIO_EVENT_ANTENNA;
308 event.on = connected;
309 onCallback(&event);
310 return Return<void>();
311}
312Return<void> RadioHalHidl::Tuner::trafficAnnouncement(bool active)
313{
314 ALOGV("%s IN", __FUNCTION__);
315 radio_hal_event_t event;
316 memset(&event, 0, sizeof(radio_hal_event_t));
317 event.type = RADIO_EVENT_TA;
318 event.on = active;
319 onCallback(&event);
320 return Return<void>();
321}
322Return<void> RadioHalHidl::Tuner::emergencyAnnouncement(bool active)
323{
324 ALOGV("%s IN", __FUNCTION__);
325 radio_hal_event_t event;
326 memset(&event, 0, sizeof(radio_hal_event_t));
327 event.type = RADIO_EVENT_EA;
328 event.on = active;
329 onCallback(&event);
330 return Return<void>();
331}
332Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
333 const ::android::hardware::hidl_vec<MetaData>& metadata)
334{
335 ALOGV("%s IN", __FUNCTION__);
336 radio_hal_event_t event;
337 memset(&event, 0, sizeof(radio_hal_event_t));
338 event.type = RADIO_EVENT_METADATA;
339 HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
340 onCallback(&event);
341 if (event.metadata != NULL) {
342 radio_metadata_deallocate(event.info.metadata);
343 }
344 return Return<void>();
345}
346
347
348RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
349 : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
350{
351}
352
353
354RadioHalHidl::Tuner::~Tuner()
355{
356}
357
358void RadioHalHidl::Tuner::handleHwFailure()
359{
360 ALOGV("%s IN", __FUNCTION__);
361 sp<RadioHalHidl> parentModule = mParentModule.promote();
362 if (parentModule != 0) {
363 parentModule->clearService();
364 }
365 radio_hal_event_t event;
366 memset(&event, 0, sizeof(radio_hal_event_t));
367 event.type = RADIO_EVENT_HW_FAILURE;
368 onCallback(&event);
369 mHalTuner.clear();
370}
371
372status_t RadioHalHidl::Tuner::checkHidlStatus(Status hidlStatus)
373{
374 status_t status = hidlStatus.transactionError();
375 if (status == DEAD_OBJECT) {
376 handleHwFailure();
377 }
378 return status;
379}
380
381void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent)
382{
383 if (mCallback != 0) {
384 mCallback->onEvent(halEvent);
385 }
386}
387
388} // namespace android