• 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  #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  
A2dpAudioInterface(AudioHardwareInterface * hw)46  A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
47      mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
48  {
49  }
50  
~A2dpAudioInterface()51  A2dpAudioInterface::~A2dpAudioInterface()
52  {
53      closeOutputStream((AudioStreamOut *)mOutput);
54      delete mHardwareInterface;
55  }
56  
initCheck()57  status_t A2dpAudioInterface::initCheck()
58  {
59      if (mHardwareInterface == 0) return NO_INIT;
60      return mHardwareInterface->initCheck();
61  }
62  
openOutputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status)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_out_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  
closeOutputStream(AudioStreamOut * out)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  
openInputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status,AudioSystem::audio_in_acoustics acoustics)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  
closeInputStream(AudioStreamIn * in)113  void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
114  {
115      return mHardwareInterface->closeInputStream(in);
116  }
117  
setMode(int mode)118  status_t A2dpAudioInterface::setMode(int mode)
119  {
120      return mHardwareInterface->setMode(mode);
121  }
122  
setMicMute(bool state)123  status_t A2dpAudioInterface::setMicMute(bool state)
124  {
125      return mHardwareInterface->setMicMute(state);
126  }
127  
getMicMute(bool * state)128  status_t A2dpAudioInterface::getMicMute(bool* state)
129  {
130      return mHardwareInterface->getMicMute(state);
131  }
132  
setParameters(const String8 & keyValuePairs)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  
getParameters(const String8 & keys)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  
getInputBufferSize(uint32_t sampleRate,int format,int channelCount)202  size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
203  {
204      return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
205  }
206  
setVoiceVolume(float v)207  status_t A2dpAudioInterface::setVoiceVolume(float v)
208  {
209      return mHardwareInterface->setVoiceVolume(v);
210  }
211  
setMasterVolume(float v)212  status_t A2dpAudioInterface::setMasterVolume(float v)
213  {
214      return mHardwareInterface->setMasterVolume(v);
215  }
216  
dump(int fd,const Vector<String16> & args)217  status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
218  {
219      return mHardwareInterface->dumpState(fd, args);
220  }
221  
222  // ----------------------------------------------------------------------------
223  
A2dpAudioStreamOut()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  
set(uint32_t device,int * pFormat,uint32_t * pChannels,uint32_t * pRate)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  
~A2dpAudioStreamOut()268  A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
269  {
270      ALOGV("A2dpAudioStreamOut destructor");
271      close();
272      ALOGV("A2dpAudioStreamOut destructor returning from close()");
273  }
274  
write(const void * buffer,size_t bytes)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  
init()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  
standby()351  status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
352  {
353      Mutex::Autolock lock(mLock);
354      return standby_l();
355  }
356  
standby_l()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  
setParameters(const String8 & keyValuePairs)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_out_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  
getParameters(const String8 & keys)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  
setAddress(const char * address)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  
setBluetoothEnabled(bool enabled)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  
setSuspended(bool onOff)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  
close()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  
close_l()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  
dump(int fd,const Vector<String16> & args)488  status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
489  {
490      return NO_ERROR;
491  }
492  
getRenderPosition(uint32_t * driverFrames)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
500