blob: 20db8a5ed700d480644af8e0b9c64f0ca4f6e778 [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
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
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) :
43 mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true)
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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 } else {
82 delete out;
83 }
Eric Laurenta553c252009-07-17 12:17:14 -070084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 if (status)
86 *status = err;
87 return mOutput;
88}
89
Eric Laurenta553c252009-07-17 12:17:14 -070090void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
91 if (mOutput == 0 || mOutput != out) {
Eric Laurent351def22009-08-04 07:43:10 -070092 mHardwareInterface->closeOutputStream(out);
Eric Laurenta553c252009-07-17 12:17:14 -070093 }
94 else {
95 delete mOutput;
96 mOutput = 0;
97 }
98}
99
100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101AudioStreamIn* A2dpAudioInterface::openInputStream(
Eric Laurenta553c252009-07-17 12:17:14 -0700102 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
103 AudioSystem::audio_in_acoustics acoustics)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104{
Eric Laurenta553c252009-07-17 12:17:14 -0700105 return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
106}
107
108void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
109{
110 return mHardwareInterface->closeInputStream(in);
111}
112
113status_t A2dpAudioInterface::setMode(int mode)
114{
115 return mHardwareInterface->setMode(mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
118status_t A2dpAudioInterface::setMicMute(bool state)
119{
Eric Laurenta553c252009-07-17 12:17:14 -0700120 return mHardwareInterface->setMicMute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121}
122
123status_t A2dpAudioInterface::getMicMute(bool* state)
124{
Eric Laurenta553c252009-07-17 12:17:14 -0700125 return mHardwareInterface->getMicMute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126}
127
Eric Laurenta553c252009-07-17 12:17:14 -0700128status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129{
Eric Laurenta553c252009-07-17 12:17:14 -0700130 AudioParameter param = AudioParameter(keyValuePairs);
131 String8 value;
132 String8 key;
133 status_t status = NO_ERROR;
Nick Pelly0827c812009-04-02 01:21:13 -0700134
Eric Laurenta553c252009-07-17 12:17:14 -0700135 LOGV("setParameters() %s", keyValuePairs.string());
Nick Pelly0827c812009-04-02 01:21:13 -0700136
Eric Laurenta553c252009-07-17 12:17:14 -0700137 key = "bluetooth_enabled";
138 if (param.get(key, value) == NO_ERROR) {
139 mBluetoothEnabled = (value == "true");
140 if (mOutput) {
141 mOutput->setBluetoothEnabled(mBluetoothEnabled);
142 }
143 param.remove(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 }
145
Eric Laurenta553c252009-07-17 12:17:14 -0700146 if (param.size()) {
147 status_t hwStatus = mHardwareInterface->setParameters(param.toString());
148 if (status == NO_ERROR) {
149 status = hwStatus;
150 }
151 }
152
153 return status;
154}
155
156String8 A2dpAudioInterface::getParameters(const String8& keys)
157{
158 AudioParameter param = AudioParameter(keys);
159 AudioParameter a2dpParam = AudioParameter();
160 String8 value;
161 String8 key;
162
163 key = "bluetooth_enabled";
164 if (param.get(key, value) == NO_ERROR) {
165 value = mBluetoothEnabled ? "true" : "false";
166 a2dpParam.add(key, value);
167 param.remove(key);
168 }
169
170 String8 keyValuePairs = a2dpParam.toString();
171
172 if (param.size()) {
173 keyValuePairs += ";";
174 keyValuePairs += mHardwareInterface->getParameters(param.toString());
175 }
176
177 LOGV("getParameters() %s", keyValuePairs.string());
178 return keyValuePairs;
179}
180
181size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
182{
183 return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184}
185
186status_t A2dpAudioInterface::setVoiceVolume(float v)
187{
Eric Laurenta553c252009-07-17 12:17:14 -0700188 return mHardwareInterface->setVoiceVolume(v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189}
190
191status_t A2dpAudioInterface::setMasterVolume(float v)
192{
Eric Laurenta553c252009-07-17 12:17:14 -0700193 return mHardwareInterface->setMasterVolume(v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194}
195
196status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
197{
Eric Laurenta553c252009-07-17 12:17:14 -0700198 return mHardwareInterface->dumpState(fd, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199}
200
201// ----------------------------------------------------------------------------
202
203A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
Nick Pelly0827c812009-04-02 01:21:13 -0700204 mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
205 // assume BT enabled to start, this is safe because its only the
206 // enabled->disabled transition we are worried about
Eric Laurenta553c252009-07-17 12:17:14 -0700207 mBluetoothEnabled(true), mDevice(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208{
209 // use any address by default
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700210 strcpy(mA2dpAddress, "00:00:00:00:00:00");
211 init();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212}
213
214status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
Eric Laurenta553c252009-07-17 12:17:14 -0700215 uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216{
Eric Laurenta553c252009-07-17 12:17:14 -0700217 int lFormat = pFormat ? *pFormat : 0;
218 uint32_t lChannels = pChannels ? *pChannels : 0;
219 uint32_t lRate = pRate ? *pRate : 0;
220
221 LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
223 // fix up defaults
Eric Laurenta553c252009-07-17 12:17:14 -0700224 if (lFormat == 0) lFormat = format();
225 if (lChannels == 0) lChannels = channels();
226 if (lRate == 0) lRate = sampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
228 // check values
Eric Laurenta553c252009-07-17 12:17:14 -0700229 if ((lFormat != format()) ||
230 (lChannels != channels()) ||
231 (lRate != sampleRate())){
232 if (pFormat) *pFormat = format();
233 if (pChannels) *pChannels = channels();
234 if (pRate) *pRate = sampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 return BAD_VALUE;
Eric Laurenta553c252009-07-17 12:17:14 -0700236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
Eric Laurenta553c252009-07-17 12:17:14 -0700238 if (pFormat) *pFormat = lFormat;
239 if (pChannels) *pChannels = lChannels;
240 if (pRate) *pRate = lRate;
241
242 mDevice = device;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 return NO_ERROR;
244}
245
246A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
247{
Eric Laurenta553c252009-07-17 12:17:14 -0700248 LOGV("A2dpAudioStreamOut destructor");
249 standby();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 close();
Eric Laurenta553c252009-07-17 12:17:14 -0700251 LOGV("A2dpAudioStreamOut destructor returning from close()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252}
253
254ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
Nick Pelly0827c812009-04-02 01:21:13 -0700255{
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700256 Mutex::Autolock lock(mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700258 size_t remaining = bytes;
Nick Pelly0827c812009-04-02 01:21:13 -0700259 status_t status = -1;
260
261 if (!mBluetoothEnabled) {
262 LOGW("A2dpAudioStreamOut::write(), but bluetooth disabled");
263 goto Error;
264 }
265
266 status = init();
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700267 if (status < 0)
268 goto Error;
Nick Pelly0827c812009-04-02 01:21:13 -0700269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 while (remaining > 0) {
271 status = a2dp_write(mData, buffer, remaining);
272 if (status <= 0) {
273 LOGE("a2dp_write failed err: %d\n", status);
274 goto Error;
275 }
276 remaining -= status;
277 buffer = ((char *)buffer) + status;
278 }
279
280 mStandby = false;
Nick Pelly0827c812009-04-02 01:21:13 -0700281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 return bytes;
283
284Error:
285 // Simulate audio output timing in case of error
286 usleep(bytes * 1000000 / frameSize() / sampleRate());
287
288 return status;
289}
290
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700291status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
292{
293 if (!mData) {
294 status_t status = a2dp_init(44100, 2, &mData);
295 if (status < 0) {
296 LOGE("a2dp_init failed err: %d\n", status);
297 mData = NULL;
298 return status;
299 }
300 a2dp_set_sink(mData, mA2dpAddress);
301 }
302
303 return 0;
304}
305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
307{
308 int result = 0;
309
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700310 Mutex::Autolock lock(mLock);
311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 if (!mStandby) {
313 result = a2dp_stop(mData);
314 if (result == 0)
315 mStandby = true;
316 }
317
318 return result;
319}
320
Eric Laurenta553c252009-07-17 12:17:14 -0700321status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
322{
323 AudioParameter param = AudioParameter(keyValuePairs);
324 String8 value;
325 String8 key = String8("a2dp_sink_address");
326 status_t status = NO_ERROR;
327 int device;
328 LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
329
330 if (param.get(key, value) == NO_ERROR) {
331 if (value.length() != strlen("00:00:00:00:00:00")) {
332 status = BAD_VALUE;
333 } else {
334 setAddress(value.string());
335 }
336 param.remove(key);
337 }
338 key = AudioParameter::keyRouting;
339 if (param.getInt(key, device) == NO_ERROR) {
340 if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
341 mDevice = device;
342 status = NO_ERROR;
343 } else {
344 status = BAD_VALUE;
345 }
346 param.remove(key);
347 }
348
349 if (param.size()) {
350 status = BAD_VALUE;
351 }
352 return status;
353}
354
355String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
356{
357 AudioParameter param = AudioParameter(keys);
358 String8 value;
359 String8 key = String8("a2dp_sink_address");
360
361 if (param.get(key, value) == NO_ERROR) {
362 value = mA2dpAddress;
363 param.add(key, value);
364 }
365 key = AudioParameter::keyRouting;
366 if (param.get(key, value) == NO_ERROR) {
367 param.addInt(key, (int)mDevice);
368 }
369
370 LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
371 return param.toString();
372}
373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
375{
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700376 Mutex::Autolock lock(mLock);
377
378 if (strlen(address) != strlen("00:00:00:00:00:00"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 return -EINVAL;
380
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700381 strcpy(mA2dpAddress, address);
382 if (mData)
383 a2dp_set_sink(mData, mA2dpAddress);
384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 return NO_ERROR;
386}
387
Nick Pelly0827c812009-04-02 01:21:13 -0700388status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled)
389{
390 LOGD("setBluetoothEnabled %d", enabled);
391
392 Mutex::Autolock lock(mLock);
393
394 mBluetoothEnabled = enabled;
395 if (!enabled) {
396 return close_l();
397 }
398 return NO_ERROR;
399}
400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
402{
Nick Pelly0827c812009-04-02 01:21:13 -0700403 Mutex::Autolock lock(mLock);
Eric Laurenta553c252009-07-17 12:17:14 -0700404 LOGV("A2dpAudioStreamOut::close() calling close_l()");
Nick Pelly0827c812009-04-02 01:21:13 -0700405 return close_l();
406}
407
408status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
409{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 if (mData) {
Eric Laurenta553c252009-07-17 12:17:14 -0700411 LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 a2dp_cleanup(mData);
413 mData = NULL;
414 }
415 return NO_ERROR;
416}
417
418status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
419{
420 return NO_ERROR;
421}
422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423}; // namespace android