Add AlsaMixer.app to repository
[dockapps.git] / AlsaMixer.app / AMixer / AMixer.cc
blobdbf900224143133810cd97ef26db36c0d190a84b
1 // AMixer.cc, Petr Hlavka, 2004
3 #include "AMixer.h"
4 #include "AItem.h"
6 #include <alsa/asoundlib.h>
7 #include <iostream>
8 #include <cstdio>
9 #include <cstring>
11 static bool mixerChangeIndicator = false;
12 static bool mixerReinitIndicator = false;
13 static int mixerCallback(snd_mixer_t *ctl, unsigned int mask,
14 snd_mixer_elem_t *elem);
15 static int itemCallback(snd_mixer_elem_t *elem, unsigned int mask);
18 AMixer::AMixer(const char *card) {
19 int err;
21 if (card) {
22 cardName = new char[std::strlen(card)];
23 std::strcpy(cardName, card);
24 for (int i = 0; i < MIXER_ITEMS; i++)
25 mixerItems[i] = NULL;
27 if ((err = snd_mixer_open(&mixerHandle, 0)) < 0) {
28 error("snd_mixer_open error", err);
29 mixerHandle = NULL;
31 return;
33 if ((err = snd_mixer_attach(mixerHandle, card)) < 0) {
34 error("snd_mixer_attach error", err);
35 snd_mixer_close(mixerHandle);
36 mixerHandle = NULL;
38 return;
40 if ((err = snd_mixer_selem_register(mixerHandle, NULL, NULL)) < 0) {
41 error("snd_mixer_selem_register error", err);
42 snd_mixer_close(mixerHandle);
43 mixerHandle = NULL;
45 return;
47 if ((err = snd_mixer_load(mixerHandle)) < 0) {
48 error("snd_mixer_load error", err);
49 snd_mixer_close(mixerHandle);
50 mixerHandle = NULL;
52 return;
55 snd_mixer_set_callback(mixerHandle, (snd_mixer_callback_t) &mixerCallback);
60 AMixer::~AMixer() {
61 if (mixerHandle) {
62 snd_mixer_free(mixerHandle);
63 snd_mixer_detach(mixerHandle, cardName);
64 delete[] cardName;
65 snd_mixer_close(mixerHandle);
70 bool AMixer::opened() {
71 return (mixerHandle != NULL);
75 void AMixer::error(const char *errorString, int errorCode) {
76 std::cerr << cardName << ": " << errorString << ": " << snd_strerror(errorCode) << std::endl;
80 void AMixer::handleEvents() {
81 snd_mixer_handle_events(mixerHandle);
85 AItem *AMixer::attachItem(unsigned int itemNumber, const char *itemName) {
86 if (itemNumber >= MIXER_ITEMS || !itemName)
87 return (NULL);
89 // item was already created, so deregister callback and free it first
90 if (mixerItems[itemNumber]) {
91 snd_mixer_elem_set_callback(mixerItems[itemNumber]->aElem, NULL);
92 delete mixerItems[itemNumber];
95 // try to find item by name, register callback, return success
96 snd_mixer_elem_t *elem;
97 for (elem = snd_mixer_first_elem(mixerHandle); elem; elem = snd_mixer_elem_next(elem)) {
98 if (snd_mixer_selem_is_active(elem) &&
99 snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE &&
100 std::strcmp(snd_mixer_selem_get_name(elem), itemName) == 0) {
101 snd_mixer_elem_set_callback(elem, (snd_mixer_elem_callback_t) &itemCallback);
102 return (mixerItems[itemNumber] = new AItem(this, elem));
106 return (NULL);
110 bool AMixer::itemOK(unsigned int itemNumber) {
111 return (itemNumber < MIXER_ITEMS && mixerItems[itemNumber]);
115 int AMixer::itemGetVolume(unsigned int itemNumber) {
116 if (itemNumber >= MIXER_ITEMS || !mixerItems[itemNumber])
117 return (-1);
119 return ((int) mixerItems[itemNumber]->getVolumePerc());
123 void AMixer::itemSetVolume(unsigned int itemNumber, unsigned int volume) {
124 if (itemNumber < MIXER_ITEMS && mixerItems[itemNumber])
125 mixerItems[itemNumber]->setVolumePerc(volume);
129 int AMixer::itemIsMuted(unsigned int itemNumber) {
130 if (itemNumber >= MIXER_ITEMS || !mixerItems[itemNumber])
131 return (-1);
133 return ((bool) mixerItems[itemNumber]->isMuted());
137 void AMixer::itemToggleMute(unsigned int itemNumber) {
138 if (itemNumber < MIXER_ITEMS && mixerItems[itemNumber]) {
139 if (itemIsMuted(itemNumber))
140 mixerItems[itemNumber]->unmute();
141 else
142 mixerItems[itemNumber]->mute();
147 // return true if mixer elm sent callback and this callback wasn't picked up yet
148 bool AMixer::mixerElemsChanged() {
149 if (mixerChangeIndicator) {
150 mixerChangeIndicator = false;
152 return (true);
154 else
155 return (false);
159 // return true if mixer sent callback and this callback wasn't picked up yet
160 bool AMixer::mixerChanged() {
161 if (mixerReinitIndicator) {
162 mixerReinitIndicator = false;
164 return (true);
166 else
167 return (false);
171 // this function should be called after mixer callback, reInit all items
172 void AMixer::reInit() {
173 for (int i = 0; i < MIXER_ITEMS; i++)
174 this->attachItem(i, mixerItems[i]->name);
178 int mixerCallback(snd_mixer_t *ctl, unsigned int mask,
179 snd_mixer_elem_t *elem) {
180 mixerReinitIndicator = true;
182 return (0);
186 int itemCallback(snd_mixer_elem_t *elem, unsigned int mask) {
187 mixerChangeIndicator = true;
189 return (0);
193 char* AMixer::convertIDToCard(const char* cardId) {
194 static char card[32] = "";
195 int i = snd_card_get_index(cardId);
197 if (i >= 0 && i < 32)
198 std::snprintf(card, 32, "hw:%i", i);
199 else
200 return (NULL);
202 return (card);