xref: /haiku/src/bin/desklink/MixerControl.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
1 /*
2  * Copyright 2003-2013, 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  *		Puck Meerburg, puck@puckipedia.nl
10  */
11 
12 
13 #include "MixerControl.h"
14 
15 #include <string.h>
16 
17 #include <Debug.h>
18 #include <ParameterWeb.h>
19 
20 
21 MixerControl::MixerControl(int32 volumeWhich)
22 	:
23 	fVolumeWhich(volumeWhich),
24 	fGainMediaNode(media_node::null),
25 	fParameterWeb(NULL),
26 	fMixerParameter(NULL),
27 	fMuteParameter(NULL),
28 	fMin(0.0f),
29 	fMax(0.0f),
30 	fStep(0.0f)
31 {
32 }
33 
34 
35 MixerControl::~MixerControl()
36 {
37 	_Disconnect();
38 }
39 
40 
41 bool
42 MixerControl::Connect(int32 volumeWhich, float* _value, const char** _error)
43 {
44 	fVolumeWhich = volumeWhich;
45 
46 	_Disconnect();
47 
48 	bool retrying = false;
49 
50 	status_t status = B_OK;
51 		// BMediaRoster::Roster() doesn't set it if all is ok
52 	const char* errorString = NULL;
53 	BMediaRoster* roster = BMediaRoster::Roster(&status);
54 
55 retry:
56 	// Here we release the BMediaRoster once if we can't access the system
57 	// mixer, to make sure it really isn't there, and it's not BMediaRoster
58 	// that is messed up.
59 	if (retrying) {
60 		errorString = NULL;
61 		PRINT(("retrying to get a Media Roster\n"));
62 		/* BMediaRoster looks doomed */
63 		roster = BMediaRoster::CurrentRoster();
64 		if (roster) {
65 			roster->Lock();
66 			roster->Quit();
67 		}
68 		snooze(10000);
69 		roster = BMediaRoster::Roster(&status);
70 	}
71 
72 	if (roster != NULL && status == B_OK) {
73 		switch (volumeWhich) {
74 			case VOLUME_USE_MIXER:
75 				status = roster->GetAudioMixer(&fGainMediaNode);
76 				break;
77 			case VOLUME_USE_PHYS_OUTPUT:
78 				status = roster->GetAudioOutput(&fGainMediaNode);
79 				break;
80 		}
81 		if (status == B_OK) {
82 			status = roster->GetParameterWebFor(fGainMediaNode, &fParameterWeb);
83 			if (status == B_OK) {
84 				// Finding the Mixer slider in the audio output ParameterWeb
85 				int32 numParams = fParameterWeb->CountParameters();
86 				BParameter* p = NULL;
87 				bool foundMixerLabel = false;
88 				for (int i = 0; i < numParams; i++) {
89 					p = fParameterWeb->ParameterAt(i);
90 
91 					// assume the mute preceeding master gain control
92 					if (!strcmp(p->Kind(), B_MUTE))
93 						fMuteParameter = p;
94 
95 					PRINT(("BParameter[%i]: %s\n", i, p->Name()));
96 					if (volumeWhich == VOLUME_USE_MIXER) {
97 						if (!strcmp(p->Kind(), B_MASTER_GAIN))
98 							break;
99 					} else if (volumeWhich == VOLUME_USE_PHYS_OUTPUT) {
100 						/* not all cards use the same name, and
101 						 * they don't seem to use Kind() == B_MASTER_GAIN
102 						 */
103 						if (!strcmp(p->Kind(), B_MASTER_GAIN))
104 							break;
105 						PRINT(("not MASTER_GAIN \n"));
106 
107 						/* some audio card
108 						 */
109 						if (!strcmp(p->Name(), "Master"))
110 							break;
111 						PRINT(("not 'Master' \n"));
112 
113 						/* some Ensonic card have all controls names 'Volume', so
114 						 * need to fint the one that has the 'Mixer' text label
115 						 */
116 						if (foundMixerLabel && !strcmp(p->Name(), "Volume"))
117 							break;
118 						if (!strcmp(p->Name(), "Mixer"))
119 							foundMixerLabel = true;
120 						PRINT(("not 'Mixer' \n"));
121 					}
122 #if 0
123 					//if (!strcmp(p->Name(), "Master")) {
124 					if (!strcmp(p->Kind(), B_MASTER_GAIN)) {
125 						for (; i < numParams; i++) {
126 							p = fParamWeb->ParameterAt(i);
127 							if (strcmp(p->Kind(), B_MASTER_GAIN))
128 								p = NULL;
129 							else
130 								break;
131 						}
132 						break;
133 					} else
134 						p = NULL;
135 #endif
136 					p = NULL;
137 				}
138 				if (p == NULL) {
139 					errorString = volumeWhich ? "Could not find the soundcard"
140 						: "Could not find the mixer";
141 				} else if (p->Type() != BParameter::B_CONTINUOUS_PARAMETER) {
142 					errorString = volumeWhich ? "Soundcard control unknown"
143 						: "Mixer control unknown";
144 				} else {
145 					fMixerParameter = static_cast<BContinuousParameter*>(p);
146 					fMin = fMixerParameter->MinValue();
147 					fMax = fMixerParameter->MaxValue();
148 					fStep = fMixerParameter->ValueStep();
149 
150 					if (_value != NULL) {
151 						float volume;
152 						bigtime_t lastChange;
153 						size_t size = sizeof(float);
154 						fMixerParameter->GetValue(&volume, &size, &lastChange);
155 
156 						*_value = volume;
157 					}
158 				}
159 			} else {
160 				errorString = "No parameter web";
161 				fParameterWeb = NULL;
162 			}
163 		} else {
164 			if (!retrying) {
165 				retrying = true;
166 				goto retry;
167 			}
168 			errorString = volumeWhich ? "No Audio output" : "No Mixer";
169 		}
170 	} else {
171 		if (!retrying) {
172 			retrying = true;
173 			goto retry;
174 		}
175 		errorString = "No Media Roster";
176 	}
177 
178 	if (status != B_OK)
179 		fGainMediaNode = media_node::null;
180 
181 	if (errorString) {
182 		fprintf(stderr, "MixerControl: %s.\n", errorString);
183 		if (_error)
184 			*_error = errorString;
185 	}
186 	if (fMixerParameter == NULL && _value != NULL)
187 		*_value = 0;
188 
189 	return errorString == NULL;
190 }
191 
192 
193 bool
194 MixerControl::Connected()
195 {
196 	return fGainMediaNode != media_node::null;
197 }
198 
199 
200 int32
201 MixerControl::VolumeWhich() const
202 {
203 	return fVolumeWhich;
204 }
205 
206 
207 void
208 MixerControl::SetMute(bool muted)
209 {
210 	if (fMuteParameter == NULL)
211 		return;
212 
213 	int32 mute = muted ? 1 : 0;
214 	fMuteParameter->SetValue(&mute, sizeof(int32), system_time());
215 }
216 
217 
218 bool
219 MixerControl::Mute()
220 {
221 	if (fMuteParameter == NULL)
222 		return false;
223 
224 	int32 mute = 0;
225 	bigtime_t lastChange = 0;
226 	size_t size = sizeof(int32);
227 	fMuteParameter->GetValue(&mute, &size, &lastChange);
228 	return mute != 0;
229 }
230 
231 
232 float
233 MixerControl::Volume() const
234 {
235 	if (fMixerParameter == NULL)
236 		return 0.0f;
237 
238 	float volume = 0;
239 	bigtime_t lastChange;
240 	size_t size = sizeof(float);
241 	fMixerParameter->GetValue(&volume, &size, &lastChange);
242 
243 	return volume;
244 }
245 
246 
247 void
248 MixerControl::SetVolume(float volume)
249 {
250 	if (fMixerParameter == NULL)
251 		return;
252 
253 	if (volume < fMin)
254 		volume = fMin;
255 	else if (volume > fMax)
256 		volume = fMax;
257 
258 	if (volume != Volume())
259 		fMixerParameter->SetValue(&volume, sizeof(float), system_time());
260 }
261 
262 
263 void
264 MixerControl::ChangeVolumeBy(float value)
265 {
266 	if (fMixerParameter == NULL || value == 0.0f)
267 		return;
268 
269 	float volume = Volume();
270 	SetVolume(volume + value);
271 }
272 
273 
274 void
275 MixerControl::_Disconnect()
276 {
277 	delete fParameterWeb;
278 	fParameterWeb = NULL;
279 	fMixerParameter = NULL;
280 
281 	BMediaRoster* roster = BMediaRoster::CurrentRoster();
282 	if (roster != NULL && fGainMediaNode != media_node::null)
283 		roster->ReleaseNode(fGainMediaNode);
284 
285 	fGainMediaNode = media_node::null;
286 }
287