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