1 /*
2 * Copyright (C) 2008 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 #include <math.h>
18
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "A2dpAudioInterface"
21 #include <utils/Log.h>
22 #include <utils/String8.h>
23
24 #include "A2dpAudioInterface.h"
25 #include "audio/liba2dp.h"
26
27
28 namespace android {
29
30 // ----------------------------------------------------------------------------
31
32 //AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
33 //{
34 // AudioHardwareInterface* hw = 0;
35 //
36 // hw = AudioHardwareInterface::create();
37 // LOGD("new A2dpAudioInterface(hw: %p)", hw);
38 // hw = new A2dpAudioInterface(hw);
39 // return hw;
40 //}
41
A2dpAudioInterface(AudioHardwareInterface * hw)42 A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
43 mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
44 {
45 }
46
~A2dpAudioInterface()47 A2dpAudioInterface::~A2dpAudioInterface()
48 {
49 closeOutputStream((AudioStreamOut *)mOutput);
50 delete mHardwareInterface;
51 }
52
initCheck()53 status_t A2dpAudioInterface::initCheck()
54 {
55 if (mHardwareInterface == 0) return NO_INIT;
56 return mHardwareInterface->initCheck();
57 }
58
openOutputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status)59 AudioStreamOut* A2dpAudioInterface::openOutputStream(
60 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
61 {
62 if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
63 LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
64 return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
65 }
66
67 status_t err = 0;
68
69 // only one output stream allowed
70 if (mOutput) {
71 if (status)
72 *status = -1;
73 return NULL;
74 }
75
76 // create new output stream
77 A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
78 if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
79 mOutput = out;
80 mOutput->setBluetoothEnabled(mBluetoothEnabled);
81 mOutput->setSuspended(mSuspended);
82 } else {
83 delete out;
84 }
85
86 if (status)
87 *status = err;
88 return mOutput;
89 }
90
closeOutputStream(AudioStreamOut * out)91 void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
92 if (mOutput == 0 || mOutput != out) {
93 mHardwareInterface->closeOutputStream(out);
94 }
95 else {
96 delete mOutput;
97 mOutput = 0;
98 }
99 }
100
101
openInputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status,AudioSystem::audio_in_acoustics acoustics)102 AudioStreamIn* A2dpAudioInterface::openInputStream(
103 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
104 AudioSystem::audio_in_acoustics acoustics)
105 {
106 return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
107 }
108
closeInputStream(AudioStreamIn * in)109 void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
110 {
111 return mHardwareInterface->closeInputStream(in);
112 }
113
setMode(int mode)114 status_t A2dpAudioInterface::setMode(int mode)
115 {
116 return mHardwareInterface->setMode(mode);
117 }
118
setMicMute(bool state)119 status_t A2dpAudioInterface::setMicMute(bool state)
120 {
121 return mHardwareInterface->setMicMute(state);
122 }
123
getMicMute(bool * state)124 status_t A2dpAudioInterface::getMicMute(bool* state)
125 {
126 return mHardwareInterface->getMicMute(state);
127 }
128
setParameters(const String8 & keyValuePairs)129 status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
130 {
131 AudioParameter param = AudioParameter(keyValuePairs);
132 String8 value;
133 String8 key;
134 status_t status = NO_ERROR;
135
136 LOGV("setParameters() %s", keyValuePairs.string());
137
138 key = "bluetooth_enabled";
139 if (param.get(key, value) == NO_ERROR) {
140 mBluetoothEnabled = (value == "true");
141 if (mOutput) {
142 mOutput->setBluetoothEnabled(mBluetoothEnabled);
143 }
144 param.remove(key);
145 }
146 key = String8("A2dpSuspended");
147 if (param.get(key, value) == NO_ERROR) {
148 mSuspended = (value == "true");
149 if (mOutput) {
150 mOutput->setSuspended(mSuspended);
151 }
152 param.remove(key);
153 }
154
155 if (param.size()) {
156 status_t hwStatus = mHardwareInterface->setParameters(param.toString());
157 if (status == NO_ERROR) {
158 status = hwStatus;
159 }
160 }
161
162 return status;
163 }
164
getParameters(const String8 & keys)165 String8 A2dpAudioInterface::getParameters(const String8& keys)
166 {
167 AudioParameter param = AudioParameter(keys);
168 AudioParameter a2dpParam = AudioParameter();
169 String8 value;
170 String8 key;
171
172 key = "bluetooth_enabled";
173 if (param.get(key, value) == NO_ERROR) {
174 value = mBluetoothEnabled ? "true" : "false";
175 a2dpParam.add(key, value);
176 param.remove(key);
177 }
178 key = "A2dpSuspended";
179 if (param.get(key, value) == NO_ERROR) {
180 value = mSuspended ? "true" : "false";
181 a2dpParam.add(key, value);
182 param.remove(key);
183 }
184
185 String8 keyValuePairs = a2dpParam.toString();
186
187 if (param.size()) {
188 keyValuePairs += ";";
189 keyValuePairs += mHardwareInterface->getParameters(param.toString());
190 }
191
192 LOGV("getParameters() %s", keyValuePairs.string());
193 return keyValuePairs;
194 }
195
getInputBufferSize(uint32_t sampleRate,int format,int channelCount)196 size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
197 {
198 return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
199 }
200
setVoiceVolume(float v)201 status_t A2dpAudioInterface::setVoiceVolume(float v)
202 {
203 return mHardwareInterface->setVoiceVolume(v);
204 }
205
setMasterVolume(float v)206 status_t A2dpAudioInterface::setMasterVolume(float v)
207 {
208 return mHardwareInterface->setMasterVolume(v);
209 }
210
dump(int fd,const Vector<String16> & args)211 status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
212 {
213 return mHardwareInterface->dumpState(fd, args);
214 }
215
216 // ----------------------------------------------------------------------------
217
A2dpAudioStreamOut()218 A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
219 mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
220 // assume BT enabled to start, this is safe because its only the
221 // enabled->disabled transition we are worried about
222 mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false)
223 {
224 // use any address by default
225 strcpy(mA2dpAddress, "00:00:00:00:00:00");
226 init();
227 }
228
set(uint32_t device,int * pFormat,uint32_t * pChannels,uint32_t * pRate)229 status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
230 uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
231 {
232 int lFormat = pFormat ? *pFormat : 0;
233 uint32_t lChannels = pChannels ? *pChannels : 0;
234 uint32_t lRate = pRate ? *pRate : 0;
235
236 LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
237
238 // fix up defaults
239 if (lFormat == 0) lFormat = format();
240 if (lChannels == 0) lChannels = channels();
241 if (lRate == 0) lRate = sampleRate();
242
243 // check values
244 if ((lFormat != format()) ||
245 (lChannels != channels()) ||
246 (lRate != sampleRate())){
247 if (pFormat) *pFormat = format();
248 if (pChannels) *pChannels = channels();
249 if (pRate) *pRate = sampleRate();
250 return BAD_VALUE;
251 }
252
253 if (pFormat) *pFormat = lFormat;
254 if (pChannels) *pChannels = lChannels;
255 if (pRate) *pRate = lRate;
256
257 mDevice = device;
258 return NO_ERROR;
259 }
260
~A2dpAudioStreamOut()261 A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
262 {
263 LOGV("A2dpAudioStreamOut destructor");
264 standby();
265 close();
266 LOGV("A2dpAudioStreamOut destructor returning from close()");
267 }
268
write(const void * buffer,size_t bytes)269 ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
270 {
271 Mutex::Autolock lock(mLock);
272
273 size_t remaining = bytes;
274 status_t status = -1;
275
276 if (!mBluetoothEnabled || mClosing || mSuspended) {
277 LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
278 mBluetoothEnabled %d, mClosing %d, mSuspended %d",
279 mBluetoothEnabled, mClosing, mSuspended);
280 goto Error;
281 }
282
283 status = init();
284 if (status < 0)
285 goto Error;
286
287 while (remaining > 0) {
288 status = a2dp_write(mData, buffer, remaining);
289 if (status <= 0) {
290 LOGE("a2dp_write failed err: %d\n", status);
291 goto Error;
292 }
293 remaining -= status;
294 buffer = ((char *)buffer) + status;
295 }
296
297 mStandby = false;
298
299 return bytes;
300
301 Error:
302 // Simulate audio output timing in case of error
303 usleep(bytes * 1000000 / frameSize() / sampleRate());
304
305 return status;
306 }
307
init()308 status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
309 {
310 if (!mData) {
311 status_t status = a2dp_init(44100, 2, &mData);
312 if (status < 0) {
313 LOGE("a2dp_init failed err: %d\n", status);
314 mData = NULL;
315 return status;
316 }
317 a2dp_set_sink(mData, mA2dpAddress);
318 }
319
320 return 0;
321 }
322
standby()323 status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
324 {
325 int result = 0;
326
327 if (mClosing) {
328 LOGV("Ignore standby, closing");
329 return result;
330 }
331
332 Mutex::Autolock lock(mLock);
333
334 if (!mStandby) {
335 result = a2dp_stop(mData);
336 if (result == 0)
337 mStandby = true;
338 }
339
340 return result;
341 }
342
setParameters(const String8 & keyValuePairs)343 status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
344 {
345 AudioParameter param = AudioParameter(keyValuePairs);
346 String8 value;
347 String8 key = String8("a2dp_sink_address");
348 status_t status = NO_ERROR;
349 int device;
350 LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
351
352 if (param.get(key, value) == NO_ERROR) {
353 if (value.length() != strlen("00:00:00:00:00:00")) {
354 status = BAD_VALUE;
355 } else {
356 setAddress(value.string());
357 }
358 param.remove(key);
359 }
360 key = String8("closing");
361 if (param.get(key, value) == NO_ERROR) {
362 mClosing = (value == "true");
363 param.remove(key);
364 }
365 key = AudioParameter::keyRouting;
366 if (param.getInt(key, device) == NO_ERROR) {
367 if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
368 mDevice = device;
369 status = NO_ERROR;
370 } else {
371 status = BAD_VALUE;
372 }
373 param.remove(key);
374 }
375
376 if (param.size()) {
377 status = BAD_VALUE;
378 }
379 return status;
380 }
381
getParameters(const String8 & keys)382 String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
383 {
384 AudioParameter param = AudioParameter(keys);
385 String8 value;
386 String8 key = String8("a2dp_sink_address");
387
388 if (param.get(key, value) == NO_ERROR) {
389 value = mA2dpAddress;
390 param.add(key, value);
391 }
392 key = AudioParameter::keyRouting;
393 if (param.get(key, value) == NO_ERROR) {
394 param.addInt(key, (int)mDevice);
395 }
396
397 LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
398 return param.toString();
399 }
400
setAddress(const char * address)401 status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
402 {
403 Mutex::Autolock lock(mLock);
404
405 if (strlen(address) != strlen("00:00:00:00:00:00"))
406 return -EINVAL;
407
408 strcpy(mA2dpAddress, address);
409 if (mData)
410 a2dp_set_sink(mData, mA2dpAddress);
411
412 return NO_ERROR;
413 }
414
setBluetoothEnabled(bool enabled)415 status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled)
416 {
417 LOGD("setBluetoothEnabled %d", enabled);
418
419 Mutex::Autolock lock(mLock);
420
421 mBluetoothEnabled = enabled;
422 if (!enabled) {
423 return close_l();
424 }
425 return NO_ERROR;
426 }
427
setSuspended(bool onOff)428 status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
429 {
430 LOGV("setSuspended %d", onOff);
431 mSuspended = onOff;
432 standby();
433 return NO_ERROR;
434 }
435
close()436 status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
437 {
438 Mutex::Autolock lock(mLock);
439 LOGV("A2dpAudioStreamOut::close() calling close_l()");
440 return close_l();
441 }
442
close_l()443 status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
444 {
445 if (mData) {
446 LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
447 a2dp_cleanup(mData);
448 mData = NULL;
449 }
450 return NO_ERROR;
451 }
452
dump(int fd,const Vector<String16> & args)453 status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
454 {
455 return NO_ERROR;
456 }
457
458 }; // namespace android
459