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