blob: 152619bacd26cd5babb85e4909c917a36c96c1d7 [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
25#include <system/radio.h>
26#include <system/radio_metadata.h>
27#include <cutils/atomic.h>
28#include <cutils/properties.h>
29#include <hardware/hardware.h>
30#include <utils/Errors.h>
31#include <utils/Log.h>
32#include <binder/IServiceManager.h>
33#include <binder/MemoryBase.h>
34#include <binder/MemoryHeapBase.h>
35#include <hardware/radio.h>
36#include "RadioService.h"
37#include "RadioRegions.h"
38
39namespace android {
40
41
42RadioService::RadioService()
43 : BnRadioService(), mNextUniqueId(1)
44{
45 ALOGI("%s", __FUNCTION__);
46}
47
48void RadioService::onFirstRef()
49{
50 const hw_module_t *mod;
51 int rc;
52 struct radio_hw_device *dev;
53
54 ALOGI("%s", __FUNCTION__);
55
56 rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, RADIO_HARDWARE_MODULE_ID_FM, &mod);
57 if (rc != 0) {
58 ALOGE("couldn't load radio module %s.%s (%s)",
59 RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
60 return;
61 }
62 rc = radio_hw_device_open(mod, &dev);
63 if (rc != 0) {
64 ALOGE("couldn't open radio hw device in %s.%s (%s)",
65 RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
66 return;
67 }
68 if (dev->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
69 ALOGE("wrong radio hw device version %04x", dev->common.version);
70 return;
71 }
72
73 struct radio_hal_properties halProperties;
74 rc = dev->get_properties(dev, &halProperties);
75 if (rc != 0) {
76 ALOGE("could not read implementation properties");
77 return;
78 }
79
80 radio_properties_t properties;
81 properties.handle =
82 (radio_handle_t)android_atomic_inc(&mNextUniqueId);
83
84 ALOGI("loaded default module %s, handle %d", properties.product, properties.handle);
85
86 convertProperties(&properties, &halProperties);
87 sp<Module> module = new Module(this, dev, properties);
88 mModules.add(properties.handle, module);
89}
90
91RadioService::~RadioService()
92{
93 for (size_t i = 0; i < mModules.size(); i++) {
94 radio_hw_device_close(mModules.valueAt(i)->hwDevice());
95 }
96}
97
98status_t RadioService::listModules(struct radio_properties *properties,
99 uint32_t *numModules)
100{
101 ALOGV("listModules");
102
103 AutoMutex lock(mServiceLock);
104 if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
105 return BAD_VALUE;
106 }
107 size_t maxModules = *numModules;
108 *numModules = mModules.size();
109 for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
110 properties[i] = mModules.valueAt(i)->properties();
111 }
112 return NO_ERROR;
113}
114
115status_t RadioService::attach(radio_handle_t handle,
116 const sp<IRadioClient>& client,
117 const struct radio_band_config *config,
118 bool withAudio,
119 sp<IRadio>& radio)
120{
121 ALOGV("%s %d config %p withAudio %d", __FUNCTION__, handle, config, withAudio);
122
123 AutoMutex lock(mServiceLock);
124 radio.clear();
125 if (client == 0) {
126 return BAD_VALUE;
127 }
128 ssize_t index = mModules.indexOfKey(handle);
129 if (index < 0) {
130 return BAD_VALUE;
131 }
132 sp<Module> module = mModules.valueAt(index);
133
134 if (config == NULL) {
135 config = module->getDefaultConfig();
136 if (config == NULL) {
137 return INVALID_OPERATION;
138 }
139 }
140 ALOGV("%s region %d type %d", __FUNCTION__, config->region, config->band.type);
141
142 radio = module->addClient(client, config, withAudio);
143
144 if (radio == 0) {
145 NO_INIT;
146 }
147 return NO_ERROR;
148}
149
150
151static const int kDumpLockRetries = 50;
152static const int kDumpLockSleep = 60000;
153
154static bool tryLock(Mutex& mutex)
155{
156 bool locked = false;
157 for (int i = 0; i < kDumpLockRetries; ++i) {
158 if (mutex.tryLock() == NO_ERROR) {
159 locked = true;
160 break;
161 }
162 usleep(kDumpLockSleep);
163 }
164 return locked;
165}
166
167status_t RadioService::dump(int fd, const Vector<String16>& args __unused) {
168 String8 result;
169 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
170 result.appendFormat("Permission Denial: can't dump RadioService");
171 write(fd, result.string(), result.size());
172 } else {
173 bool locked = tryLock(mServiceLock);
174 // failed to lock - RadioService is probably deadlocked
175 if (!locked) {
176 result.append("RadioService may be deadlocked\n");
177 write(fd, result.string(), result.size());
178 }
179
180 if (locked) mServiceLock.unlock();
181 }
182 return NO_ERROR;
183}
184
185status_t RadioService::onTransact(
186 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
187 return BnRadioService::onTransact(code, data, reply, flags);
188}
189
190
191// static
192void RadioService::callback(radio_hal_event_t *halEvent, void *cookie)
193{
194 CallbackThread *callbackThread = (CallbackThread *)cookie;
195 if (callbackThread == NULL) {
196 return;
197 }
198 callbackThread->sendEvent(halEvent);
199}
200
201/* static */
202void RadioService::convertProperties(radio_properties_t *properties,
203 const radio_hal_properties_t *halProperties)
204{
205 memset(properties, 0, sizeof(struct radio_properties));
206 properties->class_id = halProperties->class_id;
207 strlcpy(properties->implementor, halProperties->implementor,
208 RADIO_STRING_LEN_MAX);
209 strlcpy(properties->product, halProperties->product,
210 RADIO_STRING_LEN_MAX);
211 strlcpy(properties->version, halProperties->version,
212 RADIO_STRING_LEN_MAX);
213 strlcpy(properties->serial, halProperties->serial,
214 RADIO_STRING_LEN_MAX);
215 properties->num_tuners = halProperties->num_tuners;
216 properties->num_audio_sources = halProperties->num_audio_sources;
217 properties->supports_capture = halProperties->supports_capture;
218
219 for (size_t i = 0; i < ARRAY_SIZE(sKnownRegionConfigs); i++) {
220 const radio_hal_band_config_t *band = &sKnownRegionConfigs[i].band;
221 size_t j;
222 for (j = 0; j < halProperties->num_bands; j++) {
223 const radio_hal_band_config_t *halBand = &halProperties->bands[j];
224 size_t k;
225 if (band->type != halBand->type) continue;
226 if (band->lower_limit < halBand->lower_limit) continue;
227 if (band->upper_limit > halBand->upper_limit) continue;
228 for (k = 0; k < halBand->num_spacings; k++) {
229 if (band->spacings[0] == halBand->spacings[k]) break;
230 }
231 if (k == halBand->num_spacings) continue;
232 if (band->type == RADIO_BAND_AM) break;
233 if ((band->fm.deemphasis & halBand->fm.deemphasis) == 0) continue;
234 if (halBand->fm.rds == 0) break;
235 if ((band->fm.rds & halBand->fm.rds) != 0) break;
236 }
237 if (j == halProperties->num_bands) continue;
238
239 ALOGI("convertProperties() Adding band type %d region %d",
240 sKnownRegionConfigs[i].band.type , sKnownRegionConfigs[i].region);
241
242 memcpy(&properties->bands[properties->num_bands++],
243 &sKnownRegionConfigs[i],
244 sizeof(radio_band_config_t));
245 }
246}
247
248#undef LOG_TAG
249#define LOG_TAG "RadioService::CallbackThread"
250
251RadioService::CallbackThread::CallbackThread(const wp<ModuleClient>& moduleClient)
252 : mModuleClient(moduleClient), mMemoryDealer(new MemoryDealer(1024 * 1024, "RadioService"))
253{
254}
255
256RadioService::CallbackThread::~CallbackThread()
257{
258 mEventQueue.clear();
259}
260
261void RadioService::CallbackThread::onFirstRef()
262{
263 run("RadioService cbk", ANDROID_PRIORITY_URGENT_AUDIO);
264}
265
266bool RadioService::CallbackThread::threadLoop()
267{
268 while (!exitPending()) {
269 sp<IMemory> eventMemory;
270 sp<ModuleClient> moduleClient;
271 {
272 Mutex::Autolock _l(mCallbackLock);
273 while (mEventQueue.isEmpty() && !exitPending()) {
274 ALOGV("CallbackThread::threadLoop() sleep");
275 mCallbackCond.wait(mCallbackLock);
276 ALOGV("CallbackThread::threadLoop() wake up");
277 }
278 if (exitPending()) {
279 break;
280 }
281 eventMemory = mEventQueue[0];
282 mEventQueue.removeAt(0);
283 moduleClient = mModuleClient.promote();
284 }
285 if (moduleClient != 0) {
286 moduleClient->onCallbackEvent(eventMemory);
287 eventMemory.clear();
288 }
289 }
290 return false;
291}
292
293void RadioService::CallbackThread::exit()
294{
295 Mutex::Autolock _l(mCallbackLock);
296 requestExit();
297 mCallbackCond.broadcast();
298}
299
300sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEvent)
301{
302 sp<IMemory> eventMemory;
303
304 size_t headerSize =
305 (sizeof(struct radio_event) + sizeof(unsigned int) - 1) /sizeof(unsigned int);
306 size_t metadataSize = 0;
307 switch (halEvent->type) {
308 case RADIO_EVENT_TUNED:
309 case RADIO_EVENT_AF_SWITCH:
310 if (radio_metadata_check(halEvent->info.metadata) == 0) {
311 metadataSize = radio_metadata_get_size(halEvent->info.metadata);
312 }
313 break;
314 case RADIO_EVENT_METADATA:
315 if (radio_metadata_check(halEvent->metadata) != 0) {
316 return eventMemory;
317 }
318 metadataSize = radio_metadata_get_size(halEvent->metadata);
319 break;
320 default:
321 break;
322 }
323 size_t size = headerSize + metadataSize;
324 eventMemory = mMemoryDealer->allocate(size);
325 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
326 eventMemory.clear();
327 return eventMemory;
328 }
329 struct radio_event *event = (struct radio_event *)eventMemory->pointer();
330 event->type = halEvent->type;
331 event->status = halEvent->status;
332
333 switch (event->type) {
334 case RADIO_EVENT_CONFIG:
335 event->config.band = halEvent->config;
336 break;
337 case RADIO_EVENT_TUNED:
338 case RADIO_EVENT_AF_SWITCH:
339 event->info = halEvent->info;
340 if (metadataSize != 0) {
341 memcpy((char *)event + headerSize, halEvent->info.metadata, metadataSize);
342 // replace meta data pointer by offset while in shared memory so that receiving side
343 // can restore the pointer in destination process.
344 event->info.metadata = (radio_metadata_t *)headerSize;
345 }
346 break;
347 case RADIO_EVENT_TA:
348 case RADIO_EVENT_ANTENNA:
349 case RADIO_EVENT_CONTROL:
350 event->on = halEvent->on;
351 break;
352 case RADIO_EVENT_METADATA:
353 memcpy((char *)event + headerSize, halEvent->metadata, metadataSize);
354 // replace meta data pointer by offset while in shared memory so that receiving side
355 // can restore the pointer in destination process.
356 event->metadata = (radio_metadata_t *)headerSize;
357 break;
358 case RADIO_EVENT_HW_FAILURE:
359 default:
360 break;
361 }
362
363 return eventMemory;
364}
365
366void RadioService::CallbackThread::sendEvent(radio_hal_event_t *event)
367 {
368 sp<IMemory> eventMemory = prepareEvent(event);
369 if (eventMemory == 0) {
370 return;
371 }
372
373 AutoMutex lock(mCallbackLock);
374 mEventQueue.add(eventMemory);
375 mCallbackCond.signal();
376 ALOGV("%s DONE", __FUNCTION__);
377}
378
379
380#undef LOG_TAG
381#define LOG_TAG "RadioService::Module"
382
383RadioService::Module::Module(const sp<RadioService>& service,
384 radio_hw_device* hwDevice,
385 radio_properties properties)
386 : mService(service), mHwDevice(hwDevice), mProperties(properties), mMute(true)
387{
388}
389
390RadioService::Module::~Module() {
391 mModuleClients.clear();
392}
393
394status_t RadioService::Module::dump(int fd __unused, const Vector<String16>& args __unused) {
395 String8 result;
396 return NO_ERROR;
397}
398
399sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioClient>& client,
400 const struct radio_band_config *config,
401 bool audio)
402{
403 ALOGV("addClient() %p config %p product %s", this, config, mProperties.product);
404 AutoMutex lock(mLock);
405 sp<ModuleClient> moduleClient;
406 int ret;
407
408 for (size_t i = 0; i < mModuleClients.size(); i++) {
409 if (mModuleClients[i]->client() == client) {
410 // client already connected: reject
411 return moduleClient;
412 }
413 }
414 moduleClient = new ModuleClient(this, client, config, audio);
415
416 struct radio_hal_band_config halConfig;
417 halConfig = config->band;
418
419 sp<ModuleClient> oldestTuner;
420 sp<ModuleClient> oldestAudio;
421 size_t allocatedTuners = 0;
422 size_t allocatedAudio = 0;
423 for (size_t i = 0; i < mModuleClients.size(); i++) {
424 if (mModuleClients[i]->getTuner() != NULL) {
425 if (mModuleClients[i]->audio()) {
426 if (oldestAudio == 0) {
427 oldestAudio = mModuleClients[i];
428 }
429 allocatedAudio++;
430 } else {
431 if (oldestTuner == 0) {
432 oldestTuner = mModuleClients[i];
433 }
434 allocatedTuners++;
435 }
436 }
437 }
438
439 const struct radio_tuner *halTuner;
440 if (audio) {
441 if (allocatedAudio >= mProperties.num_audio_sources) {
442 ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
443 halTuner = oldestAudio->getTuner();
444 oldestAudio->setTuner(NULL);
445 mHwDevice->close_tuner(mHwDevice, halTuner);
446 }
447 } else {
448 if (allocatedAudio + allocatedTuners >= mProperties.num_tuners) {
449 if (allocatedTuners != 0) {
450 ALOG_ASSERT(oldestTuner != 0, "addClient() allocatedTuners/oldestTuner mismatch");
451 halTuner = oldestTuner->getTuner();
452 oldestTuner->setTuner(NULL);
453 mHwDevice->close_tuner(mHwDevice, halTuner);
454 } else {
455 ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
456 halTuner = oldestAudio->getTuner();
457 oldestAudio->setTuner(NULL);
458 mHwDevice->close_tuner(mHwDevice, halTuner);
459 }
460 }
461 }
462
463 ret = mHwDevice->open_tuner(mHwDevice, &halConfig, audio,
464 RadioService::callback, moduleClient->callbackThread().get(),
465 &halTuner);
466 if (ret == 0) {
467 ALOGV("addClient() setTuner %p", halTuner);
468 moduleClient->setTuner(halTuner);
469 mModuleClients.add(moduleClient);
470 } else {
471 moduleClient.clear();
472 }
473
474 //TODO notify audio device connection to audio policy manager if audio is on
475
476 ALOGV("addClient() DONE moduleClient %p", moduleClient.get());
477
478 return moduleClient;
479}
480
481void RadioService::Module::removeClient(const sp<ModuleClient>& moduleClient) {
482 ALOGV("removeClient()");
483 AutoMutex lock(mLock);
484 int ret;
485 ssize_t index = -1;
486
487 for (size_t i = 0; i < mModuleClients.size(); i++) {
488 if (mModuleClients[i] == moduleClient) {
489 index = i;
490 break;
491 }
492 }
493 if (index == -1) {
494 return;
495 }
496
497 mModuleClients.removeAt(index);
498 const struct radio_tuner *halTuner = moduleClient->getTuner();
499 if (halTuner == NULL) {
500 return;
501 }
502
503 mHwDevice->close_tuner(mHwDevice, halTuner);
504
505 //TODO notify audio device disconnection to audio policy manager if audio was on
506 mMute = true;
507
508 if (mModuleClients.isEmpty()) {
509 return;
510 }
511
512 sp<ModuleClient> youngestClient;
513 sp<ModuleClient> youngestClientAudio;
514 size_t allocatedTuners = 0;
515 size_t allocatedAudio = 0;
516 for (ssize_t i = mModuleClients.size(); i >= 0; i--) {
517 if (mModuleClients[i]->getTuner() == NULL) {
518 if (mModuleClients[i]->audio()) {
519 if (youngestClientAudio == 0) {
520 youngestClientAudio = mModuleClients[i];
521 }
522 } else {
523 if (youngestClient == 0) {
524 youngestClient = mModuleClients[i];
525 }
526 }
527 } else {
528 if (mModuleClients[i]->audio()) {
529 allocatedAudio++;
530 } else {
531 allocatedTuners++;
532 }
533 }
534 }
535
536 ALOG_ASSERT(allocatedTuners + allocatedAudio < mProperties.num_tuners,
537 "removeClient() removed client but no tuner available");
538
539 ALOG_ASSERT(!moduleClient->audio() || allocatedAudio < mProperties.num_audio_sources,
540 "removeClient() removed audio client but no tuner with audio available");
541
542 if (allocatedAudio < mProperties.num_audio_sources && youngestClientAudio != 0) {
543 youngestClient = youngestClientAudio;
544 }
545
546 ALOG_ASSERT(youngestClient != 0, "removeClient() removed client no candidate found for tuner");
547
548 struct radio_hal_band_config halConfig = youngestClient->halConfig();
549 ret = mHwDevice->open_tuner(mHwDevice, &halConfig, youngestClient->audio(),
550 RadioService::callback, moduleClient->callbackThread().get(),
551 &halTuner);
552
553 //TODO notify audio device connection to audio policy manager if audio is on
554
555 if (ret == 0) {
556 youngestClient->setTuner(halTuner);
557 }
558}
559
560status_t RadioService::Module::setMute(bool mute)
561{
562 Mutex::Autolock _l(mLock);
563 if (mute != mMute) {
564 mMute = mute;
565 //TODO notifify audio policy manager of media activity on radio audio device
566 }
567 return NO_ERROR;
568}
569
570status_t RadioService::Module::getMute(bool *mute)
571{
572 Mutex::Autolock _l(mLock);
573 *mute = mMute;
574 return NO_ERROR;
575}
576
577
578const struct radio_band_config *RadioService::Module::getDefaultConfig() const
579{
580 if (mProperties.num_bands == 0) {
581 return NULL;
582 }
583 return &mProperties.bands[0];
584}
585
586#undef LOG_TAG
587#define LOG_TAG "RadioService::ModuleClient"
588
589RadioService::ModuleClient::ModuleClient(const sp<Module>& module,
590 const sp<IRadioClient>& client,
591 const struct radio_band_config *config,
592 bool audio)
593 : mModule(module), mClient(client), mConfig(*config), mAudio(audio), mTuner(NULL)
594{
595}
596
597void RadioService::ModuleClient::onFirstRef()
598{
599 mCallbackThread = new CallbackThread(this);
600 IInterface::asBinder(mClient)->linkToDeath(this);
601}
602
603RadioService::ModuleClient::~ModuleClient() {
604 if (mClient != 0) {
605 IInterface::asBinder(mClient)->unlinkToDeath(this);
606 mClient.clear();
607 }
608 if (mCallbackThread != 0) {
609 mCallbackThread->exit();
610 }
611}
612
613status_t RadioService::ModuleClient::dump(int fd __unused,
614 const Vector<String16>& args __unused) {
615 String8 result;
616 return NO_ERROR;
617}
618
619void RadioService::ModuleClient::detach() {
620 ALOGV("%s", __FUNCTION__);
621 sp<ModuleClient> strongMe = this;
622 {
623 AutoMutex lock(mLock);
624 if (mClient != 0) {
625 IInterface::asBinder(mClient)->unlinkToDeath(this);
626 mClient.clear();
627 }
628 }
629 sp<Module> module = mModule.promote();
630 if (module == 0) {
631 return;
632 }
633 module->removeClient(this);
634}
635
636radio_hal_band_config_t RadioService::ModuleClient::halConfig() const
637{
638 AutoMutex lock(mLock);
639 ALOGV("%s locked", __FUNCTION__);
640 return mConfig.band;
641}
642
643const struct radio_tuner *RadioService::ModuleClient::getTuner() const
644{
645 AutoMutex lock(mLock);
646 ALOGV("%s locked", __FUNCTION__);
647 return mTuner;
648}
649
650void RadioService::ModuleClient::setTuner(const struct radio_tuner *tuner)
651{
652 ALOGV("%s %p", __FUNCTION__, this);
653
654 AutoMutex lock(mLock);
655 mTuner = tuner;
656 ALOGV("%s locked", __FUNCTION__);
657
658 radio_hal_event_t event;
659 event.type = RADIO_EVENT_CONTROL;
660 event.status = 0;
661 event.on = mTuner != NULL;
662 mCallbackThread->sendEvent(&event);
663 ALOGV("%s DONE", __FUNCTION__);
664
665}
666
667status_t RadioService::ModuleClient::setConfiguration(const struct radio_band_config *config)
668{
669 AutoMutex lock(mLock);
670 status_t status = NO_ERROR;
671 ALOGV("%s locked", __FUNCTION__);
672
673 if (mTuner != NULL) {
674 struct radio_hal_band_config halConfig;
675 halConfig = config->band;
676 status = (status_t)mTuner->set_configuration(mTuner, &halConfig);
677 if (status == NO_ERROR) {
678 mConfig = *config;
679 }
680 } else {
681 mConfig = *config;
682 status == INVALID_OPERATION;
683 }
684
685 return status;
686}
687
688status_t RadioService::ModuleClient::getConfiguration(struct radio_band_config *config)
689{
690 AutoMutex lock(mLock);
691 status_t status = NO_ERROR;
692 ALOGV("%s locked", __FUNCTION__);
693
694 if (mTuner != NULL) {
695 struct radio_hal_band_config halConfig;
696 status = (status_t)mTuner->get_configuration(mTuner, &halConfig);
697 if (status == NO_ERROR) {
698 mConfig.band = halConfig;
699 }
700 }
701 *config = mConfig;
702
703 return status;
704}
705
706status_t RadioService::ModuleClient::setMute(bool mute)
707{
708 sp<Module> module;
709 {
710 Mutex::Autolock _l(mLock);
711 ALOGV("%s locked", __FUNCTION__);
712 if (mTuner == NULL || !mAudio) {
713 return INVALID_OPERATION;
714 }
715 module = mModule.promote();
716 if (module == 0) {
717 return NO_INIT;
718 }
719 }
720 module->setMute(mute);
721 return NO_ERROR;
722}
723
724status_t RadioService::ModuleClient::getMute(bool *mute)
725{
726 sp<Module> module;
727 {
728 Mutex::Autolock _l(mLock);
729 ALOGV("%s locked", __FUNCTION__);
730 module = mModule.promote();
731 if (module == 0) {
732 return NO_INIT;
733 }
734 }
735 return module->getMute(mute);
736}
737
738status_t RadioService::ModuleClient::scan(radio_direction_t direction, bool skipSubChannel)
739{
740 AutoMutex lock(mLock);
741 ALOGV("%s locked", __FUNCTION__);
742 status_t status;
743 if (mTuner != NULL) {
744 status = (status_t)mTuner->scan(mTuner, direction, skipSubChannel);
745 } else {
746 status = INVALID_OPERATION;
747 }
748 return status;
749}
750
751status_t RadioService::ModuleClient::step(radio_direction_t direction, bool skipSubChannel)
752{
753 AutoMutex lock(mLock);
754 ALOGV("%s locked", __FUNCTION__);
755 status_t status;
756 if (mTuner != NULL) {
757 status = (status_t)mTuner->step(mTuner, direction, skipSubChannel);
758 } else {
759 status = INVALID_OPERATION;
760 }
761 return status;
762}
763
764status_t RadioService::ModuleClient::tune(unsigned int channel, unsigned int subChannel)
765{
766 AutoMutex lock(mLock);
767 ALOGV("%s locked", __FUNCTION__);
768 status_t status;
769 if (mTuner != NULL) {
770 status = (status_t)mTuner->tune(mTuner, channel, subChannel);
771 } else {
772 status = INVALID_OPERATION;
773 }
774 return status;
775}
776
777status_t RadioService::ModuleClient::cancel()
778{
779 AutoMutex lock(mLock);
780 ALOGV("%s locked", __FUNCTION__);
781 status_t status;
782 if (mTuner != NULL) {
783 status = (status_t)mTuner->cancel(mTuner);
784 } else {
785 status = INVALID_OPERATION;
786 }
787 return status;
788}
789
790status_t RadioService::ModuleClient::getProgramInformation(struct radio_program_info *info)
791{
792 AutoMutex lock(mLock);
793 ALOGV("%s locked", __FUNCTION__);
794 status_t status;
795 if (mTuner != NULL) {
796 status = (status_t)mTuner->get_program_information(mTuner, info);
797 } else {
798 status = INVALID_OPERATION;
799 }
800 return status;
801}
802
803status_t RadioService::ModuleClient::hasControl(bool *hasControl)
804{
805 Mutex::Autolock lock(mLock);
806 ALOGV("%s locked", __FUNCTION__);
807 *hasControl = mTuner != NULL;
808 return NO_ERROR;
809}
810
811void RadioService::ModuleClient::onCallbackEvent(const sp<IMemory>& eventMemory)
812{
813 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
814 return;
815 }
816
817 sp<IRadioClient> client;
818 {
819 AutoMutex lock(mLock);
820 ALOGV("%s locked", __FUNCTION__);
821 radio_event_t *event = (radio_event_t *)eventMemory->pointer();
822 switch (event->type) {
823 case RADIO_EVENT_CONFIG:
824 mConfig.band = event->config.band;
825 event->config.region = mConfig.region;
826 break;
827 default:
828 break;
829 }
830
831 client = mClient;
832 }
833 if (client != 0) {
834 client->onEvent(eventMemory);
835 }
836}
837
838
839void RadioService::ModuleClient::binderDied(
840 const wp<IBinder> &who __unused) {
841 ALOGW("client binder died for client %p", this);
842 detach();
843}
844
845}; // namespace android