xref: /haiku/src/bin/desklink/MixerControl.cpp (revision eb8e4edca5f59b409c8a0f22cde9e7efd99348af)
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 			}
162 		} else {
163 			if (!retrying) {
164 				retrying = true;
165 				goto retry;
166 			}
167 			errorString = volumeWhich ? "No Audio output" : "No Mixer";
168 		}
169 	} else {
170 		if (!retrying) {
171 			retrying = true;
172 			goto retry;
173 		}
174 		errorString = "No Media Roster";
175 	}
176 
177 	if (status != B_OK)
178 		fGainMediaNode = media_node::null;
179 
180 	if (errorString) {
181 		fprintf(stderr, "MixerControl: %s.\n", errorString);
182 		if (_error)
183 			*_error = errorString;
184 	}
185 	if (fMixerParameter == NULL && _value != NULL)
186 		*_value = 0;
187 
188 	return errorString == NULL;
189 }
190 
191 
192 bool
193 MixerControl::Connected()
194 {
195 	return fGainMediaNode != media_node::null;
196 }
197 
198 
199 int32
200 MixerControl::VolumeWhich() const
201 {
202 	return fVolumeWhich;
203 }
204 
205 
206 void
207 MixerControl::SetMute(bool muted)
208 {
209 	if (fMuteParameter == NULL)
210 		return;
211 
212 	int32 mute = muted ? 1 : 0;
213 	fMuteParameter->SetValue(&mute, sizeof(int32), system_time());
214 }
215 
216 
217 bool
218 MixerControl::Mute()
219 {
220 	if (fMuteParameter == NULL)
221 		return false;
222 
223 	int32 mute = 0;
224 	bigtime_t lastChange = 0;
225 	size_t size = sizeof(int32);
226 	fMuteParameter->GetValue(&mute, &size, &lastChange);
227 	return mute != 0;
228 }
229 
230 
231 float
232 MixerControl::Volume() const
233 {
234 	if (fMixerParameter == NULL)
235 		return 0.0f;
236 
237 	float volume = 0;
238 	bigtime_t lastChange;
239 	size_t size = sizeof(float);
240 	fMixerParameter->GetValue(&volume, &size, &lastChange);
241 
242 	return volume;
243 }
244 
245 
246 void
247 MixerControl::SetVolume(float volume)
248 {
249 	if (fMixerParameter == NULL)
250 		return;
251 
252 	if (volume < fMin)
253 		volume = fMin;
254 	else if (volume > fMax)
255 		volume = fMax;
256 
257 	if (volume != Volume())
258 		fMixerParameter->SetValue(&volume, sizeof(float), system_time());
259 }
260 
261 
262 void
263 MixerControl::ChangeVolumeBy(float value)
264 {
265 	if (fMixerParameter == NULL || value == 0.0f)
266 		return;
267 
268 	float volume = Volume();
269 	SetVolume(volume + value);
270 }
271 
272 
273 void
274 MixerControl::_Disconnect()
275 {
276 	delete fParameterWeb;
277 	fParameterWeb = NULL;
278 	fMixerParameter = NULL;
279 
280 	BMediaRoster* roster = BMediaRoster::CurrentRoster();
281 	if (roster != NULL && fGainMediaNode != media_node::null)
282 		roster->ReleaseNode(fGainMediaNode);
283 
284 	fGainMediaNode = media_node::null;
285 }
286