1 /* ALSAMixer.cpp 2 ** 3 ** Copyright 2008-2010 Wind River Systems 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include <errno.h> 19 #include <stdarg.h> 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 #include <dlfcn.h> 25 26 #define LOG_TAG "AudioHardwareALSA" 27 #include <utils/Log.h> 28 #include <utils/String8.h> 29 30 #include <cutils/properties.h> 31 #include <media/AudioRecord.h> 32 #include <hardware_legacy/power.h> 33 34 #include "AudioHardwareALSA.h" 35 36 #define SND_MIXER_VOL_RANGE_MIN (0) 37 #define SND_MIXER_VOL_RANGE_MAX (100) 38 39 #define ALSA_NAME_MAX 128 40 41 #define ALSA_STRCAT(x,y) \ 42 if (strlen(x) + strlen(y) < ALSA_NAME_MAX) \ 43 strcat(x, y); 44 45 namespace android 46 { 47 48 // ---------------------------------------------------------------------------- 49 50 struct mixer_info_t; 51 52 struct alsa_properties_t 53 { 54 const AudioSystem::audio_devices device; 55 const char *propName; 56 const char *propDefault; 57 mixer_info_t *mInfo; 58 }; 59 60 #define ALSA_PROP(dev, name, out, in) \ 61 {\ 62 {dev, "alsa.mixer.playback." name, out, NULL},\ 63 {dev, "alsa.mixer.capture." name, in, NULL}\ 64 } 65 66 static alsa_properties_t 67 mixerMasterProp[SND_PCM_STREAM_LAST+1] = 68 ALSA_PROP(AudioSystem::DEVICE_OUT_ALL, "master", "PCM", "Capture"); 69 70 static alsa_properties_t 71 mixerProp[][SND_PCM_STREAM_LAST+1] = { 72 ALSA_PROP(AudioSystem::DEVICE_OUT_EARPIECE, "earpiece", "Earpiece", "Capture"), 73 ALSA_PROP(AudioSystem::DEVICE_OUT_SPEAKER, "speaker", "Speaker", ""), 74 ALSA_PROP(AudioSystem::DEVICE_OUT_WIRED_HEADSET, "headset", "Headphone", "Capture"), 75 ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "bluetooth.sco", "Bluetooth", "Bluetooth Capture"), 76 ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "bluetooth.a2dp", "Bluetooth A2DP", "Bluetooth A2DP Capture"), 77 ALSA_PROP(static_cast<AudioSystem::audio_devices>(0), "", NULL, NULL) 78 }; 79 80 struct mixer_info_t 81 { 82 mixer_info_t() : 83 elem(0), 84 min(SND_MIXER_VOL_RANGE_MIN), 85 max(SND_MIXER_VOL_RANGE_MAX), 86 mute(false) 87 { 88 } 89 90 snd_mixer_elem_t *elem; 91 long min; 92 long max; 93 long volume; 94 bool mute; 95 char name[ALSA_NAME_MAX]; 96 }; 97 98 static int initMixer (snd_mixer_t **mixer, const char *name) 99 { 100 int err; 101 102 if ((err = snd_mixer_open(mixer, 0)) < 0) { 103 ALOGE("Unable to open mixer: %s", snd_strerror(err)); 104 return err; 105 } 106 107 if ((err = snd_mixer_attach(*mixer, name)) < 0) { 108 ALOGW("Unable to attach mixer to device %s: %s", 109 name, snd_strerror(err)); 110 111 if ((err = snd_mixer_attach(*mixer, "hw:00")) < 0) { 112 ALOGE("Unable to attach mixer to device default: %s", 113 snd_strerror(err)); 114 115 snd_mixer_close (*mixer); 116 *mixer = NULL; 117 return err; 118 } 119 } 120 121 if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0) { 122 ALOGE("Unable to register mixer elements: %s", snd_strerror(err)); 123 snd_mixer_close (*mixer); 124 *mixer = NULL; 125 return err; 126 } 127 128 // Get the mixer controls from the kernel 129 if ((err = snd_mixer_load(*mixer)) < 0) { 130 ALOGE("Unable to load mixer elements: %s", snd_strerror(err)); 131 snd_mixer_close (*mixer); 132 *mixer = NULL; 133 return err; 134 } 135 136 return 0; 137 } 138 139 typedef int (*hasVolume_t)(snd_mixer_elem_t*); 140 141 static const hasVolume_t hasVolume[] = { 142 snd_mixer_selem_has_playback_volume, 143 snd_mixer_selem_has_capture_volume 144 }; 145 146 typedef int (*getVolumeRange_t)(snd_mixer_elem_t*, long int*, long int*); 147 148 static const getVolumeRange_t getVolumeRange[] = { 149 snd_mixer_selem_get_playback_volume_range, 150 snd_mixer_selem_get_capture_volume_range 151 }; 152 153 typedef int (*setVolume_t)(snd_mixer_elem_t*, long int); 154 155 static const setVolume_t setVol[] = { 156 snd_mixer_selem_set_playback_volume_all, 157 snd_mixer_selem_set_capture_volume_all 158 }; 159 160 ALSAMixer::ALSAMixer() 161 { 162 int err; 163 164 initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidOut"); 165 initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidIn"); 166 167 snd_mixer_selem_id_t *sid; 168 snd_mixer_selem_id_alloca(&sid); 169 170 for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) { 171 172 if (!mMixer[i]) continue; 173 174 mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t; 175 176 property_get (mixerMasterProp[i].propName, 177 info->name, 178 mixerMasterProp[i].propDefault); 179 180 for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]); 181 elem; 182 elem = snd_mixer_elem_next(elem)) { 183 184 if (!snd_mixer_selem_is_active(elem)) 185 continue; 186 187 snd_mixer_selem_get_id(elem, sid); 188 189 // Find PCM playback volume control element. 190 const char *elementName = snd_mixer_selem_id_get_name(sid); 191 192 if (info->elem == NULL && 193 strcmp(elementName, info->name) == 0 && 194 hasVolume[i] (elem)) { 195 196 info->elem = elem; 197 getVolumeRange[i] (elem, &info->min, &info->max); 198 info->volume = info->max; 199 setVol[i] (elem, info->volume); 200 if (i == SND_PCM_STREAM_PLAYBACK && 201 snd_mixer_selem_has_playback_switch (elem)) 202 snd_mixer_selem_set_playback_switch_all (elem, 1); 203 break; 204 } 205 } 206 207 ALOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found"); 208 209 for (int j = 0; mixerProp[j][i].device; j++) { 210 211 mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t; 212 213 property_get (mixerProp[j][i].propName, 214 info->name, 215 mixerProp[j][i].propDefault); 216 217 for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]); 218 elem; 219 elem = snd_mixer_elem_next(elem)) { 220 221 if (!snd_mixer_selem_is_active(elem)) 222 continue; 223 224 snd_mixer_selem_get_id(elem, sid); 225 226 // Find PCM playback volume control element. 227 const char *elementName = snd_mixer_selem_id_get_name(sid); 228 229 if (info->elem == NULL && 230 strcmp(elementName, info->name) == 0 && 231 hasVolume[i] (elem)) { 232 233 info->elem = elem; 234 getVolumeRange[i] (elem, &info->min, &info->max); 235 info->volume = info->max; 236 setVol[i] (elem, info->volume); 237 if (i == SND_PCM_STREAM_PLAYBACK && 238 snd_mixer_selem_has_playback_switch (elem)) 239 snd_mixer_selem_set_playback_switch_all (elem, 1); 240 break; 241 } 242 } 243 ALOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found"); 244 } 245 } 246 ALOGV("mixer initialized."); 247 } 248 249 ALSAMixer::~ALSAMixer() 250 { 251 for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) { 252 if (mMixer[i]) snd_mixer_close (mMixer[i]); 253 if (mixerMasterProp[i].mInfo) { 254 delete mixerMasterProp[i].mInfo; 255 mixerMasterProp[i].mInfo = NULL; 256 } 257 for (int j = 0; mixerProp[j][i].device; j++) { 258 if (mixerProp[j][i].mInfo) { 259 delete mixerProp[j][i].mInfo; 260 mixerProp[j][i].mInfo = NULL; 261 } 262 } 263 } 264 ALOGV("mixer destroyed."); 265 } 266 267 status_t ALSAMixer::setMasterVolume(float volume) 268 { 269 mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo; 270 if (!info || !info->elem) return INVALID_OPERATION; 271 272 long minVol = info->min; 273 long maxVol = info->max; 274 275 // Make sure volume is between bounds. 276 long vol = minVol + volume * (maxVol - minVol); 277 if (vol > maxVol) vol = maxVol; 278 if (vol < minVol) vol = minVol; 279 280 info->volume = vol; 281 snd_mixer_selem_set_playback_volume_all (info->elem, vol); 282 283 return NO_ERROR; 284 } 285 286 status_t ALSAMixer::setMasterGain(float gain) 287 { 288 mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_CAPTURE].mInfo; 289 if (!info || !info->elem) return INVALID_OPERATION; 290 291 long minVol = info->min; 292 long maxVol = info->max; 293 294 // Make sure volume is between bounds. 295 long vol = minVol + gain * (maxVol - minVol); 296 if (vol > maxVol) vol = maxVol; 297 if (vol < minVol) vol = minVol; 298 299 info->volume = vol; 300 snd_mixer_selem_set_capture_volume_all (info->elem, vol); 301 302 return NO_ERROR; 303 } 304 305 status_t ALSAMixer::setVolume(uint32_t device, float left, float right) 306 { 307 for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++) 308 if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) { 309 310 mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo; 311 if (!info || !info->elem) return INVALID_OPERATION; 312 313 long minVol = info->min; 314 long maxVol = info->max; 315 316 // Make sure volume is between bounds. 317 long vol = minVol + left * (maxVol - minVol); 318 if (vol > maxVol) vol = maxVol; 319 if (vol < minVol) vol = minVol; 320 321 info->volume = vol; 322 snd_mixer_selem_set_playback_volume_all (info->elem, vol); 323 } 324 325 return NO_ERROR; 326 } 327 328 status_t ALSAMixer::setGain(uint32_t device, float gain) 329 { 330 for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++) 331 if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) { 332 333 mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo; 334 if (!info || !info->elem) return INVALID_OPERATION; 335 336 long minVol = info->min; 337 long maxVol = info->max; 338 339 // Make sure volume is between bounds. 340 long vol = minVol + gain * (maxVol - minVol); 341 if (vol > maxVol) vol = maxVol; 342 if (vol < minVol) vol = minVol; 343 344 info->volume = vol; 345 snd_mixer_selem_set_capture_volume_all (info->elem, vol); 346 } 347 348 return NO_ERROR; 349 } 350 351 status_t ALSAMixer::setCaptureMuteState(uint32_t device, bool state) 352 { 353 for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++) 354 if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) { 355 356 mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo; 357 if (!info || !info->elem) return INVALID_OPERATION; 358 359 if (snd_mixer_selem_has_capture_switch (info->elem)) { 360 361 int err = snd_mixer_selem_set_capture_switch_all (info->elem, static_cast<int>(!state)); 362 if (err < 0) { 363 ALOGE("Unable to %s capture mixer switch %s", 364 state ? "enable" : "disable", info->name); 365 return INVALID_OPERATION; 366 } 367 } 368 369 info->mute = state; 370 } 371 372 return NO_ERROR; 373 } 374 375 status_t ALSAMixer::getCaptureMuteState(uint32_t device, bool *state) 376 { 377 if (!state) return BAD_VALUE; 378 379 for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].device; j++) 380 if (mixerProp[j][SND_PCM_STREAM_CAPTURE].device & device) { 381 382 mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo; 383 if (!info || !info->elem) return INVALID_OPERATION; 384 385 *state = info->mute; 386 return NO_ERROR; 387 } 388 389 return BAD_VALUE; 390 } 391 392 status_t ALSAMixer::setPlaybackMuteState(uint32_t device, bool state) 393 { 394 for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++) 395 if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) { 396 397 mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo; 398 if (!info || !info->elem) return INVALID_OPERATION; 399 400 if (snd_mixer_selem_has_playback_switch (info->elem)) { 401 402 int err = snd_mixer_selem_set_playback_switch_all (info->elem, static_cast<int>(!state)); 403 if (err < 0) { 404 ALOGE("Unable to %s playback mixer switch %s", 405 state ? "enable" : "disable", info->name); 406 return INVALID_OPERATION; 407 } 408 } 409 410 info->mute = state; 411 } 412 413 return NO_ERROR; 414 } 415 416 status_t ALSAMixer::getPlaybackMuteState(uint32_t device, bool *state) 417 { 418 if (!state) return BAD_VALUE; 419 420 for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++) 421 if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) { 422 423 mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo; 424 if (!info || !info->elem) return INVALID_OPERATION; 425 426 *state = info->mute; 427 return NO_ERROR; 428 } 429 430 return BAD_VALUE; 431 } 432 433 }; // namespace android 434