blob: 3448678b57458e7b44a94f16dd5945ea261cbdd0 [file] [log] [blame]
Eric Laurent4e090692015-03-05 15:12:40 -08001/*
2 * Copyright (C) 2015 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 "RadioService"
18//#define LOG_NDEBUG 0
19
20#include <stdio.h>
21#include <string.h>
22#include <sys/types.h>
23#include <pthread.h>
24
Eric Laurent53810822015-03-12 09:12:01 -070025#include <system/audio.h>
26#include <system/audio_policy.h>
Eric Laurent4e090692015-03-05 15:12:40 -080027#include <system/radio.h>
28#include <system/radio_metadata.h>
29#include <cutils/atomic.h>
30#include <cutils/properties.h>
31#include <hardware/hardware.h>
32#include <utils/Errors.h>
33#include <utils/Log.h>
34#include <binder/IServiceManager.h>
35#include <binder/MemoryBase.h>
36#include <binder/MemoryHeapBase.h>
37#include <hardware/radio.h>
Eric Laurent53810822015-03-12 09:12:01 -070038#include <media/AudioSystem.h>
Eric Laurent4e090692015-03-05 15:12:40 -080039#include "RadioService.h"
40#include "RadioRegions.h"
41
42namespace android {
43
Eric Laurent53810822015-03-12 09:12:01 -070044static const char kRadioTunerAudioDeviceName[] = "Radio tuner source";
Eric Laurent4e090692015-03-05 15:12:40 -080045
46RadioService::RadioService()
47 : BnRadioService(), mNextUniqueId(1)
48{
49 ALOGI("%s", __FUNCTION__);
50}
51
52void RadioService::onFirstRef()
53{
54 const hw_module_t *mod;
55 int rc;
56 struct radio_hw_device *dev;
57
58 ALOGI("%s", __FUNCTION__);
59
60 rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, RADIO_HARDWARE_MODULE_ID_FM, &mod);
61 if (rc != 0) {
62 ALOGE("couldn't load radio module %s.%s (%s)",
63 RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
64 return;
65 }
66 rc = radio_hw_device_open(mod, &dev);
67 if (rc != 0) {
68 ALOGE("couldn't open radio hw device in %s.%s (%s)",
69 RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
70 return;
71 }
72 if (dev->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
73 ALOGE("wrong radio hw device version %04x", dev->common.version);
74 return;
75 }
76
77 struct radio_hal_properties halProperties;
78 rc = dev->get_properties(dev, &halProperties);
79 if (rc != 0) {
80 ALOGE("could not read implementation properties");
81 return;
82 }
83
84 radio_properties_t properties;
85 properties.handle =
86 (radio_handle_t)android_atomic_inc(&mNextUniqueId);
Eric Laurent4e090692015-03-05 15:12:40 -080087 convertProperties(&properties, &halProperties);
Tomasz Wasilczyk164f3682017-02-08 09:18:08 -080088
89 ALOGI("loaded default module %s, ver %s, handle %d", properties.product,
90 properties.version, properties.handle);
91
Eric Laurent53810822015-03-12 09:12:01 -070092 sp<Module> module = new Module(dev, properties);
Eric Laurent4e090692015-03-05 15:12:40 -080093 mModules.add(properties.handle, module);
94}
95
96RadioService::~RadioService()
97{
98 for (size_t i = 0; i < mModules.size(); i++) {
99 radio_hw_device_close(mModules.valueAt(i)->hwDevice());
100 }
101}
102
103status_t RadioService::listModules(struct radio_properties *properties,
104 uint32_t *numModules)
105{
106 ALOGV("listModules");
107
108 AutoMutex lock(mServiceLock);
109 if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
110 return BAD_VALUE;
111 }
112 size_t maxModules = *numModules;
113 *numModules = mModules.size();
114 for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
115 properties[i] = mModules.valueAt(i)->properties();
116 }
117 return NO_ERROR;
118}
119
120status_t RadioService::attach(radio_handle_t handle,
121 const sp<IRadioClient>& client,
122 const struct radio_band_config *config,
123 bool withAudio,
124 sp<IRadio>& radio)
125{
126 ALOGV("%s %d config %p withAudio %d", __FUNCTION__, handle, config, withAudio);
127
128 AutoMutex lock(mServiceLock);
129 radio.clear();
130 if (client == 0) {
131 return BAD_VALUE;
132 }
133 ssize_t index = mModules.indexOfKey(handle);
134 if (index < 0) {
135 return BAD_VALUE;
136 }
137 sp<Module> module = mModules.valueAt(index);
138
139 if (config == NULL) {
140 config = module->getDefaultConfig();
141 if (config == NULL) {
142 return INVALID_OPERATION;
143 }
144 }
145 ALOGV("%s region %d type %d", __FUNCTION__, config->region, config->band.type);
146
147 radio = module->addClient(client, config, withAudio);
148
149 if (radio == 0) {
Eric Laurentf2f79cf2015-04-23 17:10:50 -0700150 return NO_INIT;
Eric Laurent4e090692015-03-05 15:12:40 -0800151 }
152 return NO_ERROR;
153}
154
155
156static const int kDumpLockRetries = 50;
157static const int kDumpLockSleep = 60000;
158
159static bool tryLock(Mutex& mutex)
160{
161 bool locked = false;
162 for (int i = 0; i < kDumpLockRetries; ++i) {
163 if (mutex.tryLock() == NO_ERROR) {
164 locked = true;
165 break;
166 }
167 usleep(kDumpLockSleep);
168 }
169 return locked;
170}
171
172status_t RadioService::dump(int fd, const Vector<String16>& args __unused) {
173 String8 result;
174 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
175 result.appendFormat("Permission Denial: can't dump RadioService");
176 write(fd, result.string(), result.size());
177 } else {
178 bool locked = tryLock(mServiceLock);
179 // failed to lock - RadioService is probably deadlocked
180 if (!locked) {
181 result.append("RadioService may be deadlocked\n");
182 write(fd, result.string(), result.size());
183 }
184
185 if (locked) mServiceLock.unlock();
186 }
187 return NO_ERROR;
188}
189
190status_t RadioService::onTransact(
191 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
192 return BnRadioService::onTransact(code, data, reply, flags);
193}
194
195
196// static
197void RadioService::callback(radio_hal_event_t *halEvent, void *cookie)
198{
199 CallbackThread *callbackThread = (CallbackThread *)cookie;
200 if (callbackThread == NULL) {
201 return;
202 }
203 callbackThread->sendEvent(halEvent);
204}
205
206/* static */
207void RadioService::convertProperties(radio_properties_t *properties,
208 const radio_hal_properties_t *halProperties)
209{
210 memset(properties, 0, sizeof(struct radio_properties));
211 properties->class_id = halProperties->class_id;
212 strlcpy(properties->implementor, halProperties->implementor,
213 RADIO_STRING_LEN_MAX);
214 strlcpy(properties->product, halProperties->product,
215 RADIO_STRING_LEN_MAX);
216 strlcpy(properties->version, halProperties->version,
217 RADIO_STRING_LEN_MAX);
218 strlcpy(properties->serial, halProperties->serial,
219 RADIO_STRING_LEN_MAX);
220 properties->num_tuners = halProperties->num_tuners;
221 properties->num_audio_sources = halProperties->num_audio_sources;
222 properties->supports_capture = halProperties->supports_capture;
223
224 for (size_t i = 0; i < ARRAY_SIZE(sKnownRegionConfigs); i++) {
225 const radio_hal_band_config_t *band = &sKnownRegionConfigs[i].band;
226 size_t j;
227 for (j = 0; j < halProperties->num_bands; j++) {
228 const radio_hal_band_config_t *halBand = &halProperties->bands[j];
229 size_t k;
230 if (band->type != halBand->type) continue;
231 if (band->lower_limit < halBand->lower_limit) continue;
232 if (band->upper_limit > halBand->upper_limit) continue;
233 for (k = 0; k < halBand->num_spacings; k++) {
234 if (band->spacings[0] == halBand->spacings[k]) break;
235 }
236 if (k == halBand->num_spacings) continue;
237 if (band->type == RADIO_BAND_AM) break;
238 if ((band->fm.deemphasis & halBand->fm.deemphasis) == 0) continue;
239 if (halBand->fm.rds == 0) break;
240 if ((band->fm.rds & halBand->fm.rds) != 0) break;
241 }
242 if (j == halProperties->num_bands) continue;
243
244 ALOGI("convertProperties() Adding band type %d region %d",
245 sKnownRegionConfigs[i].band.type , sKnownRegionConfigs[i].region);
246
247 memcpy(&properties->bands[properties->num_bands++],
248 &sKnownRegionConfigs[i],
249 sizeof(radio_band_config_t));
250 }
251}
252
253#undef LOG_TAG
254#define LOG_TAG "RadioService::CallbackThread"
255
256RadioService::CallbackThread::CallbackThread(const wp<ModuleClient>& moduleClient)
257 : mModuleClient(moduleClient), mMemoryDealer(new MemoryDealer(1024 * 1024, "RadioService"))
258{
259}
260
261RadioService::CallbackThread::~CallbackThread()
262{
263 mEventQueue.clear();
264}
265
266void RadioService::CallbackThread::onFirstRef()
267{
268 run("RadioService cbk", ANDROID_PRIORITY_URGENT_AUDIO);
269}
270
271bool RadioService::CallbackThread::threadLoop()
272{
273 while (!exitPending()) {
274 sp<IMemory> eventMemory;
275 sp<ModuleClient> moduleClient;
276 {
277 Mutex::Autolock _l(mCallbackLock);
278 while (mEventQueue.isEmpty() && !exitPending()) {
279 ALOGV("CallbackThread::threadLoop() sleep");
280 mCallbackCond.wait(mCallbackLock);
281 ALOGV("CallbackThread::threadLoop() wake up");
282 }
283 if (exitPending()) {
284 break;
285 }
286 eventMemory = mEventQueue[0];
287 mEventQueue.removeAt(0);
288 moduleClient = mModuleClient.promote();
289 }
290 if (moduleClient != 0) {
291 moduleClient->onCallbackEvent(eventMemory);
292 eventMemory.clear();
293 }
294 }
295 return false;
296}
297
298void RadioService::CallbackThread::exit()
299{
300 Mutex::Autolock _l(mCallbackLock);
301 requestExit();
302 mCallbackCond.broadcast();
303}
304
305sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEvent)
306{
307 sp<IMemory> eventMemory;
308
309 size_t headerSize =
310 (sizeof(struct radio_event) + sizeof(unsigned int) - 1) /sizeof(unsigned int);
311 size_t metadataSize = 0;
312 switch (halEvent->type) {
313 case RADIO_EVENT_TUNED:
314 case RADIO_EVENT_AF_SWITCH:
315 if (radio_metadata_check(halEvent->info.metadata) == 0) {
316 metadataSize = radio_metadata_get_size(halEvent->info.metadata);
317 }
318 break;
319 case RADIO_EVENT_METADATA:
320 if (radio_metadata_check(halEvent->metadata) != 0) {
321 return eventMemory;
322 }
323 metadataSize = radio_metadata_get_size(halEvent->metadata);
324 break;
325 default:
326 break;
327 }
328 size_t size = headerSize + metadataSize;
329 eventMemory = mMemoryDealer->allocate(size);
330 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
331 eventMemory.clear();
332 return eventMemory;
333 }
334 struct radio_event *event = (struct radio_event *)eventMemory->pointer();
335 event->type = halEvent->type;
336 event->status = halEvent->status;
337
338 switch (event->type) {
339 case RADIO_EVENT_CONFIG:
340 event->config.band = halEvent->config;
341 break;
342 case RADIO_EVENT_TUNED:
343 case RADIO_EVENT_AF_SWITCH:
344 event->info = halEvent->info;
345 if (metadataSize != 0) {
346 memcpy((char *)event + headerSize, halEvent->info.metadata, metadataSize);
347 // replace meta data pointer by offset while in shared memory so that receiving side
348 // can restore the pointer in destination process.
349 event->info.metadata = (radio_metadata_t *)headerSize;
350 }
351 break;
352 case RADIO_EVENT_TA:
Sanket Agarwalf639ba12015-10-12 13:05:53 -0700353 case RADIO_EVENT_EA:
Eric Laurent4e090692015-03-05 15:12:40 -0800354 case RADIO_EVENT_ANTENNA:
355 case RADIO_EVENT_CONTROL:
356 event->on = halEvent->on;
357 break;
358 case RADIO_EVENT_METADATA:
359 memcpy((char *)event + headerSize, halEvent->metadata, metadataSize);
360 // replace meta data pointer by offset while in shared memory so that receiving side
361 // can restore the pointer in destination process.
362 event->metadata = (radio_metadata_t *)headerSize;
363 break;
364 case RADIO_EVENT_HW_FAILURE:
365 default:
366 break;
367 }
368
369 return eventMemory;
370}
371
372void RadioService::CallbackThread::sendEvent(radio_hal_event_t *event)
373 {
374 sp<IMemory> eventMemory = prepareEvent(event);
375 if (eventMemory == 0) {
376 return;
377 }
378
379 AutoMutex lock(mCallbackLock);
380 mEventQueue.add(eventMemory);
381 mCallbackCond.signal();
382 ALOGV("%s DONE", __FUNCTION__);
383}
384
385
386#undef LOG_TAG
387#define LOG_TAG "RadioService::Module"
388
Eric Laurent53810822015-03-12 09:12:01 -0700389RadioService::Module::Module(radio_hw_device* hwDevice, radio_properties properties)
390 : mHwDevice(hwDevice), mProperties(properties), mMute(true)
Eric Laurent4e090692015-03-05 15:12:40 -0800391{
392}
393
394RadioService::Module::~Module() {
395 mModuleClients.clear();
396}
397
398status_t RadioService::Module::dump(int fd __unused, const Vector<String16>& args __unused) {
399 String8 result;
400 return NO_ERROR;
401}
402
403sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioClient>& client,
404 const struct radio_band_config *config,
405 bool audio)
406{
407 ALOGV("addClient() %p config %p product %s", this, config, mProperties.product);
408 AutoMutex lock(mLock);
409 sp<ModuleClient> moduleClient;
410 int ret;
411
412 for (size_t i = 0; i < mModuleClients.size(); i++) {
413 if (mModuleClients[i]->client() == client) {
414 // client already connected: reject
415 return moduleClient;
416 }
417 }
418 moduleClient = new ModuleClient(this, client, config, audio);
419
420 struct radio_hal_band_config halConfig;
421 halConfig = config->band;
422
Eric Laurent53810822015-03-12 09:12:01 -0700423 // Tuner preemption logic:
424 // There is a limited amount of tuners and a limited amount of radio audio sources per module.
425 // The minimum is one tuner and one audio source.
426 // The numbers of tuners and sources are indicated in the module properties.
427 // NOTE: current framework implementation only supports one radio audio source.
428 // It is possible to open more than one tuner at a time but only one tuner can be connected
429 // to the radio audio source (AUDIO_DEVICE_IN_FM_TUNER).
430 // The base rule is that a newly connected tuner always wins, i.e. always gets a tuner
431 // and can use the audio source if requested.
432 // If another client is preempted, it is notified by a callback with RADIO_EVENT_CONTROL
433 // indicating loss of control.
434 // - If the newly connected client requests the audio source (audio == true):
435 // - if an audio source is available
436 // no problem
437 // - if not:
438 // the oldest client in the list using audio is preempted.
439 // - If the newly connected client does not request the audio source (audio == false):
440 // - if a tuner is available
441 // no problem
442 // - if not:
443 // The oldest client not using audio is preempted first and if none is found the
444 // the oldest client using audio is preempted.
445 // Each time a tuner using the audio source is opened or closed, the audio policy manager is
446 // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER.
447
Eric Laurent4e090692015-03-05 15:12:40 -0800448 sp<ModuleClient> oldestTuner;
449 sp<ModuleClient> oldestAudio;
450 size_t allocatedTuners = 0;
451 size_t allocatedAudio = 0;
452 for (size_t i = 0; i < mModuleClients.size(); i++) {
453 if (mModuleClients[i]->getTuner() != NULL) {
454 if (mModuleClients[i]->audio()) {
455 if (oldestAudio == 0) {
456 oldestAudio = mModuleClients[i];
457 }
458 allocatedAudio++;
459 } else {
460 if (oldestTuner == 0) {
461 oldestTuner = mModuleClients[i];
462 }
463 allocatedTuners++;
464 }
465 }
466 }
467
468 const struct radio_tuner *halTuner;
Eric Laurent53810822015-03-12 09:12:01 -0700469 sp<ModuleClient> preemtedClient;
Eric Laurent4e090692015-03-05 15:12:40 -0800470 if (audio) {
471 if (allocatedAudio >= mProperties.num_audio_sources) {
472 ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
Eric Laurent53810822015-03-12 09:12:01 -0700473 preemtedClient = oldestAudio;
Eric Laurent4e090692015-03-05 15:12:40 -0800474 }
475 } else {
476 if (allocatedAudio + allocatedTuners >= mProperties.num_tuners) {
477 if (allocatedTuners != 0) {
478 ALOG_ASSERT(oldestTuner != 0, "addClient() allocatedTuners/oldestTuner mismatch");
Eric Laurent53810822015-03-12 09:12:01 -0700479 preemtedClient = oldestTuner;
Eric Laurent4e090692015-03-05 15:12:40 -0800480 } else {
481 ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
Eric Laurent53810822015-03-12 09:12:01 -0700482 preemtedClient = oldestAudio;
Eric Laurent4e090692015-03-05 15:12:40 -0800483 }
484 }
485 }
Eric Laurent53810822015-03-12 09:12:01 -0700486 if (preemtedClient != 0) {
487 halTuner = preemtedClient->getTuner();
488 preemtedClient->setTuner(NULL);
489 mHwDevice->close_tuner(mHwDevice, halTuner);
490 if (preemtedClient->audio()) {
491 notifyDeviceConnection(false, "");
492 }
493 }
Eric Laurent4e090692015-03-05 15:12:40 -0800494
495 ret = mHwDevice->open_tuner(mHwDevice, &halConfig, audio,
496 RadioService::callback, moduleClient->callbackThread().get(),
497 &halTuner);
498 if (ret == 0) {
499 ALOGV("addClient() setTuner %p", halTuner);
500 moduleClient->setTuner(halTuner);
501 mModuleClients.add(moduleClient);
Eric Laurent53810822015-03-12 09:12:01 -0700502 if (audio) {
503 notifyDeviceConnection(true, "");
504 }
Eric Laurentf2f79cf2015-04-23 17:10:50 -0700505 ALOGV("addClient() DONE moduleClient %p", moduleClient.get());
Eric Laurent4e090692015-03-05 15:12:40 -0800506 } else {
Eric Laurentf2f79cf2015-04-23 17:10:50 -0700507 ALOGW("%s open_tuner failed with error %d", __FUNCTION__, ret);
Eric Laurent4e090692015-03-05 15:12:40 -0800508 moduleClient.clear();
509 }
510
Eric Laurent4e090692015-03-05 15:12:40 -0800511 return moduleClient;
512}
513
514void RadioService::Module::removeClient(const sp<ModuleClient>& moduleClient) {
515 ALOGV("removeClient()");
516 AutoMutex lock(mLock);
517 int ret;
518 ssize_t index = -1;
519
520 for (size_t i = 0; i < mModuleClients.size(); i++) {
521 if (mModuleClients[i] == moduleClient) {
522 index = i;
523 break;
524 }
525 }
526 if (index == -1) {
527 return;
528 }
529
530 mModuleClients.removeAt(index);
531 const struct radio_tuner *halTuner = moduleClient->getTuner();
532 if (halTuner == NULL) {
533 return;
534 }
535
536 mHwDevice->close_tuner(mHwDevice, halTuner);
Eric Laurent53810822015-03-12 09:12:01 -0700537 if (moduleClient->audio()) {
538 notifyDeviceConnection(false, "");
539 }
Eric Laurent4e090692015-03-05 15:12:40 -0800540
Eric Laurent4e090692015-03-05 15:12:40 -0800541 mMute = true;
542
543 if (mModuleClients.isEmpty()) {
544 return;
545 }
546
Eric Laurent53810822015-03-12 09:12:01 -0700547 // Tuner reallocation logic:
548 // When a client is removed and was controlling a tuner, this tuner will be allocated to a
549 // previously preempted client. This client will be notified by a callback with
550 // RADIO_EVENT_CONTROL indicating gain of control.
551 // - If a preempted client is waiting for an audio source and one becomes available:
552 // Allocate the tuner to the most recently added client waiting for an audio source
553 // - If not:
554 // Allocate the tuner to the most recently added client.
555 // Each time a tuner using the audio source is opened or closed, the audio policy manager is
556 // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER.
557
Eric Laurent4e090692015-03-05 15:12:40 -0800558 sp<ModuleClient> youngestClient;
559 sp<ModuleClient> youngestClientAudio;
560 size_t allocatedTuners = 0;
561 size_t allocatedAudio = 0;
Eric Laurent53810822015-03-12 09:12:01 -0700562 for (ssize_t i = mModuleClients.size() - 1; i >= 0; i--) {
Eric Laurent4e090692015-03-05 15:12:40 -0800563 if (mModuleClients[i]->getTuner() == NULL) {
564 if (mModuleClients[i]->audio()) {
565 if (youngestClientAudio == 0) {
566 youngestClientAudio = mModuleClients[i];
567 }
568 } else {
569 if (youngestClient == 0) {
570 youngestClient = mModuleClients[i];
571 }
572 }
573 } else {
574 if (mModuleClients[i]->audio()) {
575 allocatedAudio++;
576 } else {
577 allocatedTuners++;
578 }
579 }
580 }
581
582 ALOG_ASSERT(allocatedTuners + allocatedAudio < mProperties.num_tuners,
583 "removeClient() removed client but no tuner available");
584
585 ALOG_ASSERT(!moduleClient->audio() || allocatedAudio < mProperties.num_audio_sources,
586 "removeClient() removed audio client but no tuner with audio available");
587
588 if (allocatedAudio < mProperties.num_audio_sources && youngestClientAudio != 0) {
589 youngestClient = youngestClientAudio;
590 }
591
592 ALOG_ASSERT(youngestClient != 0, "removeClient() removed client no candidate found for tuner");
593
594 struct radio_hal_band_config halConfig = youngestClient->halConfig();
595 ret = mHwDevice->open_tuner(mHwDevice, &halConfig, youngestClient->audio(),
596 RadioService::callback, moduleClient->callbackThread().get(),
597 &halTuner);
598
Eric Laurent4e090692015-03-05 15:12:40 -0800599 if (ret == 0) {
600 youngestClient->setTuner(halTuner);
Eric Laurent53810822015-03-12 09:12:01 -0700601 if (youngestClient->audio()) {
602 notifyDeviceConnection(true, "");
603 }
Eric Laurent4e090692015-03-05 15:12:40 -0800604 }
605}
606
607status_t RadioService::Module::setMute(bool mute)
608{
609 Mutex::Autolock _l(mLock);
610 if (mute != mMute) {
611 mMute = mute;
612 //TODO notifify audio policy manager of media activity on radio audio device
613 }
614 return NO_ERROR;
615}
616
617status_t RadioService::Module::getMute(bool *mute)
618{
619 Mutex::Autolock _l(mLock);
620 *mute = mMute;
621 return NO_ERROR;
622}
623
624
625const struct radio_band_config *RadioService::Module::getDefaultConfig() const
626{
627 if (mProperties.num_bands == 0) {
628 return NULL;
629 }
630 return &mProperties.bands[0];
631}
632
Eric Laurent53810822015-03-12 09:12:01 -0700633void RadioService::Module::notifyDeviceConnection(bool connected,
634 const char *address) {
635 int64_t token = IPCThreadState::self()->clearCallingIdentity();
636 AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
637 connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE :
638 AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
639 address, kRadioTunerAudioDeviceName);
640 IPCThreadState::self()->restoreCallingIdentity(token);
641}
642
Eric Laurent4e090692015-03-05 15:12:40 -0800643#undef LOG_TAG
644#define LOG_TAG "RadioService::ModuleClient"
645
646RadioService::ModuleClient::ModuleClient(const sp<Module>& module,
647 const sp<IRadioClient>& client,
648 const struct radio_band_config *config,
649 bool audio)
650 : mModule(module), mClient(client), mConfig(*config), mAudio(audio), mTuner(NULL)
651{
652}
653
654void RadioService::ModuleClient::onFirstRef()
655{
656 mCallbackThread = new CallbackThread(this);
657 IInterface::asBinder(mClient)->linkToDeath(this);
658}
659
660RadioService::ModuleClient::~ModuleClient() {
661 if (mClient != 0) {
662 IInterface::asBinder(mClient)->unlinkToDeath(this);
663 mClient.clear();
664 }
665 if (mCallbackThread != 0) {
666 mCallbackThread->exit();
667 }
668}
669
670status_t RadioService::ModuleClient::dump(int fd __unused,
671 const Vector<String16>& args __unused) {
672 String8 result;
673 return NO_ERROR;
674}
675
676void RadioService::ModuleClient::detach() {
677 ALOGV("%s", __FUNCTION__);
678 sp<ModuleClient> strongMe = this;
679 {
680 AutoMutex lock(mLock);
681 if (mClient != 0) {
682 IInterface::asBinder(mClient)->unlinkToDeath(this);
683 mClient.clear();
684 }
685 }
686 sp<Module> module = mModule.promote();
687 if (module == 0) {
688 return;
689 }
690 module->removeClient(this);
691}
692
693radio_hal_band_config_t RadioService::ModuleClient::halConfig() const
694{
695 AutoMutex lock(mLock);
696 ALOGV("%s locked", __FUNCTION__);
697 return mConfig.band;
698}
699
700const struct radio_tuner *RadioService::ModuleClient::getTuner() const
701{
702 AutoMutex lock(mLock);
703 ALOGV("%s locked", __FUNCTION__);
704 return mTuner;
705}
706
707void RadioService::ModuleClient::setTuner(const struct radio_tuner *tuner)
708{
709 ALOGV("%s %p", __FUNCTION__, this);
710
711 AutoMutex lock(mLock);
712 mTuner = tuner;
713 ALOGV("%s locked", __FUNCTION__);
714
715 radio_hal_event_t event;
716 event.type = RADIO_EVENT_CONTROL;
717 event.status = 0;
718 event.on = mTuner != NULL;
719 mCallbackThread->sendEvent(&event);
720 ALOGV("%s DONE", __FUNCTION__);
721
722}
723
724status_t RadioService::ModuleClient::setConfiguration(const struct radio_band_config *config)
725{
726 AutoMutex lock(mLock);
727 status_t status = NO_ERROR;
728 ALOGV("%s locked", __FUNCTION__);
729
730 if (mTuner != NULL) {
731 struct radio_hal_band_config halConfig;
732 halConfig = config->band;
733 status = (status_t)mTuner->set_configuration(mTuner, &halConfig);
734 if (status == NO_ERROR) {
735 mConfig = *config;
736 }
737 } else {
738 mConfig = *config;
Aurimas Liutikas13958742016-02-18 10:02:35 -0800739 status = INVALID_OPERATION;
Eric Laurent4e090692015-03-05 15:12:40 -0800740 }
741
742 return status;
743}
744
745status_t RadioService::ModuleClient::getConfiguration(struct radio_band_config *config)
746{
747 AutoMutex lock(mLock);
748 status_t status = NO_ERROR;
749 ALOGV("%s locked", __FUNCTION__);
750
751 if (mTuner != NULL) {
752 struct radio_hal_band_config halConfig;
753 status = (status_t)mTuner->get_configuration(mTuner, &halConfig);
754 if (status == NO_ERROR) {
755 mConfig.band = halConfig;
756 }
757 }
758 *config = mConfig;
759
760 return status;
761}
762
763status_t RadioService::ModuleClient::setMute(bool mute)
764{
765 sp<Module> module;
766 {
767 Mutex::Autolock _l(mLock);
768 ALOGV("%s locked", __FUNCTION__);
769 if (mTuner == NULL || !mAudio) {
770 return INVALID_OPERATION;
771 }
772 module = mModule.promote();
773 if (module == 0) {
774 return NO_INIT;
775 }
776 }
777 module->setMute(mute);
778 return NO_ERROR;
779}
780
781status_t RadioService::ModuleClient::getMute(bool *mute)
782{
783 sp<Module> module;
784 {
785 Mutex::Autolock _l(mLock);
786 ALOGV("%s locked", __FUNCTION__);
787 module = mModule.promote();
788 if (module == 0) {
789 return NO_INIT;
790 }
791 }
792 return module->getMute(mute);
793}
794
795status_t RadioService::ModuleClient::scan(radio_direction_t direction, bool skipSubChannel)
796{
797 AutoMutex lock(mLock);
798 ALOGV("%s locked", __FUNCTION__);
799 status_t status;
800 if (mTuner != NULL) {
801 status = (status_t)mTuner->scan(mTuner, direction, skipSubChannel);
802 } else {
803 status = INVALID_OPERATION;
804 }
805 return status;
806}
807
808status_t RadioService::ModuleClient::step(radio_direction_t direction, bool skipSubChannel)
809{
810 AutoMutex lock(mLock);
811 ALOGV("%s locked", __FUNCTION__);
812 status_t status;
813 if (mTuner != NULL) {
814 status = (status_t)mTuner->step(mTuner, direction, skipSubChannel);
815 } else {
816 status = INVALID_OPERATION;
817 }
818 return status;
819}
820
821status_t RadioService::ModuleClient::tune(unsigned int channel, unsigned int subChannel)
822{
823 AutoMutex lock(mLock);
824 ALOGV("%s locked", __FUNCTION__);
825 status_t status;
826 if (mTuner != NULL) {
827 status = (status_t)mTuner->tune(mTuner, channel, subChannel);
828 } else {
829 status = INVALID_OPERATION;
830 }
831 return status;
832}
833
834status_t RadioService::ModuleClient::cancel()
835{
836 AutoMutex lock(mLock);
837 ALOGV("%s locked", __FUNCTION__);
838 status_t status;
839 if (mTuner != NULL) {
840 status = (status_t)mTuner->cancel(mTuner);
841 } else {
842 status = INVALID_OPERATION;
843 }
844 return status;
845}
846
847status_t RadioService::ModuleClient::getProgramInformation(struct radio_program_info *info)
848{
849 AutoMutex lock(mLock);
850 ALOGV("%s locked", __FUNCTION__);
851 status_t status;
852 if (mTuner != NULL) {
853 status = (status_t)mTuner->get_program_information(mTuner, info);
854 } else {
855 status = INVALID_OPERATION;
856 }
857 return status;
858}
859
860status_t RadioService::ModuleClient::hasControl(bool *hasControl)
861{
862 Mutex::Autolock lock(mLock);
863 ALOGV("%s locked", __FUNCTION__);
864 *hasControl = mTuner != NULL;
865 return NO_ERROR;
866}
867
868void RadioService::ModuleClient::onCallbackEvent(const sp<IMemory>& eventMemory)
869{
870 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
871 return;
872 }
873
874 sp<IRadioClient> client;
875 {
876 AutoMutex lock(mLock);
877 ALOGV("%s locked", __FUNCTION__);
878 radio_event_t *event = (radio_event_t *)eventMemory->pointer();
879 switch (event->type) {
880 case RADIO_EVENT_CONFIG:
881 mConfig.band = event->config.band;
882 event->config.region = mConfig.region;
883 break;
884 default:
885 break;
886 }
887
888 client = mClient;
889 }
890 if (client != 0) {
891 client->onEvent(eventMemory);
892 }
893}
894
895
896void RadioService::ModuleClient::binderDied(
897 const wp<IBinder> &who __unused) {
898 ALOGW("client binder died for client %p", this);
899 detach();
900}
901
902}; // namespace android