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