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