3 // Copyright (C) 2004, Petr Hlavka
5 // SPDX-License-Identifier: GPL-2.0+
10 #include <alsa/asoundlib.h>
15 static bool mixerChangeIndicator
= false;
16 static bool mixerReinitIndicator
= false;
17 static int mixerCallback(snd_mixer_t
*ctl
, unsigned int mask
,
18 snd_mixer_elem_t
*elem
);
19 static int itemCallback(snd_mixer_elem_t
*elem
, unsigned int mask
);
22 AMixer::AMixer(const char *card
) {
26 cardName
= new char[std::strlen(card
)];
27 std::strcpy(cardName
, card
);
28 for (int i
= 0; i
< MIXER_ITEMS
; i
++)
31 if ((err
= snd_mixer_open(&mixerHandle
, 0)) < 0) {
32 error("snd_mixer_open error", err
);
37 if ((err
= snd_mixer_attach(mixerHandle
, card
)) < 0) {
38 error("snd_mixer_attach error", err
);
39 snd_mixer_close(mixerHandle
);
44 if ((err
= snd_mixer_selem_register(mixerHandle
, NULL
, NULL
)) < 0) {
45 error("snd_mixer_selem_register error", err
);
46 snd_mixer_close(mixerHandle
);
51 if ((err
= snd_mixer_load(mixerHandle
)) < 0) {
52 error("snd_mixer_load error", err
);
53 snd_mixer_close(mixerHandle
);
59 snd_mixer_set_callback(mixerHandle
, (snd_mixer_callback_t
) &mixerCallback
);
66 snd_mixer_free(mixerHandle
);
67 snd_mixer_detach(mixerHandle
, cardName
);
69 snd_mixer_close(mixerHandle
);
74 bool AMixer::opened() {
75 return (mixerHandle
!= NULL
);
79 void AMixer::error(const char *errorString
, int errorCode
) {
80 std::cerr
<< cardName
<< ": " << errorString
<< ": " << snd_strerror(errorCode
) << std::endl
;
84 void AMixer::handleEvents() {
85 snd_mixer_handle_events(mixerHandle
);
89 AItem
*AMixer::attachItem(unsigned int itemNumber
, const char *itemName
) {
90 if (itemNumber
>= MIXER_ITEMS
|| !itemName
)
93 // item was already created, so deregister callback and free it first
94 if (mixerItems
[itemNumber
]) {
95 snd_mixer_elem_set_callback(mixerItems
[itemNumber
]->aElem
, NULL
);
96 delete mixerItems
[itemNumber
];
99 // try to find item by name, register callback, return success
100 snd_mixer_elem_t
*elem
;
101 for (elem
= snd_mixer_first_elem(mixerHandle
); elem
; elem
= snd_mixer_elem_next(elem
)) {
102 if (snd_mixer_selem_is_active(elem
) &&
103 snd_mixer_elem_get_type(elem
) == SND_MIXER_ELEM_SIMPLE
&&
104 std::strcmp(snd_mixer_selem_get_name(elem
), itemName
) == 0) {
105 snd_mixer_elem_set_callback(elem
, (snd_mixer_elem_callback_t
) &itemCallback
);
106 return (mixerItems
[itemNumber
] = new AItem(this, elem
));
114 bool AMixer::itemOK(unsigned int itemNumber
) {
115 return (itemNumber
< MIXER_ITEMS
&& mixerItems
[itemNumber
]);
119 int AMixer::itemGetVolume(unsigned int itemNumber
) {
120 if (itemNumber
>= MIXER_ITEMS
|| !mixerItems
[itemNumber
])
123 return ((int) mixerItems
[itemNumber
]->getVolumePerc());
127 void AMixer::itemSetVolume(unsigned int itemNumber
, unsigned int volume
) {
128 if (itemNumber
< MIXER_ITEMS
&& mixerItems
[itemNumber
])
129 mixerItems
[itemNumber
]->setVolumePerc(volume
);
133 int AMixer::itemIsMuted(unsigned int itemNumber
) {
134 if (itemNumber
>= MIXER_ITEMS
|| !mixerItems
[itemNumber
])
137 return ((bool) mixerItems
[itemNumber
]->isMuted());
141 void AMixer::itemToggleMute(unsigned int itemNumber
) {
142 if (itemNumber
< MIXER_ITEMS
&& mixerItems
[itemNumber
]) {
143 if (itemIsMuted(itemNumber
))
144 mixerItems
[itemNumber
]->unmute();
146 mixerItems
[itemNumber
]->mute();
151 // return true if mixer elm sent callback and this callback wasn't picked up yet
152 bool AMixer::mixerElemsChanged() {
153 if (mixerChangeIndicator
) {
154 mixerChangeIndicator
= false;
163 // return true if mixer sent callback and this callback wasn't picked up yet
164 bool AMixer::mixerChanged() {
165 if (mixerReinitIndicator
) {
166 mixerReinitIndicator
= false;
175 // this function should be called after mixer callback, reInit all items
176 void AMixer::reInit() {
177 for (int i
= 0; i
< MIXER_ITEMS
; i
++)
178 this->attachItem(i
, mixerItems
[i
]->name
);
182 int mixerCallback(snd_mixer_t
*ctl
, unsigned int mask
,
183 snd_mixer_elem_t
*elem
) {
184 mixerReinitIndicator
= true;
190 int itemCallback(snd_mixer_elem_t
*elem
, unsigned int mask
) {
191 mixerChangeIndicator
= true;
197 char* AMixer::convertIDToCard(const char* cardId
) {
198 static char card
[32] = "";
199 int i
= snd_card_get_index(cardId
);
201 if (i
>= 0 && i
< 32)
202 std::snprintf(card
, 32, "hw:%i", i
);