OSDN Git Service

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