gf_ai_box/include/modules/audiotk/audio_vol_ctrl.c
2026-04-12 17:47:54 +08:00

1486 lines
41 KiB
C

/*
*******************************************************************************
* Copyright (c) 2010-2022 VATICS(KNERON) Inc. All rights reserved.
*
* +-----------------------------------------------------------------+
* | THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED |
* | AND COPIED IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF SUCH |
* | A LICENSE AND WITH THE INCLUSION OF THE THIS COPY RIGHT NOTICE. |
* | THIS SOFTWARE OR ANY OTHER COPIES OF THIS SOFTWARE MAY NOT BE |
* | PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. THE |
* | OWNERSHIP AND TITLE OF THIS SOFTWARE IS NOT TRANSFERRED. |
* | |
* | THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT |
* | ANY PRIOR NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY |
* | VATICS(KNERON) INC. |
* +-----------------------------------------------------------------+
*
*******************************************************************************
*/
#include <audio_vol_ctrl.h>
#include <string.h>
#include <math.h>
//#define VTCS_AUDIO_CTRL
typedef struct
{
int (*has_volume)(snd_mixer_elem_t *elem);
int (*get_volume_range)(snd_mixer_elem_t *elem, long *min, long *max);
int (*set_volume_all)(snd_mixer_elem_t *elem, long value);
int (*set_volume)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value);
int (*get_volume)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
int (*get_dB_range)(snd_mixer_elem_t *elem, long *min, long *max);
int (*set_dB_all)(snd_mixer_elem_t *elem, long value, int dir);
int (*set_dB)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir);
int (*get_dB)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value);
int (*has_switch)(snd_mixer_elem_t *elem);
int (*set_switch_all)(snd_mixer_elem_t *elem, int value);
int (*set_switch)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value);
int (*get_switch)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value);
} mixer_ops_t;
static mixer_ops_t mixer_ops_funcs[2] = {
{
.has_volume = snd_mixer_selem_has_playback_volume,
.get_volume_range = snd_mixer_selem_get_playback_volume_range,
.set_volume_all = snd_mixer_selem_set_playback_volume_all,
.set_volume = snd_mixer_selem_set_playback_volume,
.get_volume = snd_mixer_selem_get_playback_volume,
.get_dB_range = snd_mixer_selem_get_playback_dB_range,
.set_dB_all = snd_mixer_selem_set_playback_dB_all,
.set_dB = snd_mixer_selem_set_playback_dB,
.get_dB = snd_mixer_selem_get_playback_dB,
.has_switch = snd_mixer_selem_has_playback_switch,
.set_switch_all = snd_mixer_selem_set_playback_switch_all,
.set_switch = snd_mixer_selem_set_playback_switch,
.get_switch = snd_mixer_selem_get_playback_switch
},
{
.has_volume = snd_mixer_selem_has_capture_volume,
.get_volume_range = snd_mixer_selem_get_capture_volume_range,
.set_volume_all = snd_mixer_selem_set_capture_volume_all,
.set_volume = snd_mixer_selem_set_capture_volume,
.get_volume = snd_mixer_selem_get_capture_volume,
.get_dB_range = snd_mixer_selem_get_capture_dB_range,
.set_dB_all = snd_mixer_selem_set_capture_dB_all,
.set_dB = snd_mixer_selem_set_capture_dB,
.get_dB = snd_mixer_selem_get_capture_dB,
.has_switch = snd_mixer_selem_has_capture_switch,
.set_switch_all = snd_mixer_selem_set_capture_switch_all,
.set_switch = snd_mixer_selem_set_capture_switch,
.get_switch = snd_mixer_selem_get_capture_switch
}
};
/**
* @brief Function to help to find a element.
*
* @param[in] handle The handle for ALSA mixer.
* @param[in] config The configuration for mixer.
* @return NULL: Failed, otherwise: element.
*/
static snd_mixer_elem_t* mixer_find_elem_helper(snd_mixer_t *handle, const ATK_AUDIO_SCTRL_CONFIG_T *config)
{
if((handle == NULL) || (config == NULL))
{
return NULL;
}
snd_mixer_selem_id_t *sid = NULL;
const char *card = (config->szCard) ? (config->szCard) : "default";
int err = 0;
// Attach an HCTL specified with the CTL device name to an opened mixer.
if((err = snd_mixer_attach(handle, card)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't attach control. %s\n", __FILE__, __func__, snd_strerror(err));
return NULL;
}
// Register mixer simple element class.
if((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't register mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return NULL;
}
// Load a mixer elements.
if((err = snd_mixer_load(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't load mixer elements. %s\n", __FILE__, __func__, snd_strerror(err));
return NULL;
}
snd_mixer_selem_id_alloca(&sid);
// Set index part of a mixer simple element identifier.
snd_mixer_selem_id_set_index(sid, config->dwSelemIndex);
// Set name part of a mixer simple element identifier.
snd_mixer_selem_id_set_name(sid, ((config->szSelemName) ? (config->szSelemName) : "Master"));
// Find a mixer simple element.
return snd_mixer_find_selem(handle, sid);
}
/**
* @brief Function to convert the volume from one range to another range.
*
* @param[in] from_vol The volume need to be converted.
* @param[in] from_vol_max The max volume of original range.
* @param[in] from_vol_min The min volume of original range.
* @param[in] to_vol_max The max volume of new range.
* @param[in] to_vol_min The min volume of new range.
* @return The new volume in the new range ('to' range).
*/
static long convert_range_vol(long from_vol, long from_vol_max, long from_vol_min, long to_vol_max, long to_vol_min)
{
if((from_vol >= from_vol_max) || (from_vol_max == from_vol_min))
{
return to_vol_max - 1;
}
if(from_vol <= from_vol_min)
{
return 0;
}
return (((float)((from_vol - from_vol_min)*(to_vol_max - to_vol_min - 2 )) / (float)(from_vol_max - from_vol_min) + to_vol_min) + 1);
}
int ATK_Audio_SCtrl_SetVolume(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, long lVol)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
long vol_min = 0;
long vol_max = 0;
if((ptConfig == NULL) || (lVol < 0) || (lVol > 100))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
mixer_ops_funcs[stream_idx].get_volume_range(elem, &vol_min, &vol_max);
if((err = mixer_ops_funcs[stream_idx].set_volume_all(elem, convert_range_vol(lVol, 100, 0, vol_max, vol_min))) < 0)
{
fprintf(stderr, "[%s, %s]: Can't set volume. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_SetChannelVolume(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, long lVol)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
long vol_min = 0;
long vol_max = 0;
if((ptConfig == NULL) || (lVol < 0) || (lVol > 100))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
mixer_ops_funcs[stream_idx].get_volume_range(elem, &vol_min, &vol_max);
if((err = mixer_ops_funcs[stream_idx].set_volume(elem, eChannelId, convert_range_vol(lVol, 100, 0, vol_max, vol_min))) < 0)
{
fprintf(stderr, "[%s, %s]: Can't set volume. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_GetChannelVolume(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, long *plVol)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
long vol_min = 0;
long vol_max = 0;
long hw_vol = 0;
if((ptConfig == NULL) || (plVol == NULL))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
mixer_ops_funcs[stream_idx].get_volume_range(elem, &vol_min, &vol_max);
if((err = mixer_ops_funcs[stream_idx].get_volume(elem, eChannelId, &hw_vol)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't get volume.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -1;
}
*plVol = convert_range_vol(hw_vol, vol_max, vol_min, 100, 0);
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_SetVolume_dB(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, long lVol)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if(ptConfig == NULL)
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].set_dB_all(elem, lVol*100, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't set volume in dB. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_SetChannelVolume_dB(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, long lVol)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if(ptConfig == NULL)
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].set_dB(elem, eChannelId, lVol*100, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't set volume. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_GetChannelVolume_dB(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, long *plVol)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if((ptConfig == NULL) || (plVol == NULL))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].get_dB(elem, eChannelId, plVol)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't get volume.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -1;
}
*plVol /= 100;
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_GetVolume_Range_dB(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, long *plMin, long *plMax)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if((ptConfig == NULL) || (plMin == NULL) || (plMax == NULL))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_volume(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].get_dB_range(elem, plMin, plMax)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't get volume.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -1;
}
*plMin /= 100;
*plMax /= 100;
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_SetSwitch(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, int bIsOn)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if(ptConfig == NULL)
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_switch(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].set_switch_all(elem, bIsOn)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't turn on or off. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_SetChannelSwitch(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, int bIsOn)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if(ptConfig == NULL)
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_switch(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].set_switch(elem, eChannelId, bIsOn)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't mute. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_GetChannelSwitch(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, int *pbIsOn)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if((ptConfig == NULL) || (pbIsOn == NULL))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
int stream_idx = ptConfig->eStream;
if(mixer_ops_funcs[stream_idx].has_switch(elem) == 1)
{
if((err = mixer_ops_funcs[stream_idx].get_switch(elem, eChannelId, pbIsOn)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't mute. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
}
else
{
fprintf(stderr, "[%s, %s]: Warning! No volumn control.\n", __FILE__, __func__);
snd_mixer_close(handle);
return -2;
}
if((err = snd_mixer_close(handle)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close mixer. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
int ATK_Audio_SCtrl_Set_Enumerated(const ATK_AUDIO_SCTRL_CONFIG_T *ptConfig, snd_mixer_selem_channel_id_t eChannelId, const char *szEnumStr)
{
int err = 0;
snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem = NULL;
if((ptConfig == NULL) || (szEnumStr == NULL))
{
return -1;
}
if((err = snd_mixer_open(&handle, 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open mixer. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
elem = mixer_find_elem_helper(handle, ptConfig);
if(elem == NULL)
{
snd_mixer_close(handle);
return -1;
}
if(snd_mixer_selem_is_enumerated(elem))
{
int items = snd_mixer_selem_get_enum_items(elem);
if(items < 0)
{
snd_mixer_close(handle);
return -1;
}
char name[128] = {'\0'};
for(int i = 0; i < items; ++i)
{
if(snd_mixer_selem_get_enum_item_name(elem, i, sizeof(name)-1, name) < 0)
{
continue;
}
if(strcmp(name, szEnumStr) == 0)
{
if((err = snd_mixer_selem_set_enum_item(elem, eChannelId, i)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't set enumerated value. %s\n", __FILE__, __func__, snd_strerror(err));
snd_mixer_close(handle);
return -1;
}
snd_mixer_close(handle);
return 0;
}
}
}
snd_mixer_close(handle);
return -1;
}
int ATK_Audio_Ctrl_Set_Int_Or_Bool(const ATK_AUDIO_CTRL_CONFIG_T *ptConfig, unsigned int dwIdx, long lVal)
{
int err = 0;
snd_hctl_t *hctl = NULL;
snd_ctl_elem_id_t *id = NULL;
snd_hctl_elem_t *elem = NULL;
snd_ctl_elem_value_t *control = NULL;
snd_ctl_elem_info_t *info = NULL;
snd_ctl_elem_type_t type;
if(ptConfig == NULL)
{
return -1;
}
if((err = snd_hctl_open(&hctl, (ptConfig->szCard) ? (ptConfig->szCard) : "hw:0", 0)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't open hight level control. %s\n", __FILE__, __func__, snd_strerror(err));
return -1;
}
if((err = snd_hctl_load(hctl)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't load all elements for hight level control. %s\n", __FILE__, __func__, snd_strerror(err));
snd_hctl_close(hctl);
return -1;
}
snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
snd_ctl_elem_id_set_name(id, ptConfig->szElemName);
elem = snd_hctl_find_elem(hctl, id);
if(elem == NULL)
{
fprintf(stderr, "[%s, %s]: Can't find element %s.\n", __FILE__, __func__, ptConfig->szElemName);
snd_hctl_close(hctl);
return -1;
}
snd_ctl_elem_info_alloca(&info);
if((err = snd_hctl_elem_info(elem, info)) < 0)
{
fprintf(stderr, "[%s, %s]: snd_hctl_elem_info error: %s.\n", __FILE__, __func__, snd_strerror(err));
snd_hctl_close(hctl);
return -1;
}
type = snd_ctl_elem_info_get_type(info);
snd_ctl_elem_value_alloca(&control);
snd_ctl_elem_value_set_id(control, id);
switch(type)
{
case SND_CTL_ELEM_TYPE_BOOLEAN:
snd_ctl_elem_value_set_boolean(control, dwIdx, lVal);
break;
case SND_CTL_ELEM_TYPE_INTEGER:
snd_ctl_elem_value_set_integer(control, dwIdx, lVal);
break;
default:
// We don't use SND_CTL_ELEM_TYPE_INTEGER64
fprintf(stderr, "[%s, %s]: Unsupport element type.\n", __FILE__, __func__);
snd_hctl_close(hctl);
return -1;
}
if((err = snd_hctl_elem_write(elem, control)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't write the value to element. %s\n", __FILE__, __func__, snd_strerror(err));
snd_hctl_close(hctl);
return -1;
}
if((err = snd_hctl_close(hctl)) < 0)
{
fprintf(stderr, "[%s, %s]: Can't close hight level control. %s\n", __FILE__, __func__, snd_strerror(err));
}
return 0;
}
static int atk_audio_set_capture_volume(long vol, int mode)
{
ATK_AUDIO_SCTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_SCTRL_CONFIG_T));
typedef int (*set_vol_func_ptr)(const ATK_AUDIO_SCTRL_CONFIG_T *config, long vol);
set_vol_func_ptr set_func = (mode) ? ATK_Audio_SCtrl_SetVolume_dB : ATK_Audio_SCtrl_SetVolume;
#ifdef VTCS_AUDIO_CTRL
int ret = 0;
int ret2 = 0;
audio_config.eStream = SND_PCM_STREAM_CAPTURE;
audio_config.szSelemName = "Capture";
ret = set_func(&audio_config, vol);
audio_config.eStream = SND_PCM_STREAM_CAPTURE;
audio_config.szSelemName = "Input";
ret2 = set_func(&audio_config, vol);
return ((ret == 0) || (ret2 == 0)) ? 0 : -1;
#else
audio_config.eStream = SND_PCM_STREAM_CAPTURE;
audio_config.szSelemName = "Capture";
return set_func(&audio_config, vol);
#endif
}
int ATK_Audio_SetCaptureVolume(long lVol)
{
return atk_audio_set_capture_volume(lVol, 0);
}
int ATK_Audio_SetCaptureVolume_dB(long lVol)
{
return atk_audio_set_capture_volume(lVol, 1);
}
/*
* PGA vol control
* */
static int atk_audio_set_capture_pga(long vol, int mode)
{
ATK_AUDIO_SCTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_SCTRL_CONFIG_T));
typedef int (*set_vol_func_ptr)(const ATK_AUDIO_SCTRL_CONFIG_T *config, long vol);
set_vol_func_ptr set_func = (mode) ? ATK_Audio_SCtrl_SetVolume_dB : ATK_Audio_SCtrl_SetVolume;
audio_config.eStream = SND_PCM_STREAM_CAPTURE;
audio_config.szSelemName = "PGA";
return set_func(&audio_config, vol);
}
int ATK_Audio_SetCapturePga(long lPga)
{
return atk_audio_set_capture_pga(lPga, 0);
}
int ATK_Audio_SetCapturePga_dB(long lPga)
{
return atk_audio_set_capture_pga(lPga, 1);
}
/*
* PGA ends
* */
int ATK_Audio_SetCaptureMute(int bIsMute, TK_AUDIO_INPUT_TYPE eType)
{
#ifdef VTCS_AUDIO_CTRL
int err = 0;
int err2 = 0;
int err3 = 0;
ATK_AUDIO_CTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_CTRL_CONFIG_T));
audio_config.szElemName = "Mic Mute";
err = ATK_Audio_Ctrl_Set_Int_Or_Bool(&audio_config, 0, bIsMute);
err2 = ATK_Audio_SetCaptureVolume((bIsMute) ? 0 : 100);
audio_config.szElemName = "Left ADC mute";
err3 = ATK_Audio_Ctrl_Set_Int_Or_Bool(&audio_config, 0, bIsMute);
return ((err == 0) || (err2 == 0) || (err3 == 0)) ? 0 : -1;
#else
int err = -1;
int err2 = 0;
ATK_AUDIO_SCTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_SCTRL_CONFIG_T));
audio_config.eStream = SND_PCM_STREAM_CAPTURE;
//audio_config.szSelemName = "Capture";
//err = ATK_Audio_SCtrl_SetSwitch(&audio_config, !bIsMute);
switch(eType)
{
case kTKAudioMicIn:
audio_config.szSelemName = "Mic";
err2 = ATK_Audio_SCtrl_SetSwitch(&audio_config, !bIsMute);
break;
case kTKAudioLineIn:
audio_config.szSelemName = "Line";
err2 = ATK_Audio_SCtrl_SetSwitch(&audio_config, !bIsMute);
break;
case kTKAudioByPass:
break;
default:
err2 = -1;
break;
}
return ((err == 0) || (err2 == 0)) ? 0 : -1;
#endif
}
int ATK_Audio_InputSelection(TK_AUDIO_INPUT_TYPE eType)
{
#if 1 //def VTCS_AUDIO_CTRL
ATK_AUDIO_CTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_CTRL_CONFIG_T));
if(eType != kTKAudioByPass)
{
//audio drivers use different "control anme".
audio_config.szElemName = "Input Select"; //Pesaro built-in audio codec.
// Line in: 0, Mic in (single ended): 2, Mic in (differential): 4
if (ATK_Audio_Ctrl_Set_Int_Or_Bool(&audio_config, 0, ((eType == kTKAudioMicIn) ? 2 : 0)) == 0)
return 0;
//other audio codec for Mozart 3s
audio_config.szElemName = "Input Type";
if (ATK_Audio_Ctrl_Set_Int_Or_Bool(&audio_config, 0, ((eType == kTKAudioMicIn) ? 0 : 1)) == 0)
return 0;
audio_config.szElemName = "Input Selection";
if(ATK_Audio_Ctrl_Set_Int_Or_Bool(&audio_config, 0, ((eType == kTKAudioMicIn) ? 2 : 1)) == 0)
return 0;
return -1;
}
audio_config.szElemName = "Input Selection";
return ATK_Audio_Ctrl_Set_Int_Or_Bool(&audio_config, 0, 0);
#else
int err = 0, err2 = 0, err3 = 0, err4 = 0;
ATK_AUDIO_SCTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_SCTRL_CONFIG_T));
audio_config.eStream = SND_PCM_STREAM_CAPTURE;
switch(eType)
{
case kTKAudioMicIn:
audio_config.szSelemName = "Bypass Capture";
err = ATK_Audio_SCtrl_SetSwitch(&audio_config, 0);
audio_config.szSelemName = "Line";
err2 = ATK_Audio_SCtrl_SetSwitch(&audio_config, 0);
audio_config.szSelemName = "Mic";
err3 = ATK_Audio_SCtrl_SetSwitch(&audio_config, 1);
audio_config.szSelemName = "Capture Source";
err4 = ATK_Audio_SCtrl_Set_Enumerated(&audio_config, 0, "Mic");
break;
case kTKAudioLineIn:
audio_config.szSelemName = "Bypass Capture";
err = ATK_Audio_SCtrl_SetSwitch(&audio_config, 0);
audio_config.szSelemName = "Mic";
err2 = ATK_Audio_SCtrl_SetSwitch(&audio_config, 0);
audio_config.szSelemName = "Line";
err3 = ATK_Audio_SCtrl_SetSwitch(&audio_config, 1);
audio_config.szSelemName = "Capture Source";
err4 = ATK_Audio_SCtrl_Set_Enumerated(&audio_config, 0, "Line");
break;
case kTKAudioByPass:
audio_config.szSelemName = "Line";
err = ATK_Audio_SCtrl_SetSwitch(&audio_config, 0);
audio_config.szSelemName = "Mic";
err2 = ATK_Audio_SCtrl_SetSwitch(&audio_config, 0);
audio_config.szSelemName = "Bypass Capture";
err3 = ATK_Audio_SCtrl_SetSwitch(&audio_config, 1);
break;
default:
return -1;
}
return ((err == 0) && (err2 == 0) && (err3 == 0) && (err4 == 0)) ? 0 : -1;
#endif
}
static int atk_audio_set_playback_volume(long vol, int mode)
{
int err = 0, err2 = 0;
typedef int (*set_vol_func_ptr)(const ATK_AUDIO_SCTRL_CONFIG_T *config, long vol);
set_vol_func_ptr set_func = (mode) ? ATK_Audio_SCtrl_SetVolume_dB : ATK_Audio_SCtrl_SetVolume;
ATK_AUDIO_SCTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_SCTRL_CONFIG_T));
audio_config.eStream = SND_PCM_STREAM_PLAYBACK;
audio_config.szSelemName = "Master";
err = set_func(&audio_config, vol);
audio_config.szSelemName = "Playback";
err2 = set_func(&audio_config, vol);
return ((err == 0) || (err2 == 0)) ? 0 : -1;
}
int ATK_Audio_SetPlaybackVolume(long lVol)
{
return atk_audio_set_playback_volume(lVol, 0);
}
int ATK_Audio_SetPlaybackVolume_dB(long lVol)
{
return atk_audio_set_playback_volume(lVol, 1);
}
int ATK_Audio_SetPlaybackMute(int bIsMute)
{
int err = 0, err2 = 0;
ATK_AUDIO_SCTRL_CONFIG_T audio_config;
memset(&audio_config, 0, sizeof(ATK_AUDIO_SCTRL_CONFIG_T));
audio_config.eStream = SND_PCM_STREAM_PLAYBACK;
audio_config.szSelemName = "Master";
err = ATK_Audio_SCtrl_SetSwitch(&audio_config, !bIsMute);
audio_config.szSelemName = "Playback";
err2 = ATK_Audio_SCtrl_SetSwitch(&audio_config, !bIsMute);
return ((err == 0) || (err2 == 0)) ? 0 : -1;
}
#define LEVEL_BASIC (1<<0)
/* Fuction to convert from volume to percentage. val = volume */
static int convert_prange(int val, int min, int max)
{
int range = max - min;
int tmp;
if (range == 0)
return 0;
val -= min;
tmp = rint((double)val/(double)range * 100);
return tmp;
}
/* Function to convert from percentage to volume. val = percentage */
#define convert_prange1(val, min, max) \
ceil((val) * ((max) - (min)) * 0.01 + (min))
static const char *get_percent(int val, int min, int max)
{
static char str[32];
int p;
p = convert_prange(val, min, max);
sprintf(str, "%i [%i%%]", val, p);
return str;
}
static void print_dB(long dB)
{
printf("%li.%02lidB", dB / 100, (dB < 0 ? -dB : dB) % 100);
}
int show_selem(snd_mixer_t *handle, snd_mixer_selem_id_t *id, const char *space, int level)
{
snd_mixer_selem_channel_id_t chn;
long pmin = 0, pmax = 0;
long cmin = 0, cmax = 0;
long pvol, cvol;
int psw, csw;
int pmono, cmono, mono_ok = 0;
long db;
snd_mixer_elem_t *elem;
const char *card = "default";
elem = snd_mixer_find_selem(handle, id);
if (!elem) {
printf("Mixer %s simple element not found", card);
return -ENOENT;
}
if (level & LEVEL_BASIC) {
printf("%sCapabilities:", space);
if (snd_mixer_selem_has_common_volume(elem)) {
printf(" volume");
if (snd_mixer_selem_has_playback_volume_joined(elem))
printf(" volume-joined");
} else {
if (snd_mixer_selem_has_playback_volume(elem)) {
printf(" pvolume");
if (snd_mixer_selem_has_playback_volume_joined(elem))
printf(" pvolume-joined");
}
if (snd_mixer_selem_has_capture_volume(elem)) {
printf(" cvolume");
if (snd_mixer_selem_has_capture_volume_joined(elem))
printf(" cvolume-joined");
}
}
if (snd_mixer_selem_has_common_switch(elem)) {
printf(" switch");
if (snd_mixer_selem_has_playback_switch_joined(elem))
printf(" switch-joined");
} else {
if (snd_mixer_selem_has_playback_switch(elem)) {
printf(" pswitch");
if (snd_mixer_selem_has_playback_switch_joined(elem))
printf(" pswitch-joined");
}
if (snd_mixer_selem_has_capture_switch(elem)) {
printf(" cswitch");
if (snd_mixer_selem_has_capture_switch_joined(elem))
printf(" cswitch-joined");
if (snd_mixer_selem_has_capture_switch_exclusive(elem))
printf(" cswitch-exclusive");
}
}
if (snd_mixer_selem_is_enum_playback(elem)) {
printf(" penum");
} else if (snd_mixer_selem_is_enum_capture(elem)) {
printf(" cenum");
} else if (snd_mixer_selem_is_enumerated(elem)) {
printf(" enum");
}
printf("\n");
if (snd_mixer_selem_is_enumerated(elem)) {
int i, items;
unsigned int idx;
char itemname[40];
items = snd_mixer_selem_get_enum_items(elem);
printf(" Items:");
for (i = 0; i < items; i++) {
snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname);
printf(" '%s'", itemname);
}
printf("\n");
for (i = 0; !snd_mixer_selem_get_enum_item(elem, i, &idx); i++) {
snd_mixer_selem_get_enum_item_name(elem, idx, sizeof(itemname) - 1, itemname);
printf(" Item%d: '%s'\n", i, itemname);
}
return 0; /* no more thing to do */
}
if (snd_mixer_selem_has_capture_switch_exclusive(elem))
printf("%sCapture exclusive group: %i\n", space,
snd_mixer_selem_get_capture_group(elem));
if (snd_mixer_selem_has_playback_volume(elem) ||
snd_mixer_selem_has_playback_switch(elem)) {
printf("%sPlayback channels:", space);
if (snd_mixer_selem_is_playback_mono(elem)) {
printf(" Mono");
} else {
int first = 1;
for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){
if (!snd_mixer_selem_has_playback_channel(elem, chn))
continue;
if (!first)
printf(" -");
printf(" %s", snd_mixer_selem_channel_name(chn));
first = 0;
}
}
printf("\n");
}
if (snd_mixer_selem_has_capture_volume(elem) ||
snd_mixer_selem_has_capture_switch(elem)) {
printf("%sCapture channels:", space);
if (snd_mixer_selem_is_capture_mono(elem)) {
printf(" Mono");
} else {
int first = 1;
for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){
if (!snd_mixer_selem_has_capture_channel(elem, chn))
continue;
if (!first)
printf(" -");
printf(" %s", snd_mixer_selem_channel_name(chn));
first = 0;
}
}
printf("\n");
}
if (snd_mixer_selem_has_playback_volume(elem) ||
snd_mixer_selem_has_capture_volume(elem)) {
printf("%sLimits:", space);
if (snd_mixer_selem_has_common_volume(elem)) {
snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax);
printf(" %li - %li", pmin, pmax);
} else {
if (snd_mixer_selem_has_playback_volume(elem)) {
snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
printf(" Playback %li - %li", pmin, pmax);
}
if (snd_mixer_selem_has_capture_volume(elem)) {
snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax);
printf(" Capture %li - %li", cmin, cmax);
}
}
printf("\n");
}
pmono = snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO) &&
(snd_mixer_selem_is_playback_mono(elem) ||
(!snd_mixer_selem_has_playback_volume(elem) &&
!snd_mixer_selem_has_playback_switch(elem)));
cmono = snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO) &&
(snd_mixer_selem_is_capture_mono(elem) ||
(!snd_mixer_selem_has_capture_volume(elem) &&
!snd_mixer_selem_has_capture_switch(elem)));
if (pmono || cmono) {
if (!mono_ok) {
printf("%s%s:", space, "Mono");
mono_ok = 1;
}
if (snd_mixer_selem_has_common_volume(elem)) {
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &pvol);
printf(" %s", get_percent(pvol, pmin, pmax));
if (!snd_mixer_selem_get_playback_dB(elem, SND_MIXER_SCHN_MONO, &db)) {
printf(" [");
print_dB(db);
printf("]");
}
}
if (snd_mixer_selem_has_common_switch(elem)) {
snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw);
printf(" [%s]", psw ? "on" : "off");
}
}
if (pmono && snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO)) {
int title = 0;
if (!mono_ok) {
printf("%s%s:", space, "Mono");
mono_ok = 1;
}
if (!snd_mixer_selem_has_common_volume(elem)) {
if (snd_mixer_selem_has_playback_volume(elem)) {
printf(" Playback");
title = 1;
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &pvol);
printf(" %s", get_percent(pvol, pmin, pmax));
if (!snd_mixer_selem_get_playback_dB(elem, SND_MIXER_SCHN_MONO, &db)) {
printf(" [");
print_dB(db);
printf("]");
}
}
}
if (!snd_mixer_selem_has_common_switch(elem)) {
if (snd_mixer_selem_has_playback_switch(elem)) {
if (!title)
printf(" Playback");
snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw);
printf(" [%s]", psw ? "on" : "off");
}
}
}
if (cmono && snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO)) {
int title = 0;
if (!mono_ok) {
printf("%s%s:", space, "Mono");
mono_ok = 1;
}
if (!snd_mixer_selem_has_common_volume(elem)) {
if (snd_mixer_selem_has_capture_volume(elem)) {
printf(" Capture");
title = 1;
snd_mixer_selem_get_capture_volume(elem, SND_MIXER_SCHN_MONO, &cvol);
printf(" %s", get_percent(cvol, cmin, cmax));
if (!snd_mixer_selem_get_capture_dB(elem, SND_MIXER_SCHN_MONO, &db)) {
printf(" [");
print_dB(db);
printf("]");
}
}
}
if (!snd_mixer_selem_has_common_switch(elem)) {
if (snd_mixer_selem_has_capture_switch(elem)) {
if (!title)
printf(" Capture");
snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_MONO, &csw);
printf(" [%s]", csw ? "on" : "off");
}
}
}
if (pmono || cmono)
printf("\n");
if (!pmono || !cmono) {
for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
if ((pmono || !snd_mixer_selem_has_playback_channel(elem, chn)) &&
(cmono || !snd_mixer_selem_has_capture_channel(elem, chn)))
continue;
printf("%s%s:", space, snd_mixer_selem_channel_name(chn));
if (!pmono && !cmono && snd_mixer_selem_has_common_volume(elem)) {
snd_mixer_selem_get_playback_volume(elem, chn, &pvol);
printf(" %s", get_percent(pvol, pmin, pmax));
if (!snd_mixer_selem_get_playback_dB(elem, chn, &db)) {
printf(" [");
print_dB(db);
printf("]");
}
}
if (!pmono && !cmono && snd_mixer_selem_has_common_switch(elem)) {
snd_mixer_selem_get_playback_switch(elem, chn, &psw);
printf(" [%s]", psw ? "on" : "off");
}
if (!pmono && snd_mixer_selem_has_playback_channel(elem, chn)) {
int title = 0;
if (!snd_mixer_selem_has_common_volume(elem)) {
if (snd_mixer_selem_has_playback_volume(elem)) {
printf(" Playback");
title = 1;
snd_mixer_selem_get_playback_volume(elem, chn, &pvol);
printf(" %s", get_percent(pvol, pmin, pmax));
if (!snd_mixer_selem_get_playback_dB(elem, chn, &db)) {
printf(" [");
print_dB(db);
printf("]");
}
}
}
if (!snd_mixer_selem_has_common_switch(elem)) {
if (snd_mixer_selem_has_playback_switch(elem)) {
if (!title)
printf(" Playback");
snd_mixer_selem_get_playback_switch(elem, chn, &psw);
printf(" [%s]", psw ? "on" : "off");
}
}
}
if (!cmono && snd_mixer_selem_has_capture_channel(elem, chn)) {
int title = 0;
if (!snd_mixer_selem_has_common_volume(elem)) {
if (snd_mixer_selem_has_capture_volume(elem)) {
printf(" Capture");
title = 1;
snd_mixer_selem_get_capture_volume(elem, chn, &cvol);
printf(" %s", get_percent(cvol, cmin, cmax));
if (!snd_mixer_selem_get_capture_dB(elem, chn, &db)) {
printf(" [");
print_dB(db);
printf("]");
}
}
}
if (!snd_mixer_selem_has_common_switch(elem)) {
if (snd_mixer_selem_has_capture_switch(elem)) {
if (!title)
printf(" Capture");
snd_mixer_selem_get_capture_switch(elem, chn, &csw);
printf(" [%s]", csw ? "on" : "off");
}
}
}
printf("\n");
}
}
}
return 0;
}
int ATK_Audio_PrintControl()
{
/* From amixer selems(int level)*/
int err;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
snd_mixer_elem_t *elem;
const char *card = "default";
snd_mixer_selem_id_alloca(&sid);
if ((err = snd_mixer_open(&handle, 0)) < 0) {
printf("Mixer '%s' open error: %s", card, snd_strerror(err));
return err;
}
if ((err = snd_mixer_attach(handle, card)) < 0) {
printf("Mixer attach '%s' error: %s", card, snd_strerror(err));
snd_mixer_close(handle);
return err;
}
if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
printf("Mixer register error: %s", snd_strerror(err));
snd_mixer_close(handle);
return err;
}
err = snd_mixer_load(handle);
if (err < 0) {
printf("Mixer '%s' load error: %s", card, snd_strerror(err));
snd_mixer_close(handle);
return err;
}
for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
snd_mixer_selem_get_id(elem, sid);
printf("Mixer control: Index=%i, Name='%s' \n",
snd_mixer_selem_id_get_index(sid), snd_mixer_selem_id_get_name(sid));
show_selem(handle, sid, " ", 1);
}
snd_mixer_close(handle);
return 0;
}
int ATK_Audio_SetControl(char* pcName, int sdwValue)
{
int err;
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
snd_mixer_elem_t *elem;
const char *card = "default";
snd_mixer_selem_id_alloca(&sid);
if ((err = snd_mixer_open(&handle, 0)) < 0) {
printf("Mixer '%s' open error: %s", card, snd_strerror(err));
return err;
}
if ((err = snd_mixer_attach(handle, card)) < 0) {
printf("Mixer attach '%s' error: %s", card, snd_strerror(err));
snd_mixer_close(handle);
return err;
}
if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
printf("Mixer register error: %s", snd_strerror(err));
snd_mixer_close(handle);
return err;
}
err = snd_mixer_load(handle);
if (err < 0) {
printf("Mixer '%s' load error: %s", card, snd_strerror(err));
snd_mixer_close(handle);
return err;
}
// Set index part of a mixer simple element identifier.
snd_mixer_selem_id_set_index(sid, 0);
// Set name part of a mixer simple element identifier.
snd_mixer_selem_id_set_name(sid, pcName);
// Find a mixer simple element.
elem = snd_mixer_find_selem(handle, sid);
show_selem(handle, sid, " ", 1);
//! Try to set value
if (snd_mixer_selem_has_playback_volume(elem)) {
//! Playback
if(!snd_mixer_selem_set_playback_volume_all(elem, sdwValue)) {
//! Success
printf("Mixer set %s to %d success!\n", pcName, sdwValue);
} else
printf("Mixer set %s to %d fail!\n", pcName, sdwValue);
} else if(snd_mixer_selem_has_capture_volume(elem)) {
//! Capture
if(!snd_mixer_selem_set_capture_volume_all(elem, sdwValue)) {
//! Success
printf("Mixer set %s to %d success!\n", pcName, sdwValue);
} else
printf("Mixer set %s to %d fail!\n", pcName, sdwValue);
} else if(snd_mixer_selem_has_playback_switch(elem)) {
if(!snd_mixer_selem_set_playback_switch_all(elem, sdwValue)) {
//! Success
printf("Mixer set %s to %d success!\n", pcName, sdwValue);
} else
printf("Mixer set %s to %d fail!\n", pcName, sdwValue);
} else if(snd_mixer_selem_has_capture_switch(elem)) {
if(!snd_mixer_selem_set_capture_switch_all(elem, sdwValue)) {
//! Success
printf("Mixer set %s to %d success!\n", pcName, sdwValue);
} else
printf("Mixer set %s to %d fail!\n", pcName, sdwValue);
}
show_selem(handle, sid, " ", 1);
snd_mixer_close(handle);
return -1;
}