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
28namespace 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
42A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
43    mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
44{
45}
46
47A2dpAudioInterface::~A2dpAudioInterface()
48{
49    closeOutputStream((AudioStreamOut *)mOutput);
50    delete mHardwareInterface;
51}
52
53status_t A2dpAudioInterface::initCheck()
54{
55    if (mHardwareInterface == 0) return NO_INIT;
56    return mHardwareInterface->initCheck();
57}
58
59AudioStreamOut* 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
91void 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
102AudioStreamIn* 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
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);
117}
118
119status_t A2dpAudioInterface::setMicMute(bool state)
120{
121    return mHardwareInterface->setMicMute(state);
122}
123
124status_t A2dpAudioInterface::getMicMute(bool* state)
125{
126    return mHardwareInterface->getMicMute(state);
127}
128
129status_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
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    }
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        if (keyValuePairs != "") {
189            keyValuePairs += ";";
190        }
191        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);
201}
202
203status_t A2dpAudioInterface::setVoiceVolume(float v)
204{
205    return mHardwareInterface->setVoiceVolume(v);
206}
207
208status_t A2dpAudioInterface::setMasterVolume(float v)
209{
210    return mHardwareInterface->setMasterVolume(v);
211}
212
213status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
214{
215    return mHardwareInterface->dumpState(fd, args);
216}
217
218// ----------------------------------------------------------------------------
219
220A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
221    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
224    mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false)
225{
226    // use any address by default
227    strcpy(mA2dpAddress, "00:00:00:00:00:00");
228    init();
229}
230
231status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
232        uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
233{
234    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);
239
240    // fix up defaults
241    if (lFormat == 0) lFormat = format();
242    if (lChannels == 0) lChannels = channels();
243    if (lRate == 0) lRate = sampleRate();
244
245    // check values
246    if ((lFormat != format()) ||
247            (lChannels != channels()) ||
248            (lRate != sampleRate())){
249        if (pFormat) *pFormat = format();
250        if (pChannels) *pChannels = channels();
251        if (pRate) *pRate = sampleRate();
252        return BAD_VALUE;
253    }
254
255    if (pFormat) *pFormat = lFormat;
256    if (pChannels) *pChannels = lChannels;
257    if (pRate) *pRate = lRate;
258
259    mDevice = device;
260    return NO_ERROR;
261}
262
263A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
264{
265    LOGV("A2dpAudioStreamOut destructor");
266    standby();
267    close();
268    LOGV("A2dpAudioStreamOut destructor returning from close()");
269}
270
271ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
272{
273    Mutex::Autolock lock(mLock);
274
275    size_t remaining = bytes;
276    status_t status = -1;
277
278    if (!mBluetoothEnabled || mClosing || mSuspended) {
279        LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
280               mBluetoothEnabled %d, mClosing %d, mSuspended %d",
281                mBluetoothEnabled, mClosing, mSuspended);
282        goto Error;
283    }
284
285    status = init();
286    if (status < 0)
287        goto Error;
288
289    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;
300
301    return bytes;
302
303Error:
304    // Simulate audio output timing in case of error
305    usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);
306
307    return status;
308}
309
310status_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
325status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
326{
327    int result = 0;
328
329    if (mClosing) {
330        LOGV("Ignore standby, closing");
331        return result;
332    }
333
334    Mutex::Autolock lock(mLock);
335
336    if (!mStandby) {
337        result = a2dp_stop(mData);
338        if (result == 0)
339            mStandby = true;
340    }
341
342    return result;
343}
344
345status_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    }
362    key = String8("closing");
363    if (param.get(key, value) == NO_ERROR) {
364        mClosing = (value == "true");
365        param.remove(key);
366    }
367    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
403status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
404{
405    Mutex::Autolock lock(mLock);
406
407    if (strlen(address) != strlen("00:00:00:00:00:00"))
408        return -EINVAL;
409
410    strcpy(mA2dpAddress, address);
411    if (mData)
412        a2dp_set_sink(mData, mA2dpAddress);
413
414    return NO_ERROR;
415}
416
417status_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
430status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
431{
432    LOGV("setSuspended %d", onOff);
433    mSuspended = onOff;
434    standby();
435    return NO_ERROR;
436}
437
438status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
439{
440    Mutex::Autolock lock(mLock);
441    LOGV("A2dpAudioStreamOut::close() calling close_l()");
442    return close_l();
443}
444
445status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
446{
447    if (mData) {
448        LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
449        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
460status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames)
461{
462    //TODO: enable when supported by driver
463    return INVALID_OPERATION;
464}
465
466}; // namespace android
467