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