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