xref: /haiku/src/bin/desklink/MixerControl.cpp (revision 3d2abd1bc8a8b1151378eceb469a10d3826e433e)
1 /*
2  * Copyright 2003-2009, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Jérôme Duval
7  *		François Revol
8  *		Axel Dörfler, axeld@pinc-software.de.
9  */
10 
11 
12 #include "MixerControl.h"
13 
14 #include <string.h>
15 
16 #include <Debug.h>
17 #include <ParameterWeb.h>
18 
19 
20 MixerControl::MixerControl(int32 volumeWhich, float* _value,
21 		const char** _error)
22 	:
23 	fVolumeWhich(volumeWhich),
24 	fGainMediaNode(media_node::null),
25 	fParameterWeb(NULL),
26 	fMixerParameter(NULL),
27 	fMin(0.0f),
28 	fMax(0.0f),
29 	fStep(0.0f)
30 {
31 	bool retrying = false;
32 
33 	status_t err = B_OK;
34 		/* BMediaRoster::Roster() doesn't set it if all is ok */
35 	const char* errorString = NULL;
36 	BMediaRoster* roster = BMediaRoster::Roster(&err);
37 
38 retry:
39 	// Here we release the BMediaRoster once if we can't access the system
40 	// mixer, to make sure it really isn't there, and it's not BMediaRoster
41 	// that is messed up.
42 	if (retrying) {
43 		errorString = NULL;
44 		PRINT(("retrying to get a Media Roster\n"));
45 		/* BMediaRoster looks doomed */
46 		roster = BMediaRoster::CurrentRoster();
47 		if (roster) {
48 			roster->Lock();
49 			roster->Quit();
50 		}
51 		snooze(10000);
52 		roster = BMediaRoster::Roster(&err);
53 	}
54 
55 	if (roster && err == B_OK) {
56 		switch (volumeWhich) {
57 			case VOLUME_USE_MIXER:
58 				err = roster->GetAudioMixer(&fGainMediaNode);
59 				break;
60 			case VOLUME_USE_PHYS_OUTPUT:
61 				err = roster->GetAudioOutput(&fGainMediaNode);
62 				break;
63 		}
64 		if (err == B_OK) {
65 			err = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb);
66 			if (err == B_OK) {
67 				// Finding the Mixer slider in the audio output ParameterWeb
68 				int32 numParams = fParameterWeb->CountParameters();
69 				BParameter* p = NULL;
70 				bool foundMixerLabel = false;
71 				for (int i = 0; i < numParams; i++) {
72 					p = fParameterWeb->ParameterAt(i);
73 					PRINT(("BParameter[%i]: %s\n", i, p->Name()));
74 					if (volumeWhich == VOLUME_USE_MIXER) {
75 						if (!strcmp(p->Kind(), B_MASTER_GAIN))
76 							break;
77 					} else if (volumeWhich == VOLUME_USE_PHYS_OUTPUT) {
78 						/* not all cards use the same name, and
79 						 * they don't seem to use Kind() == B_MASTER_GAIN
80 						 */
81 						if (!strcmp(p->Kind(), B_MASTER_GAIN))
82 							break;
83 						PRINT(("not MASTER_GAIN \n"));
84 
85 						/* some audio card
86 						 */
87 						if (!strcmp(p->Name(), "Master"))
88 							break;
89 						PRINT(("not 'Master' \n"));
90 
91 						/* some Ensonic card have all controls names 'Volume', so
92 						 * need to fint the one that has the 'Mixer' text label
93 						 */
94 						if (foundMixerLabel && !strcmp(p->Name(), "Volume"))
95 							break;
96 						if (!strcmp(p->Name(), "Mixer"))
97 							foundMixerLabel = true;
98 						PRINT(("not 'Mixer' \n"));
99 					}
100 #if 0
101 					//if (!strcmp(p->Name(), "Master")) {
102 					if (!strcmp(p->Kind(), B_MASTER_GAIN)) {
103 						for (; i < numParams; i++) {
104 							p = fParamWeb->ParameterAt(i);
105 							if (strcmp(p->Kind(), B_MASTER_GAIN)) p=NULL;
106 							else break;
107 						}
108 						break;
109 					} else p = NULL;
110 #endif
111 					p = NULL;
112 				}
113 				if (p == NULL) {
114 					errorString = volumeWhich ? "Could not find the soundcard"
115 						: "Could not find the mixer";
116 				} else if (p->Type() != BParameter::B_CONTINUOUS_PARAMETER) {
117 					errorString = volumeWhich ? "Soundcard control unknown"
118 						: "Mixer control unknown";
119 				} else {
120 					fMixerParameter = dynamic_cast<BContinuousParameter*>(p);
121 					fMin = fMixerParameter->MinValue();
122 					fMax = fMixerParameter->MaxValue();
123 					fStep = fMixerParameter->ValueStep();
124 
125 					if (_value != NULL) {
126 						float volume;
127 						bigtime_t lastChange;
128 						size_t size = sizeof(float);
129 						fMixerParameter->GetValue(&volume, &size, &lastChange);
130 
131 						*_value = volume;
132 					}
133 				}
134 			} else {
135 				errorString = "No parameter web";
136 			}
137 		} else {
138 			if (!retrying) {
139 				retrying = true;
140 				goto retry;
141 			}
142 			errorString = volumeWhich ? "No Audio output" : "No Mixer";
143 		}
144 	} else {
145 		if (!retrying) {
146 			retrying = true;
147 			goto retry;
148 		}
149 		errorString = "No Media Roster";
150 	}
151 
152 	if (err != B_OK)
153 		fGainMediaNode = media_node::null;
154 
155 	if (errorString) {
156 		fprintf(stderr, "MixerControl: %s.\n", errorString);
157 		if (_error)
158 			*_error = errorString;
159 	}
160 	if (fMixerParameter == NULL && _value != NULL)
161 		*_value = 0;
162 }
163 
164 
165 MixerControl::~MixerControl()
166 {
167 	delete fParameterWeb;
168 
169 	BMediaRoster* roster = BMediaRoster::CurrentRoster();
170 	if (roster != NULL && fGainMediaNode != media_node::null)
171 		roster->ReleaseNode(fGainMediaNode);
172 }
173 
174 
175 int32
176 MixerControl::VolumeWhich() const
177 {
178 	return fVolumeWhich;
179 }
180 
181 
182 float
183 MixerControl::Volume() const
184 {
185 	if (fMixerParameter == NULL)
186 		return 0.0f;
187 
188 	float volume = 0;
189 	bigtime_t lastChange;
190 	size_t size = sizeof(float);
191 	fMixerParameter->GetValue(&volume, &size, &lastChange);
192 
193 	return volume;
194 }
195 
196 
197 void
198 MixerControl::SetVolume(float volume)
199 {
200 	if (fMixerParameter == NULL)
201 		return;
202 
203 	if (volume < fMin)
204 		volume = fMin;
205 	else if (volume > fMax)
206 		volume = fMax;
207 
208 	if (volume != Volume())
209 		fMixerParameter->SetValue(&volume, sizeof(float), system_time());
210 }
211 
212 
213 void
214 MixerControl::ChangeVolumeBy(float value)
215 {
216 	if (fMixerParameter == NULL || value == 0.0f)
217 		return;
218 
219 	float volume = Volume();
220 	SetVolume(volume + value);
221 }
222 
223