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