1/** 2 * \file mixer/simple.c 3 * \brief Mixer Simple Element Class Interface 4 * \author Jaroslav Kysela <perex@perex.cz> 5 * \author Abramo Bagnara <abramo@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@perex.cz> 13 * Copyright (c) 2001 by Abramo Bagnara <abramo@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 */ 49int 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 115int 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 */ 132snd_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 */ 155void 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 */ 170const 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 */ 183unsigned 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 */ 196int 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 */ 207int 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 */ 218const 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 */ 244int 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 */ 255int 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 */ 267int 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 */ 279int 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 */ 293int 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 */ 307int 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 */ 321int 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 */ 332int 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 */ 343int 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 */ 354int 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 */ 367int 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 */ 382int 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 */ 396int 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 */ 410int 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 */ 430int 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 */ 444int 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 */ 459int 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 */ 472int 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 */ 496int 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 */ 520int 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 */ 533int 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 */ 556int 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 */ 569int 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 */ 582int 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 */ 596int 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 */ 610int 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 */ 624int 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 */ 635int 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 */ 646int 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 */ 657int 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 */ 668int 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 */ 679int 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 */ 696int 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 */ 711int 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 */ 725int 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 */ 739int 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 */ 753int 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 */ 767int 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 */ 782int 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 */ 795int 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 */ 819int 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 */ 843int 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 */ 856int 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 */ 878int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem) 879{ 880 CHECK_BASIC(elem); 881 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0); 882} 883 884/** 885 * \brief Return true if mixer simple enumerated element belongs to the playback direction 886 * \param elem Mixer simple element handle 887 * \return 0 no playback direction, 1 playback direction 888 */ 889int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem) 890{ 891 CHECK_BASIC(elem); 892 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1); 893} 894 895/** 896 * \brief Return true if mixer simple enumerated element belongs to the capture direction 897 * \param elem Mixer simple element handle 898 * \return 0 no capture direction, 1 capture direction 899 */ 900int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem) 901{ 902 CHECK_BASIC(elem); 903 return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1); 904} 905 906/** 907 * \brief Return the number of enumerated items of the given mixer simple element 908 * \param elem Mixer simple element handle 909 * \return the number of enumerated items, otherwise a negative error code 910 */ 911int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem) 912{ 913 CHECK_BASIC(elem); 914 CHECK_ENUM(elem); 915 return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0); 916} 917 918/** 919 * \brief get the enumerated item string for the given mixer simple element 920 * \param elem Mixer simple element handle 921 * \param item the index of the enumerated item to query 922 * \param maxlen the maximal length to be stored 923 * \param buf the buffer to store the name string 924 * \return 0 if successful, otherwise a negative error code 925 */ 926int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem, 927 unsigned int item, 928 size_t maxlen, char *buf) 929{ 930 CHECK_BASIC(elem); 931 CHECK_ENUM(elem); 932 return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf); 933} 934 935/** 936 * \brief get the current selected enumerated item for the given mixer simple element 937 * \param elem Mixer simple element handle 938 * \param channel mixer simple element channel identifier 939 * \param itemp the pointer to store the index of the enumerated item 940 * \return 0 if successful, otherwise a negative error code 941 */ 942int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem, 943 snd_mixer_selem_channel_id_t channel, 944 unsigned int *itemp) 945{ 946 CHECK_BASIC(elem); 947 CHECK_ENUM(elem); 948 return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp); 949} 950 951/** 952 * \brief set the current selected enumerated item for the given mixer simple element 953 * \param elem Mixer simple element handle 954 * \param channel mixer simple element channel identifier 955 * \param item the enumerated item index 956 * \return 0 if successful, otherwise a negative error code 957 */ 958int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem, 959 snd_mixer_selem_channel_id_t channel, 960 unsigned int item) 961{ 962 CHECK_BASIC(elem); 963 CHECK_ENUM(elem); 964 return sm_selem_ops(elem)->set_enum_item(elem, channel, item); 965} 966 967/** 968 * \brief get size of #snd_mixer_selem_id_t 969 * \return size in bytes 970 */ 971size_t snd_mixer_selem_id_sizeof() 972{ 973 return sizeof(snd_mixer_selem_id_t); 974} 975 976/** 977 * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc 978 * \param ptr returned pointer 979 * \return 0 on success otherwise negative error code 980 */ 981int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr) 982{ 983 assert(ptr); 984 *ptr = calloc(1, sizeof(snd_mixer_selem_id_t)); 985 if (!*ptr) 986 return -ENOMEM; 987 return 0; 988} 989 990/** 991 * \brief frees a previously allocated #snd_mixer_selem_id_t 992 * \param obj pointer to object to free 993 */ 994void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj) 995{ 996 free(obj); 997} 998 999/** 1000 * \brief copy one #snd_mixer_selem_id_t to another 1001 * \param dst pointer to destination 1002 * \param src pointer to source 1003 */ 1004void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src) 1005{ 1006 assert(dst && src); 1007 *dst = *src; 1008} 1009 1010/** 1011 * \brief Get name part of a mixer simple element identifier 1012 * \param obj Mixer simple element identifier 1013 * \return name part 1014 */ 1015const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj) 1016{ 1017 assert(obj); 1018 return obj->name; 1019} 1020 1021/** 1022 * \brief Get index part of a mixer simple element identifier 1023 * \param obj Mixer simple element identifier 1024 * \return index part 1025 */ 1026unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj) 1027{ 1028 assert(obj); 1029 return obj->index; 1030} 1031 1032/** 1033 * \brief Set name part of a mixer simple element identifier 1034 * \param obj Mixer simple element identifier 1035 * \param val name part 1036 */ 1037void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val) 1038{ 1039 assert(obj); 1040 strncpy(obj->name, val, sizeof(obj->name)); 1041 obj->name[sizeof(obj->name)-1] = '\0'; 1042} 1043 1044/** 1045 * \brief Set index part of a mixer simple element identifier 1046 * \param obj Mixer simple element identifier 1047 * \param val index part 1048 */ 1049void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val) 1050{ 1051 assert(obj); 1052 obj->index = val; 1053} 1054