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