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