1 /* ALSAStreamOps.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 27 #define LOG_TAG "ALSAStreamOps" 28 //#define LOG_NDEBUG 0 29 #define LOG_NDDEBUG 0 30 #include <utils/Log.h> 31 #include <utils/String8.h> 32 33 #include <cutils/properties.h> 34 #include <media/AudioRecord.h> 35 #include <hardware_legacy/power.h> 36 #include "AudioUtil.h" 37 #include "AudioHardwareALSA.h" 38 39 namespace android_audio_legacy 40 { 41 42 // unused 'enumVal;' is to catch error at compile time if enumVal ever changes 43 // or applied on a non-existent enum 44 #define ENUM_TO_STRING(var, enumVal) {var = #enumVal; enumVal;} 45 46 // ---------------------------------------------------------------------------- 47 48 ALSAStreamOps::ALSAStreamOps(AudioHardwareALSA *parent, alsa_handle_t *handle) : 49 mParent(parent), 50 mHandle(handle) 51 { 52 } 53 54 ALSAStreamOps::~ALSAStreamOps() 55 { 56 Mutex::Autolock autoLock(mParent->mLock); 57 58 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 59 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 60 if((mParent->mVoipStreamCount)) { 61 mParent->mVoipStreamCount--; 62 if(mParent->mVoipStreamCount > 0) { 63 ALOGD("ALSAStreamOps::close() Ignore"); 64 return ; 65 } 66 } 67 mParent->mVoipStreamCount = 0; 68 mParent->mVoipBitRate = 0; 69 } 70 close(); 71 72 for(ALSAHandleList::iterator it = mParent->mDeviceList.begin(); 73 it != mParent->mDeviceList.end(); ++it) { 74 if (mHandle == &(*it)) { 75 it->useCase[0] = 0; 76 mParent->mDeviceList.erase(it); 77 break; 78 } 79 } 80 } 81 82 // use emulated popcount optimization 83 // http://www.df.lth.se/~john_e/gems/gem002d.html 84 static inline uint32_t popCount(uint32_t u) 85 { 86 u = ((u&0x55555555) + ((u>>1)&0x55555555)); 87 u = ((u&0x33333333) + ((u>>2)&0x33333333)); 88 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); 89 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); 90 u = ( u&0x0000ffff) + (u>>16); 91 return u; 92 } 93 94 status_t ALSAStreamOps::set(int *format, 95 uint32_t *channels, 96 uint32_t *rate, 97 uint32_t device) 98 { 99 mDevices = device; 100 if (channels && *channels != 0) { 101 if (mHandle->channels != popCount(*channels)) 102 return BAD_VALUE; 103 } else if (channels) { 104 if (mHandle->devices & AudioSystem::DEVICE_OUT_ALL) { 105 switch(*channels) { 106 case AUDIO_CHANNEL_OUT_5POINT1: // 5.0 107 case (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER): // 5.1 108 case AUDIO_CHANNEL_OUT_QUAD: 109 case AUDIO_CHANNEL_OUT_STEREO: 110 case AUDIO_CHANNEL_OUT_MONO: 111 break; 112 default: 113 *channels = AUDIO_CHANNEL_OUT_STEREO; 114 return BAD_VALUE; 115 } 116 } else { 117 switch(*channels) { 118 #ifdef QCOM_SSR_ENABLED 119 // For 5.1 recording 120 case AudioSystem::CHANNEL_IN_5POINT1: 121 #endif 122 // Do not fall through... 123 case AUDIO_CHANNEL_IN_MONO: 124 case AUDIO_CHANNEL_IN_STEREO: 125 case AUDIO_CHANNEL_IN_FRONT_BACK: 126 break; 127 default: 128 *channels = AUDIO_CHANNEL_IN_MONO; 129 return BAD_VALUE; 130 } 131 } 132 } 133 134 if (rate && *rate > 0) { 135 if (mHandle->sampleRate != *rate) 136 return BAD_VALUE; 137 } else if (rate) { 138 *rate = mHandle->sampleRate; 139 } 140 141 snd_pcm_format_t iformat = mHandle->format; 142 143 if (format) { 144 switch(*format) { 145 case AudioSystem::FORMAT_DEFAULT: 146 break; 147 148 case AudioSystem::PCM_16_BIT: 149 iformat = SNDRV_PCM_FORMAT_S16_LE; 150 break; 151 case AudioSystem::AMR_NB: 152 case AudioSystem::AMR_WB: 153 #ifdef QCOM_QCHAT_ENABLED 154 case AudioSystem::EVRC: 155 case AudioSystem::EVRCB: 156 case AudioSystem::EVRCWB: 157 #endif 158 iformat = *format; 159 break; 160 161 case AudioSystem::PCM_8_BIT: 162 iformat = SNDRV_PCM_FORMAT_S8; 163 break; 164 165 default: 166 ALOGE("Unknown PCM format %i. Forcing default", *format); 167 break; 168 } 169 170 if (mHandle->format != iformat) 171 return BAD_VALUE; 172 173 switch(iformat) { 174 case SNDRV_PCM_FORMAT_S16_LE: 175 *format = AudioSystem::PCM_16_BIT; 176 break; 177 case SNDRV_PCM_FORMAT_S8: 178 *format = AudioSystem::PCM_8_BIT; 179 break; 180 default: 181 break; 182 } 183 } 184 185 return NO_ERROR; 186 } 187 188 status_t ALSAStreamOps::setParameters(const String8& keyValuePairs) 189 { 190 AudioParameter param = AudioParameter(keyValuePairs); 191 String8 key = String8(AudioParameter::keyRouting); 192 int device; 193 194 #ifdef SEPERATED_AUDIO_INPUT 195 String8 key_input = String8(AudioParameter::keyInputSource); 196 int source; 197 198 if (param.getInt(key_input, source) == NO_ERROR) { 199 ALOGD("setParameters(), input_source = %d", source); 200 mParent->mALSADevice->setInput(source); 201 param.remove(key_input); 202 } 203 #endif 204 205 if (param.getInt(key, device) == NO_ERROR) { 206 // Ignore routing if device is 0. 207 ALOGD("setParameters(): keyRouting with device 0x%x", device); 208 // reset to speaker when disconnecting HDMI to avoid timeout due to write errors 209 if ((device == 0) && (mDevices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) { 210 device = AudioSystem::DEVICE_OUT_SPEAKER; 211 } 212 if (device) 213 mDevices = device; 214 else 215 ALOGV("must not change mDevices to 0"); 216 217 if(device) { 218 mParent->doRouting(device); 219 } 220 param.remove(key); 221 } 222 #ifdef QCOM_FM_ENABLED 223 else { 224 key = String8(AudioParameter::keyHandleFm); 225 if (param.getInt(key, device) == NO_ERROR) { 226 ALOGD("setParameters(): handleFm with device %d", device); 227 mDevices = device; 228 if(device) { 229 mParent->handleFm(device); 230 } 231 param.remove(key); 232 } 233 } 234 #endif 235 236 return NO_ERROR; 237 } 238 239 String8 ALSAStreamOps::getParameters(const String8& keys) 240 { 241 AudioParameter param = AudioParameter(keys); 242 String8 value; 243 String8 key = String8(AudioParameter::keyRouting); 244 245 if (param.get(key, value) == NO_ERROR) { 246 param.addInt(key, (int)mDevices); 247 } 248 else { 249 #ifdef QCOM_VOIP_ENABLED 250 key = String8(AudioParameter::keyVoipCheck); 251 if (param.get(key, value) == NO_ERROR) { 252 if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || 253 (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) 254 param.addInt(key, true); 255 else 256 param.addInt(key, false); 257 } 258 #endif 259 } 260 key = String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS); 261 if (param.get(key, value) == NO_ERROR) { 262 EDID_AUDIO_INFO info = { 0 }; 263 bool first = true; 264 value = String8(); 265 if (AudioUtil::getHDMIAudioSinkCaps(&info)) { 266 for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) { 267 String8 append; 268 switch (info.AudioBlocksArray[i].nChannels) { 269 //Do not handle stereo output in Multi-channel cases 270 //Stereo case is handled in normal playback path 271 case 6: 272 ENUM_TO_STRING(append, AUDIO_CHANNEL_OUT_5POINT1); 273 break; 274 case 8: 275 ENUM_TO_STRING(append, AUDIO_CHANNEL_OUT_7POINT1); 276 break; 277 default: 278 ALOGD("Unsupported number of channels %d", info.AudioBlocksArray[i].nChannels); 279 break; 280 } 281 if (!append.isEmpty()) { 282 value += (first ? append : String8("|") + append); 283 first = false; 284 } 285 } 286 } else { 287 ALOGE("Failed to get HDMI sink capabilities"); 288 } 289 param.add(key, value); 290 } 291 ALOGV("getParameters() %s", param.toString().string()); 292 return param.toString(); 293 } 294 295 uint32_t ALSAStreamOps::sampleRate() const 296 { 297 return mHandle->sampleRate; 298 } 299 300 // 301 // Return the number of bytes (not frames) 302 // 303 size_t ALSAStreamOps::bufferSize() const 304 { 305 ALOGV("bufferSize() returns %d", mHandle->bufferSize); 306 return mHandle->bufferSize; 307 } 308 309 int ALSAStreamOps::format() const 310 { 311 int audioSystemFormat; 312 313 snd_pcm_format_t ALSAFormat = mHandle->format; 314 315 switch(ALSAFormat) { 316 case SNDRV_PCM_FORMAT_S8: 317 audioSystemFormat = AudioSystem::PCM_8_BIT; 318 break; 319 320 case AudioSystem::AMR_NB: 321 case AudioSystem::AMR_WB: 322 #ifdef QCOM_QCHAT_ENABLED 323 case AudioSystem::EVRC: 324 case AudioSystem::EVRCB: 325 case AudioSystem::EVRCWB: 326 #endif 327 audioSystemFormat = mHandle->format; 328 break; 329 case SNDRV_PCM_FORMAT_S16_LE: 330 audioSystemFormat = AudioSystem::PCM_16_BIT; 331 break; 332 333 default: 334 LOG_FATAL("Unknown AudioSystem bit width %d!", audioSystemFormat); 335 audioSystemFormat = AudioSystem::PCM_16_BIT; 336 break; 337 } 338 339 ALOGV("ALSAFormat:0x%x,audioSystemFormat:0x%x",ALSAFormat,audioSystemFormat); 340 return audioSystemFormat; 341 } 342 343 uint32_t ALSAStreamOps::channels() const 344 { 345 return mHandle->channelMask; 346 } 347 348 void ALSAStreamOps::close() 349 { 350 ALOGD("close"); 351 if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || 352 (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { 353 mParent->mVoipBitRate = 0; 354 mParent->mVoipStreamCount = 0; 355 } 356 mParent->mALSADevice->close(mHandle); 357 } 358 359 // 360 // Set playback or capture PCM device. It's possible to support audio output 361 // or input from multiple devices by using the ALSA plugins, but this is 362 // not supported for simplicity. 363 // 364 // The AudioHardwareALSA API does not allow one to set the input routing. 365 // 366 // If the "routes" value does not map to a valid device, the default playback 367 // device is used. 368 // 369 status_t ALSAStreamOps::open(int mode) 370 { 371 ALOGD("open"); 372 return mParent->mALSADevice->open(mHandle); 373 } 374 375 } // namespace androidi_audio_legacy 376