• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
28 namespace 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 
A2dpAudioInterface(AudioHardwareInterface * hw)42 A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
43     mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
44 {
45 }
46 
~A2dpAudioInterface()47 A2dpAudioInterface::~A2dpAudioInterface()
48 {
49     closeOutputStream((AudioStreamOut *)mOutput);
50     delete mHardwareInterface;
51 }
52 
initCheck()53 status_t A2dpAudioInterface::initCheck()
54 {
55     if (mHardwareInterface == 0) return NO_INIT;
56     return mHardwareInterface->initCheck();
57 }
58 
openOutputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status)59 AudioStreamOut* 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 
closeOutputStream(AudioStreamOut * out)91 void 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 
openInputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status,AudioSystem::audio_in_acoustics acoustics)102 AudioStreamIn* 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 
closeInputStream(AudioStreamIn * in)109 void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
110 {
111     return mHardwareInterface->closeInputStream(in);
112 }
113 
setMode(int mode)114 status_t A2dpAudioInterface::setMode(int mode)
115 {
116     return mHardwareInterface->setMode(mode);
117 }
118 
setMicMute(bool state)119 status_t A2dpAudioInterface::setMicMute(bool state)
120 {
121     return mHardwareInterface->setMicMute(state);
122 }
123 
getMicMute(bool * state)124 status_t A2dpAudioInterface::getMicMute(bool* state)
125 {
126     return mHardwareInterface->getMicMute(state);
127 }
128 
setParameters(const String8 & keyValuePairs)129 status_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 
getParameters(const String8 & keys)165 String8 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 
getInputBufferSize(uint32_t sampleRate,int format,int channelCount)198 size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
199 {
200     return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
201 }
202 
setVoiceVolume(float v)203 status_t A2dpAudioInterface::setVoiceVolume(float v)
204 {
205     return mHardwareInterface->setVoiceVolume(v);
206 }
207 
setMasterVolume(float v)208 status_t A2dpAudioInterface::setMasterVolume(float v)
209 {
210     return mHardwareInterface->setMasterVolume(v);
211 }
212 
dump(int fd,const Vector<String16> & args)213 status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
214 {
215     return mHardwareInterface->dumpState(fd, args);
216 }
217 
218 // ----------------------------------------------------------------------------
219 
A2dpAudioStreamOut()220 A2dpAudioInterface::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 
set(uint32_t device,int * pFormat,uint32_t * pChannels,uint32_t * pRate)231 status_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 
~A2dpAudioStreamOut()263 A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
264 {
265     LOGV("A2dpAudioStreamOut destructor");
266     standby();
267     close();
268     LOGV("A2dpAudioStreamOut destructor returning from close()");
269 }
270 
write(const void * buffer,size_t bytes)271 ssize_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 
303 Error:
304     // Simulate audio output timing in case of error
305     usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);
306 
307     return status;
308 }
309 
init()310 status_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 
standby()325 status_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 
setParameters(const String8 & keyValuePairs)345 status_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 
getParameters(const String8 & keys)384 String8 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 
setAddress(const char * address)403 status_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 
setBluetoothEnabled(bool enabled)417 status_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 
setSuspended(bool onOff)430 status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
431 {
432     LOGV("setSuspended %d", onOff);
433     mSuspended = onOff;
434     standby();
435     return NO_ERROR;
436 }
437 
close()438 status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
439 {
440     Mutex::Autolock lock(mLock);
441     LOGV("A2dpAudioStreamOut::close() calling close_l()");
442     return close_l();
443 }
444 
close_l()445 status_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 
dump(int fd,const Vector<String16> & args)455 status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
456 {
457     return NO_ERROR;
458 }
459 
getRenderPosition(uint32_t * driverFrames)460 status_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