1/* AudioStreamOutALSA.cpp 2 ** 3 ** Copyright 2008-2009 Wind River Systems 4 ** Copyright (c) 2011, Code Aurora Forum. All rights reserved. 5 ** 6 ** Licensed under the Apache License, Version 2.0 (the "License"); 7 ** you may not use this file except in compliance with the License. 8 ** You may obtain a copy of the License at 9 ** 10 ** http://www.apache.org/licenses/LICENSE-2.0 11 ** 12 ** Unless required by applicable law or agreed to in writing, software 13 ** distributed under the License is distributed on an "AS IS" BASIS, 14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 ** See the License for the specific language governing permissions and 16 ** limitations under the License. 17 */ 18 19#include <errno.h> 20#include <stdarg.h> 21#include <sys/stat.h> 22#include <fcntl.h> 23#include <stdlib.h> 24#include <unistd.h> 25#include <dlfcn.h> 26#include <math.h> 27 28#define LOG_TAG "AudioStreamOutALSA" 29//#define LOG_NDEBUG 0 30#define LOG_NDDEBUG 0 31#include <utils/Log.h> 32#include <utils/String8.h> 33 34#include <cutils/properties.h> 35#include <media/AudioRecord.h> 36#include <hardware_legacy/power.h> 37 38#include "AudioHardwareALSA.h" 39 40#ifndef ALSA_DEFAULT_SAMPLE_RATE 41#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz 42#endif 43 44namespace android_audio_legacy 45{ 46 47// ---------------------------------------------------------------------------- 48 49static const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE; 50 51// ---------------------------------------------------------------------------- 52 53AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent, alsa_handle_t *handle) : 54 ALSAStreamOps(parent, handle), 55 mParent(parent), 56 mFrameCount(0) 57{ 58} 59 60AudioStreamOutALSA::~AudioStreamOutALSA() 61{ 62 close(); 63} 64 65uint32_t AudioStreamOutALSA::channels() const 66{ 67 int c = ALSAStreamOps::channels(); 68 return c; 69} 70 71status_t AudioStreamOutALSA::setVolume(float left, float right) 72{ 73 int vol; 74 float volume; 75 status_t status = NO_ERROR; 76 77 volume = (left + right) / 2; 78 if (volume < 0.0) { 79 ALOGW("AudioSessionOutALSA::setVolume(%f) under 0.0, assuming 0.0\n", volume); 80 volume = 0.0; 81 } else if (volume > 1.0) { 82 ALOGW("AudioSessionOutALSA::setVolume(%f) over 1.0, assuming 1.0\n", volume); 83 volume = 1.0; 84 } 85 vol = lrint((volume * 0x2000)+0.5); 86 87 if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) || 88 !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) { 89 ALOGV("setLpaVolume(%f)\n", volume); 90 ALOGV("Setting LPA volume to %d (available range is 0 to 100)\n", vol); 91 mHandle->module->setLpaVolume(vol); 92 return status; 93 } 94 else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) || 95 !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) { 96 ALOGV("setCompressedVolume(%f)\n", volume); 97 ALOGV("Setting Compressed volume to %d (available range is 0 to 100)\n", vol); 98 mHandle->module->setCompressedVolume(vol); 99 return status; 100 } 101 else if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, 102 sizeof(mHandle->useCase)) || !strncmp(mHandle->useCase, 103 SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase))) { 104 ALOGV("Avoid Software volume by returning success\n"); 105 return status; 106 } 107 return INVALID_OPERATION; 108} 109 110ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes) 111{ 112 int period_size; 113 char *use_case; 114 115 ALOGV("write:: buffer %p, bytes %d", buffer, bytes); 116 117 snd_pcm_sframes_t n = 0; 118 size_t sent = 0; 119 status_t err; 120 121 int write_pending = bytes; 122 123 if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) && 124 (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) && 125 (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 126 mParent->mLock.lock(); 127 128 ALOGD("mHandle->useCase: %s", mHandle->useCase); 129 snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case); 130 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { 131 if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)){ 132 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, 133 sizeof(SND_USE_CASE_VERB_IP_VOICECALL)); 134 } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) { 135 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2, 136 sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2)); 137 } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)){ 138 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI, 139 sizeof(SND_USE_CASE_MOD_PLAY_MUSIC)); 140 } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) { 141 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, 142 sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)); 143 } 144 } else { 145 if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){ 146 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, 147 sizeof(SND_USE_CASE_MOD_PLAY_VOIP)); 148 } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) { 149 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2, 150 sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2)); 151 } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)){ 152 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, 153 sizeof(SND_USE_CASE_MOD_PLAY_MUSIC)); 154 } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) { 155 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, 156 sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)); 157 } 158 } 159 free(use_case); 160 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 161 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 162#ifdef QCOM_USBAUDIO_ENABLED 163 if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| 164 (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| 165 (mDevices & AudioSystem::DEVICE_OUT_PROXY)) { 166 mDevices |= AudioSystem::DEVICE_OUT_PROXY; 167 mHandle->module->route(mHandle, mDevices , mParent->mode()); 168 }else 169#endif 170 { 171 mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION); 172 } 173#ifdef QCOM_USBAUDIO_ENABLED 174 } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)|| 175 (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)|| 176 (mDevices & AudioSystem::DEVICE_OUT_PROXY)) { 177 mDevices |= AudioSystem::DEVICE_OUT_PROXY; 178 mHandle->module->route(mHandle, mDevices , mParent->mode()); 179#endif 180 } else { 181 mHandle->module->route(mHandle, mDevices , mParent->mode()); 182 } 183 if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) || 184 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) || 185 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) || 186 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) { 187 snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase); 188 } else { 189 snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase); 190 } 191 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 192 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 193 err = mHandle->module->startVoipCall(mHandle); 194 } 195 else 196 mHandle->module->open(mHandle); 197 if(mHandle->handle == NULL) { 198 ALOGE("write:: device open failed"); 199 mParent->mLock.unlock(); 200 return bytes; 201 } 202#ifdef QCOM_USBAUDIO_ENABLED 203 if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)|| 204 (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){ 205 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 206 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 207 mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; 208 } else { 209 mParent->startUsbPlaybackIfNotStarted(); 210 mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC; 211 } 212 } 213#endif 214 215 mParent->mLock.unlock(); 216 } 217 218#ifdef QCOM_USBAUDIO_ENABLED 219 if(((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) || 220 (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) && 221 (!mParent->musbPlaybackState)) { 222 mParent->mLock.lock(); 223 mParent->startUsbPlaybackIfNotStarted(); 224 ALOGV("Starting playback on USB"); 225 if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) || 226 !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) { 227 ALOGD("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState); 228 mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL; 229 }else{ 230 ALOGV("enabling music, musbPlaybackState: %d ", mParent->musbPlaybackState); 231 mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC; 232 } 233 mParent->mLock.unlock(); 234 } 235#endif 236 237 period_size = mHandle->periodSize; 238 do { 239 if (write_pending < period_size) { 240 write_pending = period_size; 241 } 242 if((mParent->mVoipStreamCount) && (mHandle->rxHandle != 0)) { 243 n = pcm_write(mHandle->rxHandle, 244 (char *)buffer + sent, 245 period_size); 246 } else if (mHandle->handle != 0){ 247 n = pcm_write(mHandle->handle, 248 (char *)buffer + sent, 249 period_size); 250 } 251 if (n < 0) { 252 mParent->mLock.lock(); 253 if (mHandle->handle != NULL) { 254 ALOGE("pcm_write returned error %d, trying to recover\n", n); 255 pcm_close(mHandle->handle); 256 mHandle->handle = NULL; 257 if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || 258 (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { 259 pcm_close(mHandle->rxHandle); 260 mHandle->rxHandle = NULL; 261 mHandle->module->startVoipCall(mHandle); 262 } 263 else 264 mHandle->module->open(mHandle); 265 if(mHandle->handle == NULL) { 266 ALOGE("write:: device re-open failed"); 267 mParent->mLock.unlock(); 268 return bytes; 269 } 270 } 271 mParent->mLock.unlock(); 272 continue; 273 } 274 else { 275 mFrameCount += n; 276 sent += static_cast<ssize_t>((period_size)); 277 write_pending -= period_size; 278 } 279 280 } while ((mHandle->handle||(mHandle->rxHandle && mParent->mVoipStreamCount)) && sent < bytes); 281 282 return sent; 283} 284 285status_t AudioStreamOutALSA::dump(int fd, const Vector<String16>& args) 286{ 287 return NO_ERROR; 288} 289 290status_t AudioStreamOutALSA::open(int mode) 291{ 292 Mutex::Autolock autoLock(mParent->mLock); 293 294 return ALSAStreamOps::open(mode); 295} 296 297status_t AudioStreamOutALSA::close() 298{ 299 Mutex::Autolock autoLock(mParent->mLock); 300 301 ALOGV("close"); 302 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 303 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 304 if((mParent->mVoipStreamCount)) { 305#ifdef QCOM_USBAUDIO_ENABLED 306 if(mParent->mVoipStreamCount == 1) { 307 ALOGV("Deregistering VOIP Call bit, musbPlaybackState:%d, musbRecordingState: %d", 308 mParent->musbPlaybackState, mParent->musbRecordingState); 309 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL; 310 mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL; 311 mParent->closeUsbPlaybackIfNothingActive(); 312 mParent->closeUsbRecordingIfNothingActive(); 313 } 314#endif 315 return NO_ERROR; 316 } 317 mParent->mVoipStreamCount = 0; 318 } 319#ifdef QCOM_USBAUDIO_ENABLED 320 else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || 321 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) { 322 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA; 323 } else { 324 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC; 325 } 326 327 mParent->closeUsbPlaybackIfNothingActive(); 328#endif 329 330 ALSAStreamOps::close(); 331 332 return NO_ERROR; 333} 334 335status_t AudioStreamOutALSA::standby() 336{ 337 Mutex::Autolock autoLock(mParent->mLock); 338 339 ALOGV("standby"); 340 341 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 342 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 343 return NO_ERROR; 344 } 345 346#ifdef QCOM_USBAUDIO_ENABLED 347 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || 348 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) { 349 ALOGV("Deregistering LPA bit"); 350 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA; 351 } else { 352 ALOGV("Deregistering MUSIC bit, musbPlaybackState: %d", mParent->musbPlaybackState); 353 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC; 354 } 355#endif 356 357 mHandle->module->standby(mHandle); 358 359#ifdef QCOM_USBAUDIO_ENABLED 360 mParent->closeUsbPlaybackIfNothingActive(); 361#endif 362 363 mFrameCount = 0; 364 365 return NO_ERROR; 366} 367 368#define USEC_TO_MSEC(x) ((x + 999) / 1000) 369 370uint32_t AudioStreamOutALSA::latency() const 371{ 372 // Android wants latency in milliseconds. 373 return USEC_TO_MSEC (mHandle->latency); 374} 375 376// return the number of audio frames written by the audio dsp to DAC since 377// the output has exited standby 378status_t AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames) 379{ 380 *dspFrames = mFrameCount; 381 return NO_ERROR; 382} 383 384} // namespace android_audio_legacy 385