xref: /haiku/src/add-ons/media/media-add-ons/mixer/MixerOutput.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * Copyright 2003-2009 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marcus Overhagen
7  */
8 
9 
10 #include "MixerOutput.h"
11 
12 #include <MediaNode.h>
13 
14 #include "MixerCore.h"
15 #include "MixerDebug.h"
16 #include "MixerUtils.h"
17 
18 
19 MixerOutput::MixerOutput(MixerCore *core, const media_output &output)
20 	:
21 	fCore(core),
22 	fOutput(output),
23 	fOutputChannelCount(0),
24 	fOutputChannelInfo(0),
25 	fOutputByteSwap(0),
26 	fMuted(false)
27 {
28 	fix_multiaudio_format(&fOutput.format.u.raw_audio);
29 	PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput);
30 	PRINT_CHANNEL_MASK(fOutput.format);
31 
32 	UpdateOutputChannels();
33 	UpdateByteOrderSwap();
34 }
35 
36 
37 MixerOutput::~MixerOutput()
38 {
39 	delete fOutputChannelInfo;
40 	delete fOutputByteSwap;
41 }
42 
43 
44 media_output &
45 MixerOutput::MediaOutput()
46 {
47 	return fOutput;
48 }
49 
50 
51 void
52 MixerOutput::ChangeFormat(const media_multi_audio_format &format)
53 {
54 	fOutput.format.u.raw_audio = format;
55 	fix_multiaudio_format(&fOutput.format.u.raw_audio);
56 
57 	PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput);
58 	PRINT_CHANNEL_MASK(fOutput.format);
59 
60 	UpdateOutputChannels();
61 	UpdateByteOrderSwap();
62 }
63 
64 
65 void
66 MixerOutput::UpdateByteOrderSwap()
67 {
68 	delete fOutputByteSwap;
69 	fOutputByteSwap = 0;
70 
71 	// perhaps we need byte swapping
72 	if (fOutput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) {
73 		if (	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
74 			 ||	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT
75 			 ||	fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) {
76 			fOutputByteSwap = new ByteSwap(fOutput.format.u.raw_audio.format);
77 		}
78 	}
79 }
80 
81 
82 void
83 MixerOutput::UpdateOutputChannels()
84 {
85 	output_chan_info *oldInfo = fOutputChannelInfo;
86 	int oldCount = fOutputChannelCount;
87 
88 	fOutputChannelCount = fOutput.format.u.raw_audio.channel_count;
89 	fOutputChannelInfo = new output_chan_info[fOutputChannelCount];
90 	for (int i = 0; i < fOutputChannelCount; i++) {
91 		fOutputChannelInfo[i].channel_type = GetChannelType(i, fOutput.format.u.raw_audio.channel_mask);
92 		fOutputChannelInfo[i].channel_gain = 1.0;
93 		fOutputChannelInfo[i].source_count = 1;
94 		fOutputChannelInfo[i].source_gain[0] = 1.0;
95 		fOutputChannelInfo[i].source_type[0] = fOutputChannelInfo[i].channel_type;
96 		// all the cached values are 0.0 for a new channel
97 		for (int j = 0; j < MAX_CHANNEL_TYPES; j++)
98 			fOutputChannelInfo[i].source_gain_cache[j] = 0.0;
99 	}
100 
101 	AssignDefaultSources();
102 
103 	// apply old gains and sources, overriding the 1.0 gain defaults for the old channels
104 	if (oldInfo != 0 && oldCount != 0) {
105 		for (int i = 0; i < fOutputChannelCount; i++) {
106 			for (int j = 0; j < oldCount; j++) {
107 				if (fOutputChannelInfo[i].channel_type == oldInfo[j].channel_type) {
108 					fOutputChannelInfo[i].channel_gain = oldInfo[j].channel_gain;
109 					fOutputChannelInfo[i].source_count = oldInfo[j].source_count;
110 					for (int k = 0; k < fOutputChannelInfo[i].source_count; k++) {
111 						fOutputChannelInfo[i].source_gain[k] = oldInfo[j].source_gain[k];
112 						fOutputChannelInfo[i].source_type[k] = oldInfo[j].source_type[k];
113 					}
114 					// also copy the old gain cache
115 					for (int k = 0; k < MAX_CHANNEL_TYPES; k++)
116 						fOutputChannelInfo[i].source_gain_cache[k] = oldInfo[j].source_gain_cache[k];
117 					break;
118 				}
119 			}
120 		}
121 		// also delete the old info array
122 		delete [] oldInfo;
123 	}
124 	for (int i = 0; i < fOutputChannelCount; i++)
125 		TRACE("UpdateOutputChannels: output channel %d, type %2d, gain %.3f\n", i, fOutputChannelInfo[i].channel_type, fOutputChannelInfo[i].channel_gain);
126 }
127 
128 
129 void
130 MixerOutput::AssignDefaultSources()
131 {
132 	uint32 mask = fOutput.format.u.raw_audio.channel_mask;
133 	int count = fOutputChannelCount;
134 
135 	// assign default sources for a few known setups,
136 	// everything else is left unchanged (it already is 1:1)
137 	if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
138 		// we have only one phycial output channel, and use it as a mix of
139 		// left, right, rear-left, rear-right, center and sub
140 		TRACE("AssignDefaultSources: 1 channel setup\n");
141 		fOutputChannelInfo[0].source_count = 9;
142 		fOutputChannelInfo[0].source_gain[0] = 1.0;
143 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
144 		fOutputChannelInfo[0].source_gain[1] = 1.0;
145 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
146 		fOutputChannelInfo[0].source_gain[2] = 0.8;
147 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
148 		fOutputChannelInfo[0].source_gain[3] = 0.8;
149 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
150 		fOutputChannelInfo[0].source_gain[4] = 0.7;
151 		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
152 		fOutputChannelInfo[0].source_gain[5] = 0.6;
153 		fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SUB);
154 		fOutputChannelInfo[0].source_gain[6] = 1.0;
155 		fOutputChannelInfo[0].source_type[6] = ChannelMaskToChannelType(B_CHANNEL_MONO);
156 		fOutputChannelInfo[0].source_gain[7] = 0.7;
157 		fOutputChannelInfo[0].source_type[7] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
158 		fOutputChannelInfo[0].source_gain[8] = 0.7;
159 		fOutputChannelInfo[0].source_type[8] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
160 	} else if (count == 2 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) {
161 		// we have have two phycial output channels
162 		TRACE("AssignDefaultSources: 2 channel setup\n");
163 		// left channel:
164 		fOutputChannelInfo[0].source_count = 6;
165 		fOutputChannelInfo[0].source_gain[0] = 1.0;
166 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
167 		fOutputChannelInfo[0].source_gain[1] = 0.8;
168 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
169 		fOutputChannelInfo[0].source_gain[2] = 0.7;
170 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
171 		fOutputChannelInfo[0].source_gain[3] = 0.6;
172 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
173 		fOutputChannelInfo[0].source_gain[4] = 1.0;
174 		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
175 		fOutputChannelInfo[0].source_gain[5] = 0.7;
176 		fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
177 		// right channel:
178 		fOutputChannelInfo[1].source_count = 6;
179 		fOutputChannelInfo[1].source_gain[0] = 1.0;
180 		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
181 		fOutputChannelInfo[1].source_gain[1] = 0.8;
182 		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
183 		fOutputChannelInfo[1].source_gain[2] = 0.7;
184 		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
185 		fOutputChannelInfo[1].source_gain[3] = 0.6;
186 		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB);
187 		fOutputChannelInfo[1].source_gain[4] = 1.0;
188 		fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO);
189 		fOutputChannelInfo[1].source_gain[5] = 0.7;
190 		fOutputChannelInfo[1].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
191 	} else if (count == 4 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT)) {
192 		TRACE("AssignDefaultSources: 4 channel setup\n");
193 		// left channel:
194 		fOutputChannelInfo[0].source_count = 5;
195 		fOutputChannelInfo[0].source_gain[0] = 1.0;
196 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
197 		fOutputChannelInfo[0].source_gain[1] = 0.7;
198 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
199 		fOutputChannelInfo[0].source_gain[2] = 0.6;
200 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
201 		fOutputChannelInfo[0].source_gain[3] = 1.0;
202 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
203 		fOutputChannelInfo[0].source_gain[4] = 0.6;
204 		fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
205 		// right channel:
206 		fOutputChannelInfo[1].source_count = 5;
207 		fOutputChannelInfo[1].source_gain[0] = 1.0;
208 		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
209 		fOutputChannelInfo[1].source_gain[1] = 0.7;
210 		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
211 		fOutputChannelInfo[1].source_gain[2] = 0.6;
212 		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB);
213 		fOutputChannelInfo[1].source_gain[3] = 1.0;
214 		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO);
215 		fOutputChannelInfo[1].source_gain[4] = 0.6;
216 		fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
217 		// rear-left channel:
218 		fOutputChannelInfo[2].source_count = 4;
219 		fOutputChannelInfo[2].source_gain[0] = 1.0;
220 		fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
221 		fOutputChannelInfo[2].source_gain[1] = 0.6;
222 		fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
223 		fOutputChannelInfo[2].source_gain[2] = 0.9;
224 		fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
225 		fOutputChannelInfo[2].source_gain[3] = 0.6;
226 		fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
227 		// rear-right channel:
228 		fOutputChannelInfo[3].source_count = 4;
229 		fOutputChannelInfo[3].source_gain[0] = 1.0;
230 		fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
231 		fOutputChannelInfo[3].source_gain[1] = 0.6;
232 		fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
233 		fOutputChannelInfo[3].source_gain[2] = 0.9;
234 		fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
235 		fOutputChannelInfo[3].source_gain[3] = 0.6;
236 		fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
237 	} else if (count == 5 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER)) {
238 		TRACE("AssignDefaultSources: 5 channel setup\n");
239 		// left channel:
240 		fOutputChannelInfo[0].source_count = 4;
241 		fOutputChannelInfo[0].source_gain[0] = 1.0;
242 		fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT);
243 		fOutputChannelInfo[0].source_gain[1] = 0.6;
244 		fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
245 		fOutputChannelInfo[0].source_gain[2] = 1.0;
246 		fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
247 		fOutputChannelInfo[0].source_gain[3] = 0.6;
248 		fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
249 		// right channel:
250 		fOutputChannelInfo[1].source_count = 4;
251 		fOutputChannelInfo[1].source_gain[0] = 1.0;
252 		fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT);
253 		fOutputChannelInfo[1].source_gain[1] = 0.6;
254 		fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
255 		fOutputChannelInfo[1].source_gain[2] = 1.0;
256 		fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
257 		fOutputChannelInfo[1].source_gain[3] = 0.6;
258 		fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
259 		// rear-left channel:
260 		fOutputChannelInfo[2].source_count = 4;
261 		fOutputChannelInfo[2].source_gain[0] = 1.0;
262 		fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT);
263 		fOutputChannelInfo[2].source_gain[1] = 0.6;
264 		fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
265 		fOutputChannelInfo[2].source_gain[2] = 0.9;
266 		fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
267 		fOutputChannelInfo[2].source_gain[3] = 0.6;
268 		fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT);
269 		// rear-right channel:
270 		fOutputChannelInfo[3].source_count = 4;
271 		fOutputChannelInfo[3].source_gain[0] = 1.0;
272 		fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT);
273 		fOutputChannelInfo[3].source_gain[1] = 0.6;
274 		fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
275 		fOutputChannelInfo[3].source_gain[2] = 0.9;
276 		fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
277 		fOutputChannelInfo[3].source_gain[3] = 0.6;
278 		fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT);
279 		// center channel:
280 		fOutputChannelInfo[4].source_count = 3;
281 		fOutputChannelInfo[4].source_gain[0] = 1.0;
282 		fOutputChannelInfo[4].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_CENTER);
283 		fOutputChannelInfo[4].source_gain[1] = 0.5;
284 		fOutputChannelInfo[4].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB);
285 		fOutputChannelInfo[4].source_gain[2] = 0.8;
286 		fOutputChannelInfo[4].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO);
287 	} else {
288 		TRACE("AssignDefaultSources: no default setup, adding mono channel to first two channels\n");
289 		if (count >= 1) {
290 			// this is not a left channel, but we add the mono channel anyway
291 			fOutputChannelInfo[0].source_gain[fOutputChannelInfo[0].source_count] = 1.0;
292 			fOutputChannelInfo[0].source_type[fOutputChannelInfo[0].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
293 			fOutputChannelInfo[0].source_count++;
294 		}
295 		if (count >= 2) {
296 			// this is not a right channel, but we add the mono channel anyway
297 			fOutputChannelInfo[1].source_gain[fOutputChannelInfo[1].source_count] = 1.0;
298 			fOutputChannelInfo[1].source_type[fOutputChannelInfo[1].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO);
299 			fOutputChannelInfo[1].source_count++;
300 		}
301 	}
302 
303 	for (int i = 0; i < fOutputChannelCount; i++) {
304 		for (int j = 0; j < fOutputChannelInfo[i].source_count; j++) {
305 			TRACE("AssignDefaultSources: output channel %d, source index %d: source_type %2d, source_gain %.3f\n", i, j, fOutputChannelInfo[i].source_type[j], fOutputChannelInfo[i].source_gain[j]);
306 		}
307 	}
308 }
309 
310 
311 int
312 MixerOutput::GetOutputChannelType(int channel)
313 {
314 	if (channel < 0 || channel >= fOutputChannelCount)
315 		return 0;
316 	return fOutputChannelInfo[channel].channel_type;
317 }
318 
319 
320 void
321 MixerOutput::SetOutputChannelGain(int channel, float gain)
322 {
323 	TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain);
324 	if (channel < 0 || channel >= fOutputChannelCount)
325 		return;
326 	fOutputChannelInfo[channel].channel_gain = gain;
327 }
328 
329 
330 void
331 MixerOutput::AddOutputChannelSource(int channel, int source_type)
332 {
333 	if (channel < 0 || channel >= fOutputChannelCount)
334 		return;
335 	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
336 		return;
337 	if (fOutputChannelInfo[channel].source_count == MAX_SOURCE_ENTRIES)
338 		return;
339 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
340 		if (fOutputChannelInfo[channel].source_type[i] == source_type)
341 			return;
342 	}
343 	// when adding a new source, use the current gain value from cache
344 	float source_gain = fOutputChannelInfo[channel].source_gain_cache[source_type];
345 	fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count] = source_type;
346 	fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count] = source_gain;
347 	fOutputChannelInfo[channel].source_count++;
348 }
349 
350 
351 void
352 MixerOutput::RemoveOutputChannelSource(int channel, int source_type)
353 {
354 	if (channel < 0 || channel >= fOutputChannelCount)
355 		return;
356 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
357 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
358 			// when removing a source, save the current gain value into the cache
359 			fOutputChannelInfo[channel].source_gain_cache[source_type] = fOutputChannelInfo[channel].source_gain[i];
360 			// remove the entry
361 			fOutputChannelInfo[channel].source_type[i] = fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count - 1];
362 			fOutputChannelInfo[channel].source_gain[i] = fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count - 1];
363 			fOutputChannelInfo[channel].source_count--;
364 			return;
365 		}
366 	}
367 }
368 
369 
370 void
371 MixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float source_gain)
372 {
373 	if (channel < 0 || channel >= fOutputChannelCount)
374 		return;
375 	// set gain for active source
376 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
377 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
378 			fOutputChannelInfo[channel].source_gain[i] = source_gain;
379 			return;
380 		}
381 	}
382 	// we don't have an active source of that type, save gain in cache
383 	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
384 		return;
385 	fOutputChannelInfo[channel].source_gain_cache[source_type] = source_gain;
386 }
387 
388 
389 float
390 MixerOutput::GetOutputChannelSourceGain(int channel, int source_type)
391 {
392 	if (channel < 0 || channel >= fOutputChannelCount)
393 		return 0.0;
394 	// get gain for active source
395 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
396 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
397 			return fOutputChannelInfo[channel].source_gain[i];
398 		}
399 	}
400 	// we don't have an active source of that type, get gain from cache
401 	if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES)
402 		return 0.0;
403 	return fOutputChannelInfo[channel].source_gain_cache[source_type];
404 }
405 
406 
407 bool
408 MixerOutput::HasOutputChannelSource(int channel, int source_type)
409 {
410 	if (channel < 0 || channel >= fOutputChannelCount)
411 		return false;
412 	for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) {
413 		if (fOutputChannelInfo[channel].source_type[i] == source_type) {
414 			return true;
415 		}
416 	}
417 	return false;
418 }
419 
420 
421 void
422 MixerOutput::SetMuted(bool yesno)
423 {
424 	fMuted = yesno;
425 }
426