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