1 /** 2 * \file mixer/simple.c 3 * \brief Mixer Simple Element Class Interface 4 * \author Jaroslav Kysela <perex (at) perex.cz> 5 * \author Abramo Bagnara <abramo (at) alsa-project.org> 6 * \date 2001-2004 7 * 8 * Mixer simple element class interface. 9 */ 10 /* 11 * Mixer Interface - simple controls 12 * Copyright (c) 2000,2004 by Jaroslav Kysela <perex (at) perex.cz> 13 * Copyright (c) 2001 by Abramo Bagnara <abramo (at) alsa-project.org> 14 * 15 * 16 * This library is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU Lesser General Public License as 18 * published by the Free Software Foundation; either version 2.1 of 19 * the License, or (at your option) any later version. 20 * 21 * This program is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * GNU Lesser General Public License for more details. 25 * 26 * You should have received a copy of the GNU Lesser General Public 27 * License along with this library; if not, write to the Free Software 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29 * 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <string.h> 36 #include <fcntl.h> 37 #include <sys/ioctl.h> 38 #include <math.h> 39 #include "mixer_local.h" 40 #include "mixer_simple.h" 41 42 /** 43 * \brief Register mixer simple element class 44 * \param mixer Mixer handle 45 * \param options Options container 46 * \param classp Pointer to returned mixer simple element class handle (or NULL) 47 * \return 0 on success otherwise a negative error code 48 */ 49 int snd_mixer_selem_register(snd_mixer_t *mixer, 50 struct snd_mixer_selem_regopt *options, 51 snd_mixer_class_t **classp) 52 { 53 if (options && options->ver == 1) { 54 if (options->device != NULL && 55 (options->playback_pcm != NULL || 56 options->capture_pcm != NULL)) 57 return -EINVAL; 58 if (options->device == NULL && 59 options->playback_pcm == NULL && 60 options->capture_pcm == NULL) 61 return -EINVAL; 62 } 63 if (options == NULL || 64 (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) { 65 int err = snd_mixer_simple_none_register(mixer, options, classp); 66 if (err < 0) 67 return err; 68 if (options != NULL) { 69 err = snd_mixer_attach(mixer, options->device); 70 if (err < 0) 71 return err; 72 } 73 return 0; 74 } else if (options->ver == 1) { 75 if (options->abstract == SND_MIXER_SABSTRACT_BASIC) 76 return snd_mixer_simple_basic_register(mixer, options, classp); 77 } 78 return -ENXIO; 79 } 80 81 #ifndef DOC_HIDDEN 82 83 #define CHECK_BASIC(xelem) \ 84 { \ 85 assert(xelem); \ 86 assert((xelem)->type == SND_MIXER_ELEM_SIMPLE); \ 87 } 88 89 #define CHECK_DIR(xelem, xwhat) \ 90 { \ 91 unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \ 92 if (! (xcaps & (xwhat))) \ 93 return -EINVAL; \ 94 } 95 96 #define CHECK_DIR_CHN(xelem, xwhat, xjoin, xchannel) \ 97 { \ 98 unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \ 99 if (! (xcaps & (xwhat))) \ 100 return -EINVAL; \ 101 if (xcaps & (xjoin)) \ 102 xchannel = 0; \ 103 } 104 105 #define CHECK_ENUM(xelem) \ 106 if (!((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM)) \ 107 return -EINVAL; 108 109 #define COND_CAPS(xelem, what) \ 110 !!(((sm_selem_t *)(elem)->private_data)->caps & (what)) 111 112 #endif /* !DOC_HIDDEN */ 113 114 #ifndef DOC_HIDDEN 115 int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2) 116 { 117 sm_selem_t *s1 = c1->private_data; 118 sm_selem_t *s2 = c2->private_data; 119 int res = strcmp(s1->id->name, s2->id->name); 120 if (res) 121 return res; 122 return s1->id->index - s2->id->index; 123 } 124 #endif 125 126 /** 127 * \brief Find a mixer simple element 128 * \param mixer Mixer handle 129 * \param id Mixer simple element identifier 130 * \return mixer simple element handle or NULL if not found 131 */ 132 snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer, 133 const snd_mixer_selem_id_t *id) 134 { 135 struct list_head *list; 136 snd_mixer_elem_t *e; 137 sm_selem_t *s; 138 139 list_for_each(list, &mixer->elems) { 140 e = list_entry(list, snd_mixer_elem_t, list); 141 if (e->type != SND_MIXER_ELEM_SIMPLE) 142 continue; 143 s = e->private_data; 144 if (!strcmp(s->id->name, id->name) && s->id->index == id->index) 145 return e; 146 } 147 return NULL; 148 } 149 150 /** 151 * \brief Get mixer simple element identifier 152 * \param elem Mixer simple element handle 153 * \param id returned mixer simple element identifier 154 */ 155 void snd_mixer_selem_get_id(snd_mixer_elem_t *elem, 156 snd_mixer_selem_id_t *id) 157 { 158 sm_selem_t *s; 159 assert(id); 160 CHECK_BASIC(elem); 161 s = elem->private_data; 162 *id = *s->id; 163 } 164 165 /** 166 * \brief Get name part of mixer simple element identifier 167 * \param elem Mixer simple element handle 168 * \return name part of simple element identifier 169 */ 170 const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem) 171 { 172 sm_selem_t *s; 173 CHECK_BASIC(elem); 174 s = elem->private_data; 175 return s->id->name; 176 } 177 178 /** 179 * \brief Get index part of mixer simple element identifier 180 * \param elem Mixer simple element handle 181 * \return index part of simple element identifier 182 */ 183 unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem) 184 { 185 sm_selem_t *s; 186 CHECK_BASIC(elem); 187 s = elem->private_data; 188 return s->id->index; 189 } 190 191 /** 192 * \brief Return true if mixer simple element has only one volume control for both playback and capture 193 * \param elem Mixer simple element handle 194 * \return 0 separated control, 1 common control 195 */ 196 int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem) 197 { 198 CHECK_BASIC(elem); 199 return COND_CAPS(elem, SM_CAP_GVOLUME); 200 } 201 202 /** 203 * \brief Return true if mixer simple element has only one switch control for both playback and capture 204 * \param elem Mixer simple element handle 205 * \return 0 separated control, 1 common control 206 */ 207 int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem) 208 { 209 CHECK_BASIC(elem); 210 return COND_CAPS(elem, SM_CAP_GSWITCH); 211 } 212 213 /** 214 * \brief Return name of mixer simple element channel 215 * \param channel mixer simple element channel identifier 216 * \return channel name 217 */ 218 const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel) 219 { 220 static const char *const array[SND_MIXER_SCHN_LAST + 1] = { 221 [SND_MIXER_SCHN_FRONT_LEFT] = "Front Left", 222 [SND_MIXER_SCHN_FRONT_RIGHT] = "Front Right", 223 [SND_MIXER_SCHN_REAR_LEFT] = "Rear Left", 224 [SND_MIXER_SCHN_REAR_RIGHT] = "Rear Right", 225 [SND_MIXER_SCHN_FRONT_CENTER] = "Front Center", 226 [SND_MIXER_SCHN_WOOFER] = "Woofer", 227 [SND_MIXER_SCHN_SIDE_LEFT] = "Side Left", 228 [SND_MIXER_SCHN_SIDE_RIGHT] = "Side Right", 229 [SND_MIXER_SCHN_REAR_CENTER] = "Rear Center" 230 }; 231 const char *p; 232 assert(channel <= SND_MIXER_SCHN_LAST); 233 p = array[channel]; 234 if (!p) 235 return "?"; 236 return p; 237 } 238 239 /** 240 * \brief Get info about the active state of a mixer simple element 241 * \param elem Mixer simple element handle 242 * \return 0 if not active, 1 if active 243 */ 244 int snd_mixer_selem_is_active(snd_mixer_elem_t *elem) 245 { 246 CHECK_BASIC(elem); 247 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0); 248 } 249 250 /** 251 * \brief Get info about channels of playback stream of a mixer simple element 252 * \param elem Mixer simple element handle 253 * \return 0 if not mono, 1 if mono 254 */ 255 int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem) 256 { 257 CHECK_BASIC(elem); 258 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_MONO, 0); 259 } 260 261 /** 262 * \brief Get info about channels of playback stream of a mixer simple element 263 * \param elem Mixer simple element handle 264 * \param channel Mixer simple element channel identifier 265 * \return 0 if channel is not present, 1 if present 266 */ 267 int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) 268 { 269 CHECK_BASIC(elem); 270 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_CHANNEL, (int)channel); 271 } 272 273 /** 274 * \brief Get range for playback volume of a mixer simple element 275 * \param elem Mixer simple element handle 276 * \param min Pointer to returned minimum 277 * \param max Pointer to returned maximum 278 */ 279 int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem, 280 long *min, long *max) 281 { 282 CHECK_BASIC(elem); 283 CHECK_DIR(elem, SM_CAP_PVOLUME); 284 return sm_selem_ops(elem)->get_range(elem, SM_PLAY, min, max); 285 } 286 287 /** 288 * \brief Get range in dB for playback volume of a mixer simple element 289 * \param elem Mixer simple element handle 290 * \param min Pointer to returned minimum (dB * 100) 291 * \param max Pointer to returned maximum (dB * 100) 292 */ 293 int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, 294 long *min, long *max) 295 { 296 CHECK_BASIC(elem); 297 CHECK_DIR(elem, SM_CAP_PVOLUME); 298 return sm_selem_ops(elem)->get_dB_range(elem, SM_PLAY, min, max); 299 } 300 301 /** 302 * \brief Set range for playback volume of a mixer simple element 303 * \param elem Mixer simple element handle 304 * \param min minimum volume value 305 * \param max maximum volume value 306 */ 307 int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem, 308 long min, long max) 309 { 310 CHECK_BASIC(elem); 311 assert(min < max); 312 CHECK_DIR(elem, SM_CAP_PVOLUME); 313 return sm_selem_ops(elem)->set_range(elem, SM_PLAY, min, max); 314 } 315 316 /** 317 * \brief Return info about playback volume control of a mixer simple element 318 * \param elem Mixer simple element handle 319 * \return 0 if no control is present, 1 if it's present 320 */ 321 int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem) 322 { 323 CHECK_BASIC(elem); 324 return COND_CAPS(elem, SM_CAP_PVOLUME); 325 } 326 327 /** 328 * \brief Return info about playback volume control of a mixer simple element 329 * \param elem Mixer simple element handle 330 * \return 0 if control is separated per channel, 1 if control acts on all channels together 331 */ 332 int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem) 333 { 334 CHECK_BASIC(elem); 335 return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN); 336 } 337 338 /** 339 * \brief Return info about playback switch control existence of a mixer simple element 340 * \param elem Mixer simple element handle 341 * \return 0 if no control is present, 1 if it's present 342 */ 343 int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem) 344 { 345 CHECK_BASIC(elem); 346 return COND_CAPS(elem, SM_CAP_PSWITCH); 347 } 348 349 /** 350 * \brief Return info about playback switch control of a mixer simple element 351 * \param elem Mixer simple element handle 352 * \return 0 if control is separated per channel, 1 if control acts on all channels together 353 */ 354 int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem) 355 { 356 CHECK_BASIC(elem); 357 return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN); 358 } 359 360 /** 361 * \brief Return corresponding dB value to an integer playback volume for a mixer simple element 362 * \param elem Mixer simple element handle 363 * \param value value to be converted to dB range 364 * \param dBvalue pointer to returned dB value 365 * \return 0 on success otherwise a negative error code 366 */ 367 int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) 368 { 369 CHECK_BASIC(elem); 370 CHECK_DIR(elem, SM_CAP_PVOLUME); 371 return sm_selem_ops(elem)->ask_vol_dB(elem, SM_PLAY, value, dBvalue); 372 } 373 374 /** 375 * \brief Return corresponding integer playback volume for given dB value for a mixer simple element 376 * \param elem Mixer simple element handle 377 * \param value value to be converted to dB range 378 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) 379 * \param dBvalue pointer to returned dB value 380 * \return 0 on success otherwise a negative error code 381 */ 382 int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) 383 { 384 CHECK_BASIC(elem); 385 CHECK_DIR(elem, SM_CAP_PVOLUME); 386 return sm_selem_ops(elem)->ask_dB_vol(elem, SM_PLAY, dBvalue, value, dir); 387 } 388 389 /** 390 * \brief Return value of playback volume control of a mixer simple element 391 * \param elem Mixer simple element handle 392 * \param channel mixer simple element channel identifier 393 * \param value pointer to returned value 394 * \return 0 on success otherwise a negative error code 395 */ 396 int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) 397 { 398 CHECK_BASIC(elem); 399 CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); 400 return sm_selem_ops(elem)->get_volume(elem, SM_PLAY, channel, value); 401 } 402 403 /** 404 * \brief Return value of playback volume in dB control of a mixer simple element 405 * \param elem Mixer simple element handle 406 * \param channel mixer simple element channel identifier 407 * \param value pointer to returned value (dB * 100) 408 * \return 0 on success otherwise a negative error code 409 */ 410 int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) 411 { 412 unsigned int caps; 413 414 CHECK_BASIC(elem); 415 caps = ((sm_selem_t *)elem->private_data)->caps; 416 if (!(caps & SM_CAP_PVOLUME)) 417 return -EINVAL; 418 if (caps & SM_CAP_PVOLUME_JOIN) 419 channel = 0; 420 return sm_selem_ops(elem)->get_dB(elem, SM_PLAY, channel, value); 421 } 422 423 /** 424 * \brief Return value of playback switch control of a mixer simple element 425 * \param elem Mixer simple element handle 426 * \param channel mixer simple element channel identifier 427 * \param value pointer to returned value 428 * \return 0 on success otherwise a negative error code 429 */ 430 int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) 431 { 432 CHECK_BASIC(elem); 433 CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel); 434 return sm_selem_ops(elem)->get_switch(elem, SM_PLAY, channel, value); 435 } 436 437 /** 438 * \brief Set value of playback volume control of a mixer simple element 439 * \param elem Mixer simple element handle 440 * \param channel mixer simple element channel identifier 441 * \param value control value 442 * \return 0 on success otherwise a negative error code 443 */ 444 int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) 445 { 446 CHECK_BASIC(elem); 447 CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); 448 return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value); 449 } 450 451 /** 452 * \brief Set value in dB of playback volume control of a mixer simple element 453 * \param elem Mixer simple element handle 454 * \param channel mixer simple element channel identifier 455 * \param value control value in dB * 100 456 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) 457 * \return 0 on success otherwise a negative error code 458 */ 459 int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) 460 { 461 CHECK_BASIC(elem); 462 CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel); 463 return sm_selem_ops(elem)->set_dB(elem, SM_PLAY, channel, value, dir); 464 } 465 466 /** 467 * \brief Set value of playback volume control for all channels of a mixer simple element 468 * \param elem Mixer simple element handle 469 * \param value control value 470 * \return 0 on success otherwise a negative error code 471 */ 472 int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value) 473 { 474 snd_mixer_selem_channel_id_t chn; 475 int err; 476 477 for (chn = 0; chn < 32; chn++) { 478 if (!snd_mixer_selem_has_playback_channel(elem, chn)) 479 continue; 480 err = snd_mixer_selem_set_playback_volume(elem, chn, value); 481 if (err < 0) 482 return err; 483 if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) 484 return 0; 485 } 486 return 0; 487 } 488 489 /** 490 * \brief Set value in dB of playback volume control for all channels of a mixer simple element 491 * \param elem Mixer simple element handle 492 * \param value control value in dB * 100 493 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) 494 * \return 0 on success otherwise a negative error code 495 */ 496 int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir) 497 { 498 snd_mixer_selem_channel_id_t chn; 499 int err; 500 501 for (chn = 0; chn < 32; chn++) { 502 if (!snd_mixer_selem_has_playback_channel(elem, chn)) 503 continue; 504 err = snd_mixer_selem_set_playback_dB(elem, chn, value, dir); 505 if (err < 0) 506 return err; 507 if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem)) 508 return 0; 509 } 510 return 0; 511 } 512 513 /** 514 * \brief Set value of playback switch control of a mixer simple element 515 * \param elem Mixer simple element handle 516 * \param channel mixer simple element channel identifier 517 * \param value control value 518 * \return 0 on success otherwise a negative error code 519 */ 520 int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) 521 { 522 CHECK_BASIC(elem); 523 CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel); 524 return sm_selem_ops(elem)->set_switch(elem, SM_PLAY, channel, value); 525 } 526 527 /** 528 * \brief Set value of playback switch control for all channels of a mixer simple element 529 * \param elem Mixer simple element handle 530 * \param value control value 531 * \return 0 on success otherwise a negative error code 532 */ 533 int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value) 534 { 535 snd_mixer_selem_channel_id_t chn; 536 int err; 537 538 CHECK_BASIC(elem); 539 for (chn = 0; chn < 32; chn++) { 540 if (!snd_mixer_selem_has_playback_channel(elem, chn)) 541 continue; 542 err = snd_mixer_selem_set_playback_switch(elem, chn, value); 543 if (err < 0) 544 return err; 545 if (chn == 0 && snd_mixer_selem_has_playback_switch_joined(elem)) 546 return 0; 547 } 548 return 0; 549 } 550 551 /** 552 * \brief Get info about channels of capture stream of a mixer simple element 553 * \param elem Mixer simple element handle 554 * \return 0 if not mono, 1 if mono 555 */ 556 int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem) 557 { 558 CHECK_BASIC(elem); 559 CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH); 560 return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_MONO, 0); 561 } 562 563 /** 564 * \brief Get info about channels of capture stream of a mixer simple element 565 * \param elem Mixer simple element handle 566 * \param channel Mixer simple element channel identifier 567 * \return 0 if channel is not present, 1 if present 568 */ 569 int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel) 570 { 571 CHECK_BASIC(elem); 572 CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH); 573 return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_CHANNEL, channel); 574 } 575 576 /** 577 * \brief Get range for capture volume of a mixer simple element 578 * \param elem Mixer simple element handle 579 * \param min Pointer to returned minimum 580 * \param max Pointer to returned maximum 581 */ 582 int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem, 583 long *min, long *max) 584 { 585 CHECK_BASIC(elem); 586 CHECK_DIR(elem, SM_CAP_CVOLUME); 587 return sm_selem_ops(elem)->get_range(elem, SM_CAPT, min, max); 588 } 589 590 /** 591 * \brief Get range in dB for capture volume of a mixer simple element 592 * \param elem Mixer simple element handle 593 * \param min Pointer to returned minimum (dB * 100) 594 * \param max Pointer to returned maximum (dB * 100) 595 */ 596 int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem, 597 long *min, long *max) 598 { 599 CHECK_BASIC(elem); 600 CHECK_DIR(elem, SM_CAP_CVOLUME); 601 return sm_selem_ops(elem)->get_dB_range(elem, SM_CAPT, min, max); 602 } 603 604 /** 605 * \brief Set range for capture volume of a mixer simple element 606 * \param elem Mixer simple element handle 607 * \param min minimum volume value 608 * \param max maximum volume value 609 */ 610 int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem, 611 long min, long max) 612 { 613 CHECK_BASIC(elem); 614 assert(min < max); 615 CHECK_DIR(elem, SM_CAP_CVOLUME); 616 return sm_selem_ops(elem)->set_range(elem, SM_CAPT, min, max); 617 } 618 619 /** 620 * \brief Return info about capture volume control of a mixer simple element 621 * \param elem Mixer simple element handle 622 * \return 0 if no control is present, 1 if it's present 623 */ 624 int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem) 625 { 626 CHECK_BASIC(elem); 627 return COND_CAPS(elem, SM_CAP_CVOLUME); 628 } 629 630 /** 631 * \brief Return info about capture volume control of a mixer simple element 632 * \param elem Mixer simple element handle 633 * \return 0 if control is separated per channel, 1 if control acts on all channels together 634 */ 635 int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem) 636 { 637 CHECK_BASIC(elem); 638 return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN); 639 } 640 641 /** 642 * \brief Return info about capture switch control existence of a mixer simple element 643 * \param elem Mixer simple element handle 644 * \return 0 if no control is present, 1 if it's present 645 */ 646 int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem) 647 { 648 CHECK_BASIC(elem); 649 return COND_CAPS(elem, SM_CAP_CSWITCH); 650 } 651 652 /** 653 * \brief Return info about capture switch control of a mixer simple element 654 * \param elem Mixer simple element handle 655 * \return 0 if control is separated per channel, 1 if control acts on all channels together 656 */ 657 int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem) 658 { 659 CHECK_BASIC(elem); 660 return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN); 661 } 662 663 /** 664 * \brief Return info about capture switch control of a mixer simple element 665 * \param elem Mixer simple element handle 666 * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group) 667 */ 668 int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem) 669 { 670 CHECK_BASIC(elem); 671 return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL); 672 } 673 674 /** 675 * \brief Return info about capture switch control of a mixer simple element 676 * \param elem Mixer simple element handle 677 * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive) 678 */ 679 int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem) 680 { 681 sm_selem_t *s; 682 CHECK_BASIC(elem); 683 s = elem->private_data; 684 if (! (s->caps & SM_CAP_CSWITCH_EXCL)) 685 return -EINVAL; 686 return s->capture_group; 687 } 688 689 /** 690 * \brief Return corresponding dB value to an integer capture volume for a mixer simple element 691 * \param elem Mixer simple element handle 692 * \param value value to be converted to dB range 693 * \param dBvalue pointer to returned dB value 694 * \return 0 on success otherwise a negative error code 695 */ 696 int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue) 697 { 698 CHECK_BASIC(elem); 699 CHECK_DIR(elem, SM_CAP_CVOLUME); 700 return sm_selem_ops(elem)->ask_vol_dB(elem, SM_CAPT, value, dBvalue); 701 } 702 703 /** 704 * \brief Return corresponding integer capture volume for given dB value for a mixer simple element 705 * \param elem Mixer simple element handle 706 * \param dBvalue dB value to be converted to integer range 707 * \param value pointer to returned integer value 708 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) 709 * \return 0 on success otherwise a negative error code 710 */ 711 int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value) 712 { 713 CHECK_BASIC(elem); 714 CHECK_DIR(elem, SM_CAP_CVOLUME); 715 return sm_selem_ops(elem)->ask_dB_vol(elem, SM_CAPT, dBvalue, value, dir); 716 } 717 718 /** 719 * \brief Return value of capture volume control of a mixer simple element 720 * \param elem Mixer simple element handle 721 * \param channel mixer simple element channel identifier 722 * \param value pointer to returned value 723 * \return 0 on success otherwise a negative error code 724 */ 725 int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) 726 { 727 CHECK_BASIC(elem); 728 CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); 729 return sm_selem_ops(elem)->get_volume(elem, SM_CAPT, channel, value); 730 } 731 732 /** 733 * \brief Return value of capture volume in dB control of a mixer simple element 734 * \param elem Mixer simple element handle 735 * \param channel mixer simple element channel identifier 736 * \param value pointer to returned value (dB * 100) 737 * \return 0 on success otherwise a negative error code 738 */ 739 int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value) 740 { 741 CHECK_BASIC(elem); 742 CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); 743 return sm_selem_ops(elem)->get_dB(elem, SM_CAPT, channel, value); 744 } 745 746 /** 747 * \brief Return value of capture switch control of a mixer simple element 748 * \param elem Mixer simple element handle 749 * \param channel mixer simple element channel identifier 750 * \param value pointer to returned value 751 * \return 0 on success otherwise a negative error code 752 */ 753 int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value) 754 { 755 CHECK_BASIC(elem); 756 CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel); 757 return sm_selem_ops(elem)->get_switch(elem, SM_CAPT, channel, value); 758 } 759 760 /** 761 * \brief Set value of capture volume control of a mixer simple element 762 * \param elem Mixer simple element handle 763 * \param channel mixer simple element channel identifier 764 * \param value control value 765 * \return 0 on success otherwise a negative error code 766 */ 767 int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value) 768 { 769 CHECK_BASIC(elem); 770 CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); 771 return sm_selem_ops(elem)->set_volume(elem, SM_CAPT, channel, value); 772 } 773 774 /** 775 * \brief Set value in dB of capture volume control of a mixer simple element 776 * \param elem Mixer simple element handle 777 * \param channel mixer simple element channel identifier 778 * \param value control value in dB * 100 779 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) 780 * \return 0 on success otherwise a negative error code 781 */ 782 int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir) 783 { 784 CHECK_BASIC(elem); 785 CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel); 786 return sm_selem_ops(elem)->set_dB(elem, SM_CAPT, channel, value, dir); 787 } 788 789 /** 790 * \brief Set value of capture volume control for all channels of a mixer simple element 791 * \param elem Mixer simple element handle 792 * \param value control value 793 * \return 0 on success otherwise a negative error code 794 */ 795 int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value) 796 { 797 snd_mixer_selem_channel_id_t chn; 798 int err; 799 800 for (chn = 0; chn < 32; chn++) { 801 if (!snd_mixer_selem_has_capture_channel(elem, chn)) 802 continue; 803 err = snd_mixer_selem_set_capture_volume(elem, chn, value); 804 if (err < 0) 805 return err; 806 if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem)) 807 return 0; 808 } 809 return 0; 810 } 811 812 /** 813 * \brief Set value in dB of capture volume control for all channels of a mixer simple element 814 * \param elem Mixer simple element handle 815 * \param value control value in dB * 100 816 * \param dir select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above) 817 * \return 0 on success otherwise a negative error code 818 */ 819 int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir) 820 { 821 snd_mixer_selem_channel_id_t chn; 822 int err; 823 824 for (chn = 0; chn < 32; chn++) { 825 if (!snd_mixer_selem_has_capture_channel(elem, chn)) 826 continue; 827 err = snd_mixer_selem_set_capture_dB(elem, chn, value, dir); 828 if (err < 0) 829 return err; 830 if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem)) 831 return 0; 832 } 833 return 0; 834 } 835 836 /** 837 * \brief Set value of capture switch control of a mixer simple element 838 * \param elem Mixer simple element handle 839 * \param channel mixer simple element channel identifier 840 * \param value control value 841 * \return 0 on success otherwise a negative error code 842 */ 843 int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value) 844 { 845 CHECK_BASIC(elem); 846 CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel); 847 return sm_selem_ops(elem)->set_switch(elem, SM_CAPT, channel, value); 848 } 849 850 /** 851 * \brief Set value of capture switch control for all channels of a mixer simple element 852 * \param elem Mixer simple element handle 853 * \param value control value 854 * \return 0 on success otherwise a negative error code 855 */ 856 int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value) 857 { 858 snd_mixer_selem_channel_id_t chn; 859 int err; 860 861 for (chn = 0; chn < 32; chn++) { 862 if (!snd_mixer_selem_has_capture_channel(elem, chn)) 863 continue; 864 err = snd_mixer_selem_set_capture_switch(elem, chn, value); 865 if (err < 0) 866 return err; 867 if (chn == 0 && snd_mixer_selem_has_capture_switch_joined(elem)) 868 return 0; 869 } 870 return 0; 871 } 872 873 /** 874 * \brief Return true if mixer simple element is an enumerated control 875 * \param elem Mixer simple element handle 876 * \return 0 normal volume/switch control, 1 enumerated control 877 */ 878 int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) 879 { 880 CHECK_BASIC(elem); 881 CHECK_ENUM(elem); 882 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0); 883 } 884 885 /** 886 * \brief Return true if mixer simple enumerated element belongs to the playback direction 887 * \param elem Mixer simple element handle 888 * \return 0 no playback direction, 1 playback direction 889 */ 890 int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem) 891 { 892 CHECK_BASIC(elem); 893 CHECK_ENUM(elem); 894 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1); 895 } 896 897 /** 898 * \brief Return true if mixer simple enumerated element belongs to the capture direction 899 * \param elem Mixer simple element handle 900 * \return 0 no capture direction, 1 capture direction 901 */ 902 int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem) 903 { 904 CHECK_BASIC(elem); 905 CHECK_ENUM(elem); 906 return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1); 907 } 908 909 /** 910 * \brief Return the number of enumerated items of the given mixer simple element 911 * \param elem Mixer simple element handle 912 * \return the number of enumerated items, otherwise a negative error code 913 */ 914 int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) 915 { 916 CHECK_BASIC(elem); 917 CHECK_ENUM(elem); 918 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0); 919 } 920 921 /** 922 * \brief get the enumerated item string for the given mixer simple element 923 * \param elem Mixer simple element handle 924 * \param item the index of the enumerated item to query 925 * \param maxlen the maximal length to be stored 926 * \param buf the buffer to store the name string 927 * \return 0 if successful, otherwise a negative error code 928 */ 929 int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, 930 unsigned int item, 931 size_t maxlen, char *buf) 932 { 933 CHECK_BASIC(elem); 934 CHECK_ENUM(elem); 935 return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf); 936 } 937 938 /** 939 * \brief get the current selected enumerated item for the given mixer simple element 940 * \param elem Mixer simple element handle 941 * \param channel mixer simple element channel identifier 942 * \param itemp the pointer to store the index of the enumerated item 943 * \return 0 if successful, otherwise a negative error code 944 */ 945 int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, 946 snd_mixer_selem_channel_id_t channel, 947 unsigned int *itemp) 948 { 949 CHECK_BASIC(elem); 950 CHECK_ENUM(elem); 951 return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp); 952 } 953 954 /** 955 * \brief set the current selected enumerated item for the given mixer simple element 956 * \param elem Mixer simple element handle 957 * \param channel mixer simple element channel identifier 958 * \param item the enumerated item index 959 * \return 0 if successful, otherwise a negative error code 960 */ 961 int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, 962 snd_mixer_selem_channel_id_t channel, 963 unsigned int item) 964 { 965 CHECK_BASIC(elem); 966 CHECK_ENUM(elem); 967 return sm_selem_ops(elem)->set_enum_item(elem, channel, item); 968 } 969 970 /** 971 * \brief get size of #snd_mixer_selem_id_t 972 * \return size in bytes 973 */ 974 size_t snd_mixer_selem_id_sizeof() 975 { 976 return sizeof(snd_mixer_selem_id_t); 977 } 978 979 /** 980 * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc 981 * \param ptr returned pointer 982 * \return 0 on success otherwise negative error code 983 */ 984 int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr) 985 { 986 assert(ptr); 987 *ptr = calloc(1, sizeof(snd_mixer_selem_id_t)); 988 if (!*ptr) 989 return -ENOMEM; 990 return 0; 991 } 992 993 /** 994 * \brief frees a previously allocated #snd_mixer_selem_id_t 995 * \param obj pointer to object to free 996 */ 997 void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj) 998 { 999 free(obj); 1000 } 1001 1002 /** 1003 * \brief copy one #snd_mixer_selem_id_t to another 1004 * \param dst pointer to destination 1005 * \param src pointer to source 1006 */ 1007 void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src) 1008 { 1009 assert(dst && src); 1010 *dst = *src; 1011 } 1012 1013 /** 1014 * \brief Get name part of a mixer simple element identifier 1015 * \param obj Mixer simple element identifier 1016 * \return name part 1017 */ 1018 const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj) 1019 { 1020 assert(obj); 1021 return obj->name; 1022 } 1023 1024 /** 1025 * \brief Get index part of a mixer simple element identifier 1026 * \param obj Mixer simple element identifier 1027 * \return index part 1028 */ 1029 unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj) 1030 { 1031 assert(obj); 1032 return obj->index; 1033 } 1034 1035 /** 1036 * \brief Set name part of a mixer simple element identifier 1037 * \param obj Mixer simple element identifier 1038 * \param val name part 1039 */ 1040 void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val) 1041 { 1042 assert(obj); 1043 strncpy(obj->name, val, sizeof(obj->name)); 1044 obj->name[sizeof(obj->name)-1] = '\0'; 1045 } 1046 1047 /** 1048 * \brief Set index part of a mixer simple element identifier 1049 * \param obj Mixer simple element identifier 1050 * \param val index part 1051 */ 1052 void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val) 1053 { 1054 assert(obj); 1055 obj->index = val; 1056 } 1057