wmshutdown: Destroy dialog window before shutting down. This is especially useful...
[dockapps.git] / AlsaMixer.app / AMixer / AMixer.cc
blobea9f70d14cc94705b4b0a9c62c1b3bb2b3e65dd8
1 // AMixer.cc
2 //
3 // Copyright (C) 2004, Petr Hlavka
4 //
5 // SPDX-License-Identifier: GPL-2.0+
7 #include "AMixer.h"
8 #include "AItem.h"
10 #include <alsa/asoundlib.h>
11 #include <iostream>
12 #include <cstdio>
13 #include <cstring>
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) {
23 int err;
25 if (card) {
26 cardName = new char[std::strlen(card)];
27 std::strcpy(cardName, card);
28 for (int i = 0; i < MIXER_ITEMS; i++)
29 mixerItems[i] = NULL;
31 if ((err = snd_mixer_open(&mixerHandle, 0)) < 0) {
32 error("snd_mixer_open error", err);
33 mixerHandle = NULL;
35 return;
37 if ((err = snd_mixer_attach(mixerHandle, card)) < 0) {
38 error("snd_mixer_attach error", err);
39 snd_mixer_close(mixerHandle);
40 mixerHandle = NULL;
42 return;
44 if ((err = snd_mixer_selem_register(mixerHandle, NULL, NULL)) < 0) {
45 error("snd_mixer_selem_register error", err);
46 snd_mixer_close(mixerHandle);
47 mixerHandle = NULL;
49 return;
51 if ((err = snd_mixer_load(mixerHandle)) < 0) {
52 error("snd_mixer_load error", err);
53 snd_mixer_close(mixerHandle);
54 mixerHandle = NULL;
56 return;
59 snd_mixer_set_callback(mixerHandle, (snd_mixer_callback_t) &mixerCallback);
64 AMixer::~AMixer() {
65 if (mixerHandle) {
66 snd_mixer_free(mixerHandle);
67 snd_mixer_detach(mixerHandle, cardName);
68 delete[] 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)
91 return (NULL);
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));
110 return (NULL);
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])
121 return (-1);
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])
135 return (-1);
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();
145 else
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;
156 return (true);
158 else
159 return (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;
168 return (true);
170 else
171 return (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;
186 return (0);
190 int itemCallback(snd_mixer_elem_t *elem, unsigned int mask) {
191 mixerChangeIndicator = true;
193 return (0);
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);
203 else
204 return (NULL);
206 return (card);