blob: 995e31ca0797089e72897f57c93447939884b588 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Eric Laurent80a6a222009-10-08 10:58:19 -070019//#define LOG_NDEBUG 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020#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
28namespace android {
29
30// ----------------------------------------------------------------------------
31
Eric Laurenta553c252009-07-17 12:17:14 -070032//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
42A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
Eric Laurent80a6a222009-10-08 10:58:19 -070043 mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044{
45}
46
47A2dpAudioInterface::~A2dpAudioInterface()
48{
Eric Laurenta553c252009-07-17 12:17:14 -070049 closeOutputStream((AudioStreamOut *)mOutput);
50 delete mHardwareInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051}
52
53status_t A2dpAudioInterface::initCheck()
54{
Eric Laurenta553c252009-07-17 12:17:14 -070055 if (mHardwareInterface == 0) return NO_INIT;
56 return mHardwareInterface->initCheck();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057}
58
59AudioStreamOut* A2dpAudioInterface::openOutputStream(
Eric Laurenta553c252009-07-17 12:17:14 -070060 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061{
Eric Laurenta553c252009-07-17 12:17:14 -070062 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 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();
Eric Laurenta553c252009-07-17 12:17:14 -070078 if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 mOutput = out;
Eric Laurenta553c252009-07-17 12:17:14 -070080 mOutput->setBluetoothEnabled(mBluetoothEnabled);
Eric Laurent80a6a222009-10-08 10:58:19 -070081 mOutput->setSuspended(mSuspended);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 } else {
83 delete out;
84 }
Eric Laurenta553c252009-07-17 12:17:14 -070085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 if (status)
87 *status = err;
88 return mOutput;
89}
90
Eric Laurenta553c252009-07-17 12:17:14 -070091void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
92 if (mOutput == 0 || mOutput != out) {
Eric Laurent351def22009-08-04 07:43:10 -070093 mHardwareInterface->closeOutputStream(out);
Eric Laurenta553c252009-07-17 12:17:14 -070094 }
95 else {
96 delete mOutput;
97 mOutput = 0;
98 }
99}
100
101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102AudioStreamIn* A2dpAudioInterface::openInputStream(
Eric Laurenta553c252009-07-17 12:17:14 -0700103 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
104 AudioSystem::audio_in_acoustics acoustics)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105{
Eric Laurenta553c252009-07-17 12:17:14 -0700106 return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
107}
108
109void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
110{
111 return mHardwareInterface->closeInputStream(in);
112}
113
114status_t A2dpAudioInterface::setMode(int mode)
115{
116 return mHardwareInterface->setMode(mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117}
118
119status_t A2dpAudioInterface::setMicMute(bool state)
120{
Eric Laurenta553c252009-07-17 12:17:14 -0700121 return mHardwareInterface->setMicMute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122}
123
124status_t A2dpAudioInterface::getMicMute(bool* state)
125{
Eric Laurenta553c252009-07-17 12:17:14 -0700126 return mHardwareInterface->getMicMute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127}
128
Eric Laurenta553c252009-07-17 12:17:14 -0700129status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130{
Eric Laurenta553c252009-07-17 12:17:14 -0700131 AudioParameter param = AudioParameter(keyValuePairs);
132 String8 value;
133 String8 key;
134 status_t status = NO_ERROR;
Nick Pelly0827c812009-04-02 01:21:13 -0700135
Eric Laurenta553c252009-07-17 12:17:14 -0700136 LOGV("setParameters() %s", keyValuePairs.string());
Nick Pelly0827c812009-04-02 01:21:13 -0700137
Eric Laurenta553c252009-07-17 12:17:14 -0700138 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 }
Eric Laurent80a6a222009-10-08 10:58:19 -0700146 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Eric Laurenta553c252009-07-17 12:17:14 -0700155 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
165String8 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 }
Eric Laurent80a6a222009-10-08 10:58:19 -0700178 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 }
Eric Laurenta553c252009-07-17 12:17:14 -0700184
185 String8 keyValuePairs = a2dpParam.toString();
186
187 if (param.size()) {
Eric Laurent4ad9ec42009-11-25 06:08:44 -0800188 if (keyValuePairs != "") {
189 keyValuePairs += ";";
190 }
Eric Laurenta553c252009-07-17 12:17:14 -0700191 keyValuePairs += mHardwareInterface->getParameters(param.toString());
192 }
193
194 LOGV("getParameters() %s", keyValuePairs.string());
195 return keyValuePairs;
196}
197
198size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
199{
200 return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201}
202
203status_t A2dpAudioInterface::setVoiceVolume(float v)
204{
Eric Laurenta553c252009-07-17 12:17:14 -0700205 return mHardwareInterface->setVoiceVolume(v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206}
207
208status_t A2dpAudioInterface::setMasterVolume(float v)
209{
Eric Laurenta553c252009-07-17 12:17:14 -0700210 return mHardwareInterface->setMasterVolume(v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211}
212
213status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
214{
Eric Laurenta553c252009-07-17 12:17:14 -0700215 return mHardwareInterface->dumpState(fd, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216}
217
218// ----------------------------------------------------------------------------
219
220A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
Nick Pelly0827c812009-04-02 01:21:13 -0700221 mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
222 // assume BT enabled to start, this is safe because its only the
223 // enabled->disabled transition we are worried about
Eric Laurent80a6a222009-10-08 10:58:19 -0700224 mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225{
226 // use any address by default
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700227 strcpy(mA2dpAddress, "00:00:00:00:00:00");
228 init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229}
230
231status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
Eric Laurenta553c252009-07-17 12:17:14 -0700232 uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233{
Eric Laurenta553c252009-07-17 12:17:14 -0700234 int lFormat = pFormat ? *pFormat : 0;
235 uint32_t lChannels = pChannels ? *pChannels : 0;
236 uint32_t lRate = pRate ? *pRate : 0;
237
238 LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 // fix up defaults
Eric Laurenta553c252009-07-17 12:17:14 -0700241 if (lFormat == 0) lFormat = format();
242 if (lChannels == 0) lChannels = channels();
243 if (lRate == 0) lRate = sampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244
245 // check values
Eric Laurenta553c252009-07-17 12:17:14 -0700246 if ((lFormat != format()) ||
247 (lChannels != channels()) ||
248 (lRate != sampleRate())){
249 if (pFormat) *pFormat = format();
250 if (pChannels) *pChannels = channels();
251 if (pRate) *pRate = sampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 return BAD_VALUE;
Eric Laurenta553c252009-07-17 12:17:14 -0700253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254
Eric Laurenta553c252009-07-17 12:17:14 -0700255 if (pFormat) *pFormat = lFormat;
256 if (pChannels) *pChannels = lChannels;
257 if (pRate) *pRate = lRate;
258
259 mDevice = device;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 return NO_ERROR;
261}
262
263A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
264{
Eric Laurenta553c252009-07-17 12:17:14 -0700265 LOGV("A2dpAudioStreamOut destructor");
266 standby();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 close();
Eric Laurenta553c252009-07-17 12:17:14 -0700268 LOGV("A2dpAudioStreamOut destructor returning from close()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269}
270
271ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
Nick Pelly0827c812009-04-02 01:21:13 -0700272{
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700273 Mutex::Autolock lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700275 size_t remaining = bytes;
Nick Pelly0827c812009-04-02 01:21:13 -0700276 status_t status = -1;
277
Eric Laurent80a6a222009-10-08 10:58:19 -0700278 if (!mBluetoothEnabled || mClosing || mSuspended) {
279 LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
280 mBluetoothEnabled %d, mClosing %d, mSuspended %d",
281 mBluetoothEnabled, mClosing, mSuspended);
Nick Pelly0827c812009-04-02 01:21:13 -0700282 goto Error;
283 }
284
285 status = init();
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700286 if (status < 0)
287 goto Error;
Nick Pelly0827c812009-04-02 01:21:13 -0700288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 while (remaining > 0) {
290 status = a2dp_write(mData, buffer, remaining);
291 if (status <= 0) {
292 LOGE("a2dp_write failed err: %d\n", status);
293 goto Error;
294 }
295 remaining -= status;
296 buffer = ((char *)buffer) + status;
297 }
298
299 mStandby = false;
Nick Pelly0827c812009-04-02 01:21:13 -0700300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 return bytes;
302
303Error:
304 // Simulate audio output timing in case of error
Jean-Michel Trivi2f22d352010-04-20 12:12:13 -0700305 usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306
307 return status;
308}
309
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700310status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
311{
312 if (!mData) {
313 status_t status = a2dp_init(44100, 2, &mData);
314 if (status < 0) {
315 LOGE("a2dp_init failed err: %d\n", status);
316 mData = NULL;
317 return status;
318 }
319 a2dp_set_sink(mData, mA2dpAddress);
320 }
321
322 return 0;
323}
324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
326{
327 int result = 0;
328
Eric Laurentfe4fc912009-08-12 05:49:58 -0700329 if (mClosing) {
330 LOGV("Ignore standby, closing");
331 return result;
332 }
333
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700334 Mutex::Autolock lock(mLock);
335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 if (!mStandby) {
337 result = a2dp_stop(mData);
338 if (result == 0)
339 mStandby = true;
340 }
341
342 return result;
343}
344
Eric Laurenta553c252009-07-17 12:17:14 -0700345status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
346{
347 AudioParameter param = AudioParameter(keyValuePairs);
348 String8 value;
349 String8 key = String8("a2dp_sink_address");
350 status_t status = NO_ERROR;
351 int device;
352 LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
353
354 if (param.get(key, value) == NO_ERROR) {
355 if (value.length() != strlen("00:00:00:00:00:00")) {
356 status = BAD_VALUE;
357 } else {
358 setAddress(value.string());
359 }
360 param.remove(key);
361 }
Eric Laurentfe4fc912009-08-12 05:49:58 -0700362 key = String8("closing");
363 if (param.get(key, value) == NO_ERROR) {
364 mClosing = (value == "true");
365 param.remove(key);
366 }
Eric Laurenta553c252009-07-17 12:17:14 -0700367 key = AudioParameter::keyRouting;
368 if (param.getInt(key, device) == NO_ERROR) {
369 if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
370 mDevice = device;
371 status = NO_ERROR;
372 } else {
373 status = BAD_VALUE;
374 }
375 param.remove(key);
376 }
377
378 if (param.size()) {
379 status = BAD_VALUE;
380 }
381 return status;
382}
383
384String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
385{
386 AudioParameter param = AudioParameter(keys);
387 String8 value;
388 String8 key = String8("a2dp_sink_address");
389
390 if (param.get(key, value) == NO_ERROR) {
391 value = mA2dpAddress;
392 param.add(key, value);
393 }
394 key = AudioParameter::keyRouting;
395 if (param.get(key, value) == NO_ERROR) {
396 param.addInt(key, (int)mDevice);
397 }
398
399 LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
400 return param.toString();
401}
402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
404{
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700405 Mutex::Autolock lock(mLock);
406
407 if (strlen(address) != strlen("00:00:00:00:00:00"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 return -EINVAL;
409
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700410 strcpy(mA2dpAddress, address);
411 if (mData)
412 a2dp_set_sink(mData, mA2dpAddress);
413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 return NO_ERROR;
415}
416
Nick Pelly0827c812009-04-02 01:21:13 -0700417status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled)
418{
419 LOGD("setBluetoothEnabled %d", enabled);
420
421 Mutex::Autolock lock(mLock);
422
423 mBluetoothEnabled = enabled;
424 if (!enabled) {
425 return close_l();
426 }
427 return NO_ERROR;
428}
429
Eric Laurent80a6a222009-10-08 10:58:19 -0700430status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
431{
432 LOGV("setSuspended %d", onOff);
433 mSuspended = onOff;
434 standby();
435 return NO_ERROR;
436}
437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
439{
Nick Pelly0827c812009-04-02 01:21:13 -0700440 Mutex::Autolock lock(mLock);
Eric Laurenta553c252009-07-17 12:17:14 -0700441 LOGV("A2dpAudioStreamOut::close() calling close_l()");
Nick Pelly0827c812009-04-02 01:21:13 -0700442 return close_l();
443}
444
445status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
446{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 if (mData) {
Eric Laurenta553c252009-07-17 12:17:14 -0700448 LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 a2dp_cleanup(mData);
450 mData = NULL;
451 }
452 return NO_ERROR;
453}
454
455status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
456{
457 return NO_ERROR;
458}
459
Eric Laurent0986e792010-01-19 17:37:09 -0800460status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames)
461{
462 //TODO: enable when supported by driver
463 return INVALID_OPERATION;
464}
465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466}; // namespace android