1 /*
2 **
3 ** Copyright (C) 2015, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #define LOG_TAG "Radio"
19 //#define LOG_NDEBUG 0
20
21 #include <utils/Log.h>
22 #include <utils/threads.h>
23 #include <binder/IPCThreadState.h>
24 #include <binder/IServiceManager.h>
25 #include <binder/IMemory.h>
26
27 #include <radio/Radio.h>
28 #include <radio/IRadio.h>
29 #include <radio/IRadioService.h>
30 #include <radio/IRadioClient.h>
31 #include <radio/RadioCallback.h>
32
33 namespace android {
34
35 namespace {
36 sp<IRadioService> gRadioService;
37 const int kRadioServicePollDelay = 500000; // 0.5s
38 const char* kRadioServiceName = "media.radio";
39 Mutex gLock;
40
41 class DeathNotifier : public IBinder::DeathRecipient
42 {
43 public:
DeathNotifier()44 DeathNotifier() {
45 }
46
binderDied(const wp<IBinder> & who __unused)47 virtual void binderDied(const wp<IBinder>& who __unused) {
48 ALOGV("binderDied");
49 Mutex::Autolock _l(gLock);
50 gRadioService.clear();
51 ALOGW("Radio service died!");
52 }
53 };
54
55 sp<DeathNotifier> gDeathNotifier;
56 }; // namespace anonymous
57
getRadioService()58 const sp<IRadioService> Radio::getRadioService()
59 {
60 Mutex::Autolock _l(gLock);
61 if (gRadioService.get() == 0) {
62 sp<IServiceManager> sm = defaultServiceManager();
63 sp<IBinder> binder;
64 do {
65 binder = sm->getService(String16(kRadioServiceName));
66 if (binder != 0) {
67 break;
68 }
69 ALOGW("RadioService not published, waiting...");
70 usleep(kRadioServicePollDelay);
71 } while(true);
72 if (gDeathNotifier == NULL) {
73 gDeathNotifier = new DeathNotifier();
74 }
75 binder->linkToDeath(gDeathNotifier);
76 gRadioService = interface_cast<IRadioService>(binder);
77 }
78 ALOGE_IF(gRadioService == 0, "no RadioService!?");
79 return gRadioService;
80 }
81
82 // Static methods
listModules(struct radio_properties * properties,uint32_t * numModules)83 status_t Radio::listModules(struct radio_properties *properties,
84 uint32_t *numModules)
85 {
86 ALOGV("listModules()");
87 const sp<IRadioService> service = getRadioService();
88 if (service == 0) {
89 return NO_INIT;
90 }
91 return service->listModules(properties, numModules);
92 }
93
attach(radio_handle_t handle,const struct radio_band_config * config,bool withAudio,const sp<RadioCallback> & callback)94 sp<Radio> Radio::attach(radio_handle_t handle,
95 const struct radio_band_config *config,
96 bool withAudio,
97 const sp<RadioCallback>& callback)
98 {
99 ALOGV("attach()");
100 sp<Radio> radio;
101 const sp<IRadioService> service = getRadioService();
102 if (service == 0) {
103 return radio;
104 }
105 radio = new Radio(handle, callback);
106 status_t status = service->attach(handle, radio, config, withAudio, radio->mIRadio);
107
108 if (status == NO_ERROR && radio->mIRadio != 0) {
109 IInterface::asBinder(radio->mIRadio)->linkToDeath(radio);
110 } else {
111 ALOGW("Error %d connecting to radio service", status);
112 radio.clear();
113 }
114 return radio;
115 }
116
117
118
119 // Radio
Radio(radio_handle_t handle,const sp<RadioCallback> & callback)120 Radio::Radio(radio_handle_t handle, const sp<RadioCallback>& callback)
121 : mHandle(handle), mCallback(callback)
122 {
123 }
124
~Radio()125 Radio::~Radio()
126 {
127 if (mIRadio != 0) {
128 mIRadio->detach();
129 }
130 }
131
132
detach()133 void Radio::detach() {
134 ALOGV("detach()");
135 Mutex::Autolock _l(mLock);
136 mCallback.clear();
137 if (mIRadio != 0) {
138 mIRadio->detach();
139 IInterface::asBinder(mIRadio)->unlinkToDeath(this);
140 mIRadio = 0;
141 }
142 }
143
setConfiguration(const struct radio_band_config * config)144 status_t Radio::setConfiguration(const struct radio_band_config *config)
145 {
146 Mutex::Autolock _l(mLock);
147 if (mIRadio == 0) {
148 return NO_INIT;
149 }
150 return mIRadio->setConfiguration(config);
151 }
152
getConfiguration(struct radio_band_config * config)153 status_t Radio::getConfiguration(struct radio_band_config *config)
154 {
155 Mutex::Autolock _l(mLock);
156 if (mIRadio == 0) {
157 return NO_INIT;
158 }
159 return mIRadio->getConfiguration(config);
160 }
161
setMute(bool mute)162 status_t Radio::setMute(bool mute)
163 {
164 Mutex::Autolock _l(mLock);
165 if (mIRadio == 0) {
166 return NO_INIT;
167 }
168 return mIRadio->setMute(mute);
169 }
170
getMute(bool * mute)171 status_t Radio::getMute(bool *mute)
172 {
173 Mutex::Autolock _l(mLock);
174 if (mIRadio == 0) {
175 return NO_INIT;
176 }
177 return mIRadio->getMute(mute);
178 }
179
scan(radio_direction_t direction,bool skipSubchannel)180 status_t Radio::scan(radio_direction_t direction, bool skipSubchannel)
181 {
182 Mutex::Autolock _l(mLock);
183 if (mIRadio == 0) {
184 return NO_INIT;
185 }
186 return mIRadio->scan(direction, skipSubchannel);
187 }
188
step(radio_direction_t direction,bool skipSubchannel)189 status_t Radio::step(radio_direction_t direction, bool skipSubchannel)
190 {
191 Mutex::Autolock _l(mLock);
192 if (mIRadio == 0) {
193 return NO_INIT;
194 }
195 return mIRadio->step(direction, skipSubchannel);
196 }
197
tune(unsigned int channel,unsigned int subChannel)198 status_t Radio::tune(unsigned int channel, unsigned int subChannel)
199 {
200 Mutex::Autolock _l(mLock);
201 if (mIRadio == 0) {
202 return NO_INIT;
203 }
204 return mIRadio->tune(channel, subChannel);
205 }
206
cancel()207 status_t Radio::cancel()
208 {
209 Mutex::Autolock _l(mLock);
210 if (mIRadio == 0) {
211 return NO_INIT;
212 }
213 return mIRadio->cancel();
214 }
215
getProgramInformation(struct radio_program_info * info)216 status_t Radio::getProgramInformation(struct radio_program_info *info)
217 {
218 Mutex::Autolock _l(mLock);
219 if (mIRadio == 0) {
220 return NO_INIT;
221 }
222 return mIRadio->getProgramInformation(info);
223 }
224
hasControl(bool * hasControl)225 status_t Radio::hasControl(bool *hasControl)
226 {
227 Mutex::Autolock _l(mLock);
228 if (mIRadio == 0) {
229 return NO_INIT;
230 }
231 return mIRadio->hasControl(hasControl);
232 }
233
234
235 // BpRadioClient
onEvent(const sp<IMemory> & eventMemory)236 void Radio::onEvent(const sp<IMemory>& eventMemory)
237 {
238 Mutex::Autolock _l(mLock);
239 if (eventMemory == 0 || eventMemory->pointer() == NULL) {
240 return;
241 }
242
243 struct radio_event *event = (struct radio_event *)eventMemory->pointer();
244 // restore local metadata pointer from offset
245 switch (event->type) {
246 case RADIO_EVENT_TUNED:
247 case RADIO_EVENT_AF_SWITCH:
248 if (event->info.metadata != NULL) {
249 event->info.metadata =
250 (radio_metadata_t *)((char *)event + (size_t)event->info.metadata);
251 }
252 break;
253 case RADIO_EVENT_METADATA:
254 if (event->metadata != NULL) {
255 event->metadata =
256 (radio_metadata_t *)((char *)event + (size_t)event->metadata);
257 }
258 break;
259 default:
260 break;
261 }
262
263 if (mCallback != 0) {
264 mCallback->onEvent(event);
265 }
266 }
267
268
269 //IBinder::DeathRecipient
binderDied(const wp<IBinder> & who __unused)270 void Radio::binderDied(const wp<IBinder>& who __unused) {
271 Mutex::Autolock _l(mLock);
272 ALOGW("Radio server binder Died ");
273 mIRadio = 0;
274 struct radio_event event;
275 memset(&event, 0, sizeof(struct radio_event));
276 event.type = RADIO_EVENT_SERVER_DIED;
277 event.status = DEAD_OBJECT;
278 if (mCallback != 0) {
279 mCallback->onEvent(&event);
280 }
281 }
282
283 }; // namespace android
284