xref: /haiku/src/add-ons/media/media-add-ons/multi_audio/MultiAudioNode.cpp (revision 0562493379cd52eb7103531f895f10bb8e77c085)
1 /*
2  * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
3  * Distributed under the terms of the MIT License.
4  */
5 
6 //! Multi-audio replacement media addon for BeOS
7 
8 #include "MultiAudioNode.h"
9 
10 #include <stdio.h>
11 #include <string.h>
12 
13 #include <Buffer.h>
14 #include <BufferGroup.h>
15 #include <ParameterWeb.h>
16 
17 #include "MultiAudioUtility.h"
18 #ifdef DEBUG
19 #	define PRINTING
20 #endif
21 #include "debug.h"
22 
23 class node_input {
24 public:
25 	node_input(media_input& input, media_format format);
26 	~node_input();
27 
28 	int32				fChannelId;
29 	media_input			fInput;
30 	media_format 		fPreferredFormat;
31 	media_format		fFormat;
32 	uint32 				fBufferCycle;
33 	multi_buffer_info	fOldBufferInfo;
34 	BBuffer*			fBuffer;
35 };
36 
37 class node_output {
38 public:
39 	node_output(media_output& output, media_format format);
40 	~node_output();
41 
42 	int32				fChannelId;
43 	media_output		fOutput;
44 	media_format 		fPreferredFormat;
45 	media_format		fFormat;
46 
47 	BBufferGroup*		fBufferGroup;
48 	bool 				fOutputEnabled;
49 	uint64 				fSamplesSent;
50 	volatile uint32 	fBufferCycle;
51 	multi_buffer_info	fOldBufferInfo;
52 };
53 
54 
55 const char* kMultiControlString[] = {
56 	"NAME IS ATTACHED",
57 	"Output", "Input", "Setup", "Tone Control", "Extended Setup", "Enhanced Setup", "Master",
58 	"Beep", "Phone", "Mic", "Line", "CD", "Video", "Aux", "Wave", "Gain", "Level", "Volume",
59 	"Mute", "Enable", "Stereo Mix", "Mono Mix", "Output Stereo Mix", "Output Mono Mix", "Output Bass",
60 	"Output Treble", "Output 3D Center", "Output 3D Depth", "Headphones", "SPDIF"
61 };
62 
63 
64 node_input::node_input(media_input& input, media_format format)
65 {
66 	CALLED();
67 	fInput = input;
68 	fPreferredFormat = format;
69 	fBufferCycle = 1;
70 	fBuffer = NULL;
71 }
72 
73 
74 node_input::~node_input()
75 {
76 	CALLED();
77 }
78 
79 
80 //	#pragma mark -
81 
82 
83 node_output::node_output(media_output& output, media_format format)
84 	:
85 	fBufferGroup(NULL),
86 	fOutputEnabled(true)
87 {
88 	CALLED();
89 	fOutput = output;
90 	fPreferredFormat = format;
91 	fBufferCycle = 1;
92 }
93 
94 
95 node_output::~node_output()
96 {
97 	CALLED();
98 }
99 
100 
101 //	#pragma mark -
102 
103 
104 MultiAudioNode::MultiAudioNode(BMediaAddOn* addon, const char* name,
105 		MultiAudioDevice* device, int32 internalID, BMessage* config)
106 	: BMediaNode(name), BBufferConsumer(B_MEDIA_RAW_AUDIO),
107 	BBufferProducer(B_MEDIA_RAW_AUDIO),
108 	fThread(-1),
109 	fDevice(device),
110 	fTimeSourceStarted(false),
111 	fWeb(NULL),
112 	fConfig()
113 {
114 	CALLED();
115 	fInitStatus = B_NO_INIT;
116 
117 	if (!device)
118 		return;
119 
120 	fAddOn = addon;
121 	fId = internalID;
122 
123 	AddNodeKind(B_PHYSICAL_OUTPUT);
124 	AddNodeKind(B_PHYSICAL_INPUT);
125 
126 	// initialize our preferred format object
127 	memset(&fPreferredFormat, 0, sizeof(fPreferredFormat)); // set everything to wildcard first
128 	fPreferredFormat.type = B_MEDIA_RAW_AUDIO;
129 	fPreferredFormat.u.raw_audio.format = MultiAudio::convert_to_media_format(fDevice->FormatInfo().output.format);
130 	fPreferredFormat.u.raw_audio.valid_bits = MultiAudio::convert_to_valid_bits(fDevice->FormatInfo().output.format);
131 	fPreferredFormat.u.raw_audio.channel_count = 2;
132 	fPreferredFormat.u.raw_audio.frame_rate = MultiAudio::convert_to_sample_rate(fDevice->FormatInfo().output.rate);		// measured in Hertz
133 	fPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
134 
135 	// we'll use the consumer's preferred buffer size, if any
136 	fPreferredFormat.u.raw_audio.buffer_size = fDevice->BufferList().return_record_buffer_size
137 		* (fPreferredFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
138 		* fPreferredFormat.u.raw_audio.channel_count;
139 
140 	if (config) {
141 		fConfig = *config;
142 		PRINT_OBJECT(*config);
143 	}
144 
145 	fInitStatus = B_OK;
146 }
147 
148 
149 MultiAudioNode::~MultiAudioNode()
150 {
151 	CALLED();
152 	fAddOn->GetConfigurationFor(this, NULL);
153 
154 	_StopThread();
155 	BMediaEventLooper::Quit();
156 
157 	fWeb = NULL;
158 }
159 
160 
161 status_t
162 MultiAudioNode::InitCheck() const
163 {
164 	CALLED();
165 	return fInitStatus;
166 }
167 
168 
169 // -------------------------------------------------------- //
170 // implementation of BMediaNode
171 // -------------------------------------------------------- //
172 
173 BMediaAddOn*
174 MultiAudioNode::AddOn(int32* _internalID) const
175 {
176 	CALLED();
177 	// BeBook says this only gets called if we were in an add-on.
178 	if (fAddOn != 0 && _internalID != NULL)
179 		*_internalID = fId;
180 
181 	return fAddOn;
182 }
183 
184 
185 void
186 MultiAudioNode::Preroll()
187 {
188 	CALLED();
189 	// XXX:Performance opportunity
190 	BMediaNode::Preroll();
191 }
192 
193 
194 status_t
195 MultiAudioNode::HandleMessage(int32 message, const void* data, size_t size)
196 {
197 	CALLED();
198 	return B_ERROR;
199 }
200 
201 
202 void
203 MultiAudioNode::NodeRegistered()
204 {
205 	CALLED();
206 
207 	if (fInitStatus != B_OK) {
208 		ReportError(B_NODE_IN_DISTRESS);
209 		return;
210 	}
211 
212 	SetPriority(B_REAL_TIME_PRIORITY);
213 	Run();
214 
215 	node_input *currentInput = NULL;
216 	int32 currentId = 0;
217 
218 	for (int32 i = 0; i < fDevice->Description().output_channel_count; i++) {
219 		if (currentInput == NULL
220 			|| (fDevice->Description().channels[i].designations & B_CHANNEL_MONO_BUS)
221 			|| (fDevice->Description().channels[currentId].designations & B_CHANNEL_STEREO_BUS
222 				&& ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT ||
223 					!(fDevice->Description().channels[i].designations & B_CHANNEL_STEREO_BUS)))
224 			|| (fDevice->Description().channels[currentId].designations & B_CHANNEL_SURROUND_BUS
225 				&& ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT ||
226 					!(fDevice->Description().channels[i].designations & B_CHANNEL_SURROUND_BUS)))
227 			) {
228 			PRINT(("NodeRegistered() : creating an input for %li\n", i));
229 			PRINT(("%ld\t%d\t0x%lx\t0x%lx\n",
230 				fDevice->Description().channels[i].channel_id,
231 				fDevice->Description().channels[i].kind,
232 				fDevice->Description().channels[i].designations,
233 				fDevice->Description().channels[i].connectors));
234 
235 			media_input* input = new media_input;
236 
237 			input->format = fPreferredFormat;
238 			input->destination.port = ControlPort();
239 			input->destination.id = fInputs.CountItems();
240 			input->node = Node();
241 			sprintf(input->name, "output %ld", input->destination.id);
242 
243 			currentInput = new node_input(*input, fPreferredFormat);
244 			currentInput->fPreferredFormat.u.raw_audio.channel_count = 1;
245 			currentInput->fInput.format = currentInput->fPreferredFormat;
246 
247 			currentInput->fChannelId = fDevice->Description().channels[i].channel_id;
248 			fInputs.AddItem(currentInput);
249 
250 			currentId = i;
251 		} else {
252 			PRINT(("NodeRegistered() : adding a channel\n"));
253 			currentInput->fPreferredFormat.u.raw_audio.channel_count++;
254 			currentInput->fInput.format = currentInput->fPreferredFormat;
255 		}
256 		currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format;
257 	}
258 
259 	node_output *currentOutput = NULL;
260 	currentId = 0;
261 
262 	for (int32 i = fDevice->Description().output_channel_count;
263 			i < fDevice->Description().output_channel_count
264 				+ fDevice->Description().input_channel_count; i++) {
265 		if (currentOutput == NULL
266 			|| (fDevice->Description().channels[i].designations & B_CHANNEL_MONO_BUS)
267 			|| (fDevice->Description().channels[currentId].designations & B_CHANNEL_STEREO_BUS
268 				&& ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT ||
269 					!(fDevice->Description().channels[i].designations & B_CHANNEL_STEREO_BUS)))
270 			|| (fDevice->Description().channels[currentId].designations & B_CHANNEL_SURROUND_BUS
271 				&& ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT ||
272 					!(fDevice->Description().channels[i].designations & B_CHANNEL_SURROUND_BUS)))
273 			) {
274 			PRINT(("NodeRegistered() : creating an output for %li\n", i));
275 			PRINT(("%ld\t%d\t0x%lx\t0x%lx\n",fDevice->Description().channels[i].channel_id,
276 											fDevice->Description().channels[i].kind,
277 											fDevice->Description().channels[i].designations,
278 											fDevice->Description().channels[i].connectors));
279 
280 			media_output *output = new media_output;
281 
282 			output->format = fPreferredFormat;
283 			output->destination = media_destination::null;
284 			output->source.port = ControlPort();
285 			output->source.id = fOutputs.CountItems();
286 			output->node = Node();
287 			sprintf(output->name, "input %ld", output->source.id);
288 
289 			currentOutput = new node_output(*output, fPreferredFormat);
290 			currentOutput->fPreferredFormat.u.raw_audio.channel_count = 1;
291 			currentOutput->fOutput.format = currentOutput->fPreferredFormat;
292 			currentOutput->fChannelId = fDevice->Description().channels[i].channel_id;
293 			fOutputs.AddItem(currentOutput);
294 
295 			currentId = i;
296 		} else {
297 			PRINT(("NodeRegistered() : adding a channel\n"));
298 			currentOutput->fPreferredFormat.u.raw_audio.channel_count++;
299 			currentOutput->fOutput.format = currentOutput->fPreferredFormat;
300 		}
301 	}
302 
303 	// Set up our parameter web
304 	fWeb = MakeParameterWeb();
305 	SetParameterWeb(fWeb);
306 
307 	/* apply configuration */
308 #ifdef PRINTING
309 	bigtime_t start = system_time();
310 #endif
311 
312 	int32 index = 0;
313 	int32 parameterID = 0;
314 	const void *data;
315 	ssize_t size;
316 	while (fConfig.FindInt32("parameterID", index, &parameterID) == B_OK) {
317 		if (fConfig.FindData("parameterData", B_RAW_TYPE, index, &data, &size)
318 				== B_OK) {
319 			SetParameterValue(parameterID, TimeSource()->Now(), data, size);
320 		}
321 		index++;
322 	}
323 
324 	PRINT(("apply configuration in : %Ld\n", system_time() - start));
325 }
326 
327 
328 status_t
329 MultiAudioNode::RequestCompleted(const media_request_info& info)
330 {
331 	CALLED();
332 	return B_OK;
333 }
334 
335 
336 void
337 MultiAudioNode::SetTimeSource(BTimeSource* timeSource)
338 {
339 	CALLED();
340 }
341 
342 
343 //	#pragma mark - BBufferConsumer
344 
345 
346 // Check to make sure the format is okay, then remove
347 // any wildcards corresponding to our requirements.
348 status_t
349 MultiAudioNode::AcceptFormat(const media_destination& dest,
350 	media_format* format)
351 {
352 	CALLED();
353 
354 	if (format == NULL)
355 		return B_BAD_VALUE;
356 	if (format->type != B_MEDIA_RAW_AUDIO)
357 		return B_MEDIA_BAD_FORMAT;
358 
359 	node_input *channel = _FindInput(dest);
360 	if (channel == NULL)
361 		return B_MEDIA_BAD_DESTINATION;
362 
363 /*	media_format * myFormat = GetFormat();
364 	fprintf(stderr,"proposed format: ");
365 	print_media_format(format);
366 	fprintf(stderr,"\n");
367 	fprintf(stderr,"my format: ");
368 	print_media_format(myFormat);
369 	fprintf(stderr,"\n");*/
370 	// Be's format_is_compatible doesn't work.
371 //	if (!format_is_compatible(*format,*myFormat)) {
372 
373 	channel->fFormat = channel->fPreferredFormat;
374 
375 	/*if(format->u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
376 		&& channel->fPreferredFormat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT)
377 		format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
378 	else*/
379 	format->u.raw_audio.format = channel->fPreferredFormat.u.raw_audio.format;
380 	format->u.raw_audio.valid_bits = channel->fPreferredFormat.u.raw_audio.valid_bits;
381 
382 	format->u.raw_audio.frame_rate    = channel->fPreferredFormat.u.raw_audio.frame_rate;
383 	format->u.raw_audio.channel_count = channel->fPreferredFormat.u.raw_audio.channel_count;
384 	format->u.raw_audio.byte_order    = B_MEDIA_HOST_ENDIAN;
385 	format->u.raw_audio.buffer_size   = fDevice->BufferList().return_playback_buffer_size
386 		* (format->u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
387 		* format->u.raw_audio.channel_count;
388 
389 	/*media_format myFormat;
390 	GetFormat(&myFormat);
391 	if (!format_is_acceptible(*format,myFormat)) {
392 		fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
393 		return B_MEDIA_BAD_FORMAT;
394 	}*/
395 	//AddRequirements(format);
396 	return B_OK;
397 }
398 
399 
400 status_t
401 MultiAudioNode::GetNextInput(int32* cookie, media_input* _input)
402 {
403 	CALLED();
404 	if (_input == NULL)
405 		return B_BAD_VALUE;
406 
407 	if (*cookie >= fInputs.CountItems() || *cookie < 0)
408 		return B_BAD_INDEX;
409 
410 	node_input *channel = (node_input *)fInputs.ItemAt(*cookie);
411 	*_input = channel->fInput;
412 	*cookie += 1;
413 	PRINT(("input.format : %lu\n", channel->fInput.format.u.raw_audio.format));
414 	return B_OK;
415 }
416 
417 
418 void
419 MultiAudioNode::DisposeInputCookie(int32 cookie)
420 {
421 	CALLED();
422 	// nothing to do since our cookies are just integers
423 }
424 
425 
426 void
427 MultiAudioNode::BufferReceived(BBuffer* buffer)
428 {
429 	//CALLED();
430 	switch (buffer->Header()->type) {
431 		/*case B_MEDIA_PARAMETERS:
432 			{
433 			status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
434 			if (status != B_OK) {
435 				fprintf(stderr,"ApplyParameterData in MultiAudioNode::BufferReceived failed\n");
436 			}
437 			buffer->Recycle();
438 			}
439 			break;*/
440 		case B_MEDIA_RAW_AUDIO:
441 			if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) {
442 				fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MultiAudioNode::BufferReceived\n");
443 				// XXX: implement this part
444 				buffer->Recycle();
445 			} else {
446 				media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
447 										buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
448 				status_t status = EventQueue()->AddEvent(event);
449 				if (status != B_OK) {
450 					fprintf(stderr,"EventQueue()->AddEvent(event) in MultiAudioNode::BufferReceived failed\n");
451 					buffer->Recycle();
452 				}
453 			}
454 			break;
455 		default:
456 			fprintf(stderr,"unexpected buffer type in MultiAudioNode::BufferReceived\n");
457 			buffer->Recycle();
458 			break;
459 	}
460 }
461 
462 
463 void
464 MultiAudioNode::ProducerDataStatus(const media_destination& forWhom,
465 	int32 status, bigtime_t atPerformanceTime)
466 {
467 	//CALLED();
468 
469 	node_input *channel = _FindInput(forWhom);
470 	if (channel == NULL) {
471 		fprintf(stderr,"invalid destination received in MultiAudioNode::ProducerDataStatus\n");
472 		return;
473 	}
474 
475 	media_timed_event event(atPerformanceTime, BTimedEventQueue::B_DATA_STATUS,
476 		&channel->fInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
477 	EventQueue()->AddEvent(event);
478 }
479 
480 
481 status_t
482 MultiAudioNode::GetLatencyFor(const media_destination& forWhom,
483 	bigtime_t* _latency, media_node_id* _timeSource)
484 {
485 	CALLED();
486 	if (_latency == NULL || _timeSource == NULL)
487 		return B_BAD_VALUE;
488 
489 	node_input *channel = _FindInput(forWhom);
490 	if (channel == NULL)
491 		return B_MEDIA_BAD_DESTINATION;
492 
493 	*_latency = EventLatency();
494 	*_timeSource = TimeSource()->ID();
495 	return B_OK;
496 }
497 
498 
499 status_t
500 MultiAudioNode::Connected(const media_source& producer,
501 	const media_destination& where, const media_format& with_format,
502 	media_input* out_input)
503 {
504 	CALLED();
505 	if (out_input == 0) {
506 		fprintf(stderr,"<- B_BAD_VALUE\n");
507 		return B_BAD_VALUE; // no crashing
508 	}
509 
510 	node_input *channel = _FindInput(where);
511 
512 	if(channel==NULL) {
513 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
514 		return B_MEDIA_BAD_DESTINATION;
515 	}
516 
517 	// use one buffer length latency
518 	fInternalLatency = with_format.u.raw_audio.buffer_size * 10000 / 2
519 		/ ( (with_format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
520 			* with_format.u.raw_audio.channel_count)
521 		/ ((int32)(with_format.u.raw_audio.frame_rate / 100));
522 
523 	PRINT(("  internal latency = %lld\n",fInternalLatency));
524 
525 	SetEventLatency(fInternalLatency);
526 
527 	// record the agreed upon values
528 	channel->fInput.source = producer;
529 	channel->fInput.format = with_format;
530 	*out_input = channel->fInput;
531 
532 	// we are sure the thread is started
533 	_StartThread();
534 
535 	return B_OK;
536 }
537 
538 
539 void
540 MultiAudioNode::Disconnected(const media_source& producer,
541 	const media_destination& where)
542 {
543 	CALLED();
544 	node_input *channel = _FindInput(where);
545 
546 	if (channel == NULL || channel->fInput.source != producer)
547 		return;
548 
549 	channel->fInput.source = media_source::null;
550 	channel->fInput.format = channel->fPreferredFormat;
551 	_FillWithZeros(*channel);
552 	//GetFormat(&channel->fInput.format);
553 }
554 
555 
556 status_t
557 MultiAudioNode::FormatChanged(const media_source& producer,
558 	const media_destination& consumer, int32 change_tag,
559 	const media_format& format)
560 {
561 	CALLED();
562 	node_input *channel = _FindInput(consumer);
563 
564 	if(channel==NULL) {
565 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
566 		return B_MEDIA_BAD_DESTINATION;
567 	}
568 	if (channel->fInput.source != producer) {
569 		return B_MEDIA_BAD_SOURCE;
570 	}
571 
572 	return B_ERROR;
573 }
574 
575 
576 status_t
577 MultiAudioNode::SeekTagRequested(const media_destination& destination,
578 				bigtime_t in_target_time,
579 				uint32 in_flags,
580 				media_seek_tag * out_seek_tag,
581 				bigtime_t * out_tagged_time,
582 				uint32 * out_flags)
583 {
584 	CALLED();
585 	return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags,
586 											out_seek_tag,out_tagged_time,out_flags);
587 }
588 
589 
590 //	#pragma mark - BBufferProducer
591 
592 
593 status_t
594 MultiAudioNode::FormatSuggestionRequested(media_type type, int32 /*quality*/,
595 	media_format* format)
596 {
597 	// FormatSuggestionRequested() is not necessarily part of the format negotiation
598 	// process; it's simply an interrogation -- the caller wants to see what the node's
599 	// preferred data format is, given a suggestion by the caller.
600 	CALLED();
601 
602 	if (!format)
603 	{
604 		fprintf(stderr, "\tERROR - NULL format pointer passed in!\n");
605 		return B_BAD_VALUE;
606 	}
607 
608 	// this is the format we'll be returning (our preferred format)
609 	*format = fPreferredFormat;
610 
611 	// a wildcard type is okay; we can specialize it
612 	if (type == B_MEDIA_UNKNOWN_TYPE) type = B_MEDIA_RAW_AUDIO;
613 
614 	// we only support raw audio
615 	if (type != B_MEDIA_RAW_AUDIO) return B_MEDIA_BAD_FORMAT;
616 	else return B_OK;
617 }
618 
619 
620 status_t
621 MultiAudioNode::FormatProposal(const media_source& output, media_format* format)
622 {
623 	// FormatProposal() is the first stage in the BMediaRoster::Connect() process.  We hand
624 	// out a suggested format, with wildcards for any variations we support.
625 	CALLED();
626 	node_output *channel = _FindOutput(output);
627 
628 	// is this a proposal for our select output?
629 	if (channel == NULL)
630 	{
631 		fprintf(stderr, "MultiAudioNode::FormatProposal returning B_MEDIA_BAD_SOURCE\n");
632 		return B_MEDIA_BAD_SOURCE;
633 	}
634 
635 	// we only support floating-point raw audio, so we always return that, but we
636 	// supply an error code depending on whether we found the proposal acceptable.
637 	media_type requestedType = format->type;
638 	*format = channel->fPreferredFormat;
639 	if ((requestedType != B_MEDIA_UNKNOWN_TYPE) && (requestedType != B_MEDIA_RAW_AUDIO))
640 	{
641 		fprintf(stderr, "MultiAudioNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n");
642 		return B_MEDIA_BAD_FORMAT;
643 	}
644 	else return B_OK;		// raw audio or wildcard type, either is okay by us
645 }
646 
647 
648 status_t
649 MultiAudioNode::FormatChangeRequested(const media_source& source,
650 	const media_destination& destination, media_format* format,
651 	int32* _deprecated_)
652 {
653 	CALLED();
654 
655 	// we don't support any other formats, so we just reject any format changes.
656 	return B_ERROR;
657 }
658 
659 
660 status_t
661 MultiAudioNode::GetNextOutput(int32* cookie, media_output* out_output)
662 {
663 	CALLED();
664 
665 	if ((*cookie < fOutputs.CountItems()) && (*cookie >= 0)) {
666 		node_output *channel = (node_output *)fOutputs.ItemAt(*cookie);
667 		*out_output = channel->fOutput;
668 		*cookie += 1;
669 		return B_OK;
670 	} else
671 		return B_BAD_INDEX;
672 }
673 
674 
675 status_t
676 MultiAudioNode::DisposeOutputCookie(int32 cookie)
677 {
678 	CALLED();
679 	// do nothing because we don't use the cookie for anything special
680 	return B_OK;
681 }
682 
683 
684 status_t
685 MultiAudioNode::SetBufferGroup(const media_source& for_source,
686 	BBufferGroup* newGroup)
687 {
688 	CALLED();
689 
690 	node_output *channel = _FindOutput(for_source);
691 
692 	// is this our output?
693 	if (channel == NULL)
694 	{
695 		fprintf(stderr, "MultiAudioNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n");
696 		return B_MEDIA_BAD_SOURCE;
697 	}
698 
699 	// Are we being passed the buffer group we're already using?
700 	if (newGroup == channel->fBufferGroup) return B_OK;
701 
702 	// Ahh, someone wants us to use a different buffer group.  At this point we delete
703 	// the one we are using and use the specified one instead.  If the specified group is
704 	// NULL, we need to recreate one ourselves, and use *that*.  Note that if we're
705 	// caching a BBuffer that we requested earlier, we have to Recycle() that buffer
706 	// *before* deleting the buffer group, otherwise we'll deadlock waiting for that
707 	// buffer to be recycled!
708 	delete channel->fBufferGroup;		// waits for all buffers to recycle
709 	if (newGroup != NULL)
710 	{
711 		// we were given a valid group; just use that one from now on
712 		channel->fBufferGroup = newGroup;
713 	}
714 	else
715 	{
716 		// we were passed a NULL group pointer; that means we construct
717 		// our own buffer group to use from now on
718 		size_t size = channel->fOutput.format.u.raw_audio.buffer_size;
719 		int32 count = int32(fLatency / BufferDuration() + 1 + 1);
720 		channel->fBufferGroup = new BBufferGroup(size, count);
721 	}
722 
723 	return B_OK;
724 }
725 
726 
727 status_t
728 MultiAudioNode::PrepareToConnect(const media_source& what,
729 	const media_destination& where, media_format* format,
730 	media_source* source, char* name)
731 {
732 	CALLED();
733 
734 	// is this our output?
735 	node_output* channel = _FindOutput(what);
736 	if (channel == NULL) {
737 		fprintf(stderr, "MultiAudioNode::PrepareToConnect returning B_MEDIA_BAD_SOURCE\n");
738 		return B_MEDIA_BAD_SOURCE;
739 	}
740 
741 	// are we already connected?
742 	if (channel->fOutput.destination != media_destination::null)
743 		return B_MEDIA_ALREADY_CONNECTED;
744 
745 	// the format may not yet be fully specialized (the consumer might have
746 	// passed back some wildcards).  Finish specializing it now, and return an
747 	// error if we don't support the requested format.
748 	if (format->type != B_MEDIA_RAW_AUDIO) {
749 		fprintf(stderr, "\tnon-raw-audio format?!\n");
750 		return B_MEDIA_BAD_FORMAT;
751 	}
752 
753 	// !!! validate all other fields except for buffer_size here, because the
754 	// consumer might have supplied different values from AcceptFormat()?
755 
756 	// check the buffer size, which may still be wildcarded
757 	if (format->u.raw_audio.buffer_size
758 			== media_raw_audio_format::wildcard.buffer_size) {
759 		format->u.raw_audio.buffer_size = 2048;
760 			// pick something comfortable to suggest
761 		fprintf(stderr, "\tno buffer size provided, suggesting %lu\n",
762 			format->u.raw_audio.buffer_size);
763 	} else {
764 		fprintf(stderr, "\tconsumer suggested buffer_size %lu\n",
765 			format->u.raw_audio.buffer_size);
766 	}
767 
768 	// Now reserve the connection, and return information about it
769 	channel->fOutput.destination = where;
770 	channel->fOutput.format = *format;
771 
772 	*source = channel->fOutput.source;
773 #ifdef __HAIKU__
774 	strlcpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
775 #else
776 	strncpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
777 #endif
778 	return B_OK;
779 }
780 
781 
782 void
783 MultiAudioNode::Connect(status_t error, const media_source& source,
784 	const media_destination& destination, const media_format& format,
785 	char* name)
786 {
787 	CALLED();
788 
789 	// is this our output?
790 	node_output* channel = _FindOutput(source);
791 	if (channel == NULL) {
792 		fprintf(stderr, "MultiAudioNode::Connect returning (cause : B_MEDIA_BAD_SOURCE)\n");
793 		return;
794 	}
795 
796 	// If something earlier failed, Connect() might still be called, but with
797 	// a non-zero error code.  When that happens we simply unreserve the
798 	// connection and do nothing else.
799 	if (error) {
800 		channel->fOutput.destination = media_destination::null;
801 		channel->fOutput.format = channel->fPreferredFormat;
802 		return;
803 	}
804 
805 	// Okay, the connection has been confirmed.  Record the destination and
806 	// format that we agreed on, and report our connection name again.
807 	channel->fOutput.destination = destination;
808 	channel->fOutput.format = format;
809 #ifdef __HAIKU__
810 	strlcpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
811 #else
812 	strncpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
813 #endif
814 
815 	// reset our buffer duration, etc. to avoid later calculations
816 	bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000
817 		/ ((channel->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
818 			* channel->fOutput.format.u.raw_audio.channel_count)
819 		/ ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100));
820 
821 	SetBufferDuration(duration);
822 
823 	// Now that we're connected, we can determine our downstream latency.
824 	// Do so, then make sure we get our events early enough.
825 	media_node_id id;
826 	FindLatencyFor(channel->fOutput.destination, &fLatency, &id);
827 	PRINT(("\tdownstream latency = %Ld\n", fLatency));
828 
829 	fInternalLatency = BufferDuration();
830 	PRINT(("\tbuffer-filling took %Ld usec on this machine\n", fInternalLatency));
831 	//SetEventLatency(fLatency + fInternalLatency);
832 
833 	// Set up the buffer group for our connection, as long as nobody handed us
834 	// a buffer group (via SetBufferGroup()) prior to this.  That can happen,
835 	// for example, if the consumer calls SetOutputBuffersFor() on us from
836 	// within its Connected() method.
837 	if (!channel->fBufferGroup)
838 		_AllocateBuffers(*channel);
839 
840 	// we are sure the thread is started
841 	_StartThread();
842 }
843 
844 
845 void
846 MultiAudioNode::Disconnect(const media_source& what,
847 	const media_destination& where)
848 {
849 	CALLED();
850 
851 	// is this our output?
852 	node_output* channel = _FindOutput(what);
853 	if (channel == NULL) {
854 		fprintf(stderr, "MultiAudioNode::Disconnect() returning (cause : B_MEDIA_BAD_SOURCE)\n");
855 		return;
856 	}
857 
858 	// Make sure that our connection is the one being disconnected
859 	if (where == channel->fOutput.destination
860 		&& what == channel->fOutput.source) {
861 		channel->fOutput.destination = media_destination::null;
862 		channel->fOutput.format = channel->fPreferredFormat;
863 		delete channel->fBufferGroup;
864 		channel->fBufferGroup = NULL;
865 	} else {
866 		fprintf(stderr, "\tDisconnect() called with wrong source/destination (%ld/%ld), ours is (%ld/%ld)\n",
867 			what.id, where.id, channel->fOutput.source.id, channel->fOutput.destination.id);
868 	}
869 }
870 
871 
872 void
873 MultiAudioNode::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
874 	bigtime_t performanceTime)
875 {
876 	CALLED();
877 
878 	// is this our output?
879 	node_output *channel = _FindOutput(what);
880 	if (channel == NULL)
881 		return;
882 
883 	// If we're late, we need to catch up.  Respond in a manner appropriate
884 	// to our current run mode.
885 	if (RunMode() == B_RECORDING) {
886 		// A hardware capture node can't adjust; it simply emits buffers at
887 		// appropriate points.  We (partially) simulate this by not adjusting
888 		// our behavior upon receiving late notices -- after all, the hardware
889 		// can't choose to capture "sooner"....
890 	} else if (RunMode() == B_INCREASE_LATENCY) {
891 		// We're late, and our run mode dictates that we try to produce buffers
892 		// earlier in order to catch up.  This argues that the downstream nodes
893 		// are not properly reporting their latency, but there's not much we can
894 		// do about that at the moment, so we try to start producing buffers
895 		// earlier to compensate.
896 		fInternalLatency += howMuch;
897 		SetEventLatency(fLatency + fInternalLatency);
898 
899 		fprintf(stderr, "\tincreasing latency to %Ld\n",
900 			fLatency + fInternalLatency);
901 	} else {
902 		// The other run modes dictate various strategies for sacrificing data
903 		// quality in the interests of timely data delivery.  The way *we* do
904 		// this is to skip a buffer, which catches us up in time by one buffer
905 		// duration.
906 		/*size_t nSamples = fOutput.format.u.raw_audio.buffer_size / sizeof(float);
907 		mSamplesSent += nSamples;*/
908 
909 		fprintf(stderr, "\tskipping a buffer to try to catch up\n");
910 	}
911 }
912 
913 
914 void
915 MultiAudioNode::EnableOutput(const media_source& what, bool enabled,
916 	int32* _deprecated_)
917 {
918 	CALLED();
919 
920 	// If I had more than one output, I'd have to walk my list of output
921 	// records to see which one matched the given source, and then
922 	// enable/disable that one.  But this node only has one output, so I
923 	// just make sure the given source matches, then set the enable state
924 	// accordingly.
925 	node_output *channel = _FindOutput(what);
926 	if (channel != NULL)
927 		channel->fOutputEnabled = enabled;
928 }
929 
930 
931 void
932 MultiAudioNode::AdditionalBufferRequested(const media_source& source,
933 	media_buffer_id previousBuffer, bigtime_t previousTime,
934 	const media_seek_tag* previousTag)
935 {
936 	CALLED();
937 	// we don't support offline mode
938 	return;
939 }
940 
941 
942 //	#pragma mark - BMediaEventLooper
943 
944 
945 void
946 MultiAudioNode::HandleEvent(const media_timed_event* event, bigtime_t lateness,
947 	bool realTimeEvent)
948 {
949 	//CALLED();
950 	switch (event->type) {
951 		case BTimedEventQueue::B_START:
952 			_HandleStart(event, lateness, realTimeEvent);
953 			break;
954 		case BTimedEventQueue::B_SEEK:
955 			_HandleSeek(event, lateness, realTimeEvent);
956 			break;
957 		case BTimedEventQueue::B_WARP:
958 			_HandleWarp(event, lateness, realTimeEvent);
959 			break;
960 		case BTimedEventQueue::B_STOP:
961 			_HandleStop(event, lateness, realTimeEvent);
962 			break;
963 		case BTimedEventQueue::B_HANDLE_BUFFER:
964 			if (RunState() == BMediaEventLooper::B_STARTED)
965 				_HandleBuffer(event, lateness, realTimeEvent);
966 			break;
967 		case BTimedEventQueue::B_DATA_STATUS:
968 			_HandleDataStatus(event, lateness, realTimeEvent);
969 			break;
970 		case BTimedEventQueue::B_PARAMETER:
971 			_HandleParameter(event, lateness, realTimeEvent);
972 			break;
973 		default:
974 			fprintf(stderr,"  unknown event type: %li\n", event->type);
975 			break;
976 	}
977 }
978 
979 
980 // TODO: how should we handle late buffers? drop them?
981 // notify the producer?
982 status_t
983 MultiAudioNode::_HandleBuffer(const media_timed_event* event,
984 	bigtime_t lateness, bool realTimeEvent)
985 {
986 	//CALLED();
987 	BBuffer* buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
988 	if (buffer == NULL)
989 		return B_BAD_VALUE;
990 
991 	//PRINT(("buffer->Header()->destination : %i\n", buffer->Header()->destination));
992 
993 	node_input* channel = _FindInput(buffer->Header()->destination);
994 	if (channel == NULL) {
995 		buffer->Recycle();
996 		return B_MEDIA_BAD_DESTINATION;
997 	}
998 
999 	bigtime_t now = TimeSource()->Now();
1000 	bigtime_t performanceTime = buffer->Header()->start_time;
1001 
1002 	// the how_early calculate here doesn't include scheduling latency because
1003 	// we've already been scheduled to handle the buffer
1004 	bigtime_t howEarly = performanceTime - EventLatency() - now;
1005 
1006 	// if the buffer is late, we ignore it and report the fact to the producer
1007 	// who sent it to us
1008 	if (RunMode() != B_OFFLINE && RunMode() != B_RECORDING && howEarly < 0LL) {
1009 		// lateness doesn't matter in offline mode or in recording mode
1010 		//mLateBuffers++;
1011 		NotifyLateProducer(channel->fInput.source, -howEarly, performanceTime);
1012 		fprintf(stderr,"	<- LATE BUFFER : %lli\n", howEarly);
1013 		buffer->Recycle();
1014 	} else {
1015 		//WriteBuffer(buffer, *channel);
1016 		if (channel->fBuffer != NULL) {
1017 			PRINT(("MultiAudioNode::HandleBuffer snoozing recycling channelId : %li, how_early:%Ld\n", channel->fChannelId, howEarly));
1018 			//channel->fBuffer->Recycle();
1019 			snooze(100);
1020 			if (channel->fBuffer != NULL)
1021 				buffer->Recycle();
1022 			else
1023 				channel->fBuffer = buffer;
1024 		} else {
1025 			//PRINT(("MultiAudioNode::HandleBuffer writing channelId : %li, how_early:%Ld\n", channel->fChannelId, howEarly));
1026 			channel->fBuffer = buffer;
1027 		}
1028 	}
1029 	return B_OK;
1030 }
1031 
1032 
1033 status_t
1034 MultiAudioNode::_HandleDataStatus(const media_timed_event* event,
1035 	bigtime_t lateness, bool realTimeEvent)
1036 {
1037 	//CALLED();
1038 	PRINT(("MultiAudioNode::HandleDataStatus status:%li, lateness:%Li\n", event->data, lateness));
1039 	switch (event->data) {
1040 		case B_DATA_NOT_AVAILABLE:
1041 			break;
1042 		case B_DATA_AVAILABLE:
1043 			break;
1044 		case B_PRODUCER_STOPPED:
1045 			break;
1046 		default:
1047 			break;
1048 	}
1049 	return B_OK;
1050 }
1051 
1052 
1053 status_t
1054 MultiAudioNode::_HandleStart(const media_timed_event *event, bigtime_t lateness,
1055 	bool realTimeEvent)
1056 {
1057 	CALLED();
1058 	if (RunState() != B_STARTED) {
1059 	}
1060 	return B_OK;
1061 }
1062 
1063 
1064 status_t
1065 MultiAudioNode::_HandleSeek(const media_timed_event* event, bigtime_t lateness,
1066 	bool realTimeEvent)
1067 {
1068 	CALLED();
1069 	PRINT(("MultiAudioNode::HandleSeek(t=%lld,d=%li,bd=%lld)\n",
1070 		event->event_time,event->data,event->bigdata));
1071 	return B_OK;
1072 }
1073 
1074 
1075 status_t
1076 MultiAudioNode::_HandleWarp(const media_timed_event* event, bigtime_t lateness,
1077 	bool realTimeEvent)
1078 {
1079 	CALLED();
1080 	return B_OK;
1081 }
1082 
1083 
1084 status_t
1085 MultiAudioNode::_HandleStop(const media_timed_event* event, bigtime_t lateness,
1086 	bool realTimeEvent)
1087 {
1088 	CALLED();
1089 	// flush the queue so downstreamers don't get any more
1090 	EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
1091 		BTimedEventQueue::B_HANDLE_BUFFER);
1092 
1093 	//_StopThread();
1094 	return B_OK;
1095 }
1096 
1097 
1098 status_t
1099 MultiAudioNode::_HandleParameter(const media_timed_event* event,
1100 	bigtime_t lateness, bool realTimeEvent)
1101 {
1102 	CALLED();
1103 	return B_OK;
1104 }
1105 
1106 
1107 //	#pragma mark - BTimeSource
1108 
1109 
1110 void
1111 MultiAudioNode::SetRunMode(run_mode mode)
1112 {
1113 	CALLED();
1114 	PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode));
1115 	//BTimeSource::SetRunMode(mode);
1116 }
1117 
1118 
1119 status_t
1120 MultiAudioNode::TimeSourceOp(const time_source_op_info& op, void* _reserved)
1121 {
1122 	CALLED();
1123 	switch (op.op) {
1124 		case B_TIMESOURCE_START:
1125 			PRINT(("TimeSourceOp op B_TIMESOURCE_START\n"));
1126 			if (RunState() != BMediaEventLooper::B_STARTED) {
1127 				fTimeSourceStarted = true;
1128 				_StartThread();
1129 
1130 				media_timed_event startEvent(0, BTimedEventQueue::B_START);
1131 				EventQueue()->AddEvent(startEvent);
1132 			}
1133 			break;
1134 		case B_TIMESOURCE_STOP:
1135 			PRINT(("TimeSourceOp op B_TIMESOURCE_STOP\n"));
1136 			if (RunState() == BMediaEventLooper::B_STARTED) {
1137 				media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
1138 				EventQueue()->AddEvent(stopEvent);
1139 				fTimeSourceStarted = false;
1140 				_StopThread();
1141 				PublishTime(0, 0, 0);
1142 			}
1143 			break;
1144 		case B_TIMESOURCE_STOP_IMMEDIATELY:
1145 			PRINT(("TimeSourceOp op B_TIMESOURCE_STOP_IMMEDIATELY\n"));
1146 			if (RunState() == BMediaEventLooper::B_STARTED) {
1147 				media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
1148 				EventQueue()->AddEvent(stopEvent);
1149 				fTimeSourceStarted = false;
1150 				_StopThread();
1151 				PublishTime(0, 0, 0);
1152 			}
1153 			break;
1154 		case B_TIMESOURCE_SEEK:
1155 			PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n"));
1156 			BroadcastTimeWarp(op.real_time, op.performance_time);
1157 			break;
1158 		default:
1159 			break;
1160 	}
1161 	return B_OK;
1162 }
1163 
1164 
1165 //	#pragma mark - BControllable
1166 
1167 
1168 status_t
1169 MultiAudioNode::GetParameterValue(int32 id, bigtime_t* lastChange, void* value,
1170 	size_t* size)
1171 {
1172 	CALLED();
1173 
1174 	PRINT(("id : %li\n", id));
1175 	BParameter* parameter = NULL;
1176 	for (int32 i = 0; i < fWeb->CountParameters(); i++) {
1177 		parameter = fWeb->ParameterAt(i);
1178 		if (parameter->ID() == id)
1179 			break;
1180 	}
1181 
1182 	if (parameter == NULL) {
1183 		// Hmmm, we were asked for a parameter that we don't actually
1184 		// support.  Report an error back to the caller.
1185 		PRINT(("\terror - asked for illegal parameter %ld\n", id));
1186 		return B_ERROR;
1187 	}
1188 
1189 	multi_mix_value_info info;
1190 	multi_mix_value values[2];
1191 	info.values = values;
1192 	info.item_count = 0;
1193 	multi_mix_control* controls = fDevice->MixControlInfo().controls;
1194 	int32 control_id = controls[id - 100].id;
1195 
1196 	if (*size < sizeof(float))
1197 		return B_ERROR;
1198 
1199 	if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) {
1200 		info.item_count = 1;
1201 		values[0].id = control_id;
1202 
1203 		if (parameter->CountChannels() == 2) {
1204 			if (*size < 2*sizeof(float))
1205 				return B_ERROR;
1206 			info.item_count = 2;
1207 			values[1].id = controls[id + 1 - 100].id;
1208 		}
1209 	} else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) {
1210 		info.item_count = 1;
1211 		values[0].id = control_id;
1212 	}
1213 
1214 	if (info.item_count > 0) {
1215 		status_t status = fDevice->GetMix(&info);
1216 		if (status != B_OK) {
1217 			fprintf(stderr, "Failed on DRIVER_GET_MIX\n");
1218 		} else {
1219 			if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) {
1220 				((float*)value)[0] = values[0].gain;
1221 				*size = sizeof(float);
1222 
1223 				if (parameter->CountChannels() == 2) {
1224 					((float*)value)[1] = values[1].gain;
1225 					*size = 2*sizeof(float);
1226 				}
1227 
1228 				for (uint32 i = 0; i < *size / sizeof(float); i++) {
1229 					PRINT(("GetParameterValue B_CONTINUOUS_PARAMETER value[%li] : %f\n", i, ((float*)value)[i]));
1230 				}
1231 			} else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) {
1232 				BDiscreteParameter* discrete = (BDiscreteParameter*)parameter;
1233 				if (discrete->CountItems() <= 2)
1234 					((int32*)value)[0] = values[0].enable ? 1 : 0;
1235 				else
1236 					((int32*)value)[0] = values[0].mux;
1237 
1238 				*size = sizeof(int32);
1239 
1240 				for (uint32 i = 0; i < *size / sizeof(int32); i++) {
1241 					PRINT(("GetParameterValue B_DISCRETE_PARAMETER value[%li] : %li\n", i, ((int32*)value)[i]));
1242 				}
1243 			}
1244 		}
1245 	}
1246 	return B_OK;
1247 }
1248 
1249 
1250 void
1251 MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
1252 	const void* value, size_t size)
1253 {
1254 	CALLED();
1255 	PRINT(("id : %li, performance_time : %lld, size : %li\n", id, performanceTime, size));
1256 
1257 	BParameter* parameter = NULL;
1258 	for (int32 i = 0; i < fWeb->CountParameters(); i++) {
1259 		parameter = fWeb->ParameterAt(i);
1260 		if (parameter->ID() == id)
1261 			break;
1262 	}
1263 
1264 	if (parameter == NULL)
1265 		return;
1266 
1267 	multi_mix_value_info info;
1268 	multi_mix_value values[2];
1269 	info.values = values;
1270 	info.item_count = 0;
1271 	multi_mix_control* controls = fDevice->MixControlInfo().controls;
1272 	int32 control_id = controls[id - 100].id;
1273 
1274 	if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) {
1275 		for (uint32 i = 0; i < size / sizeof(float); i++) {
1276 			PRINT(("SetParameterValue B_CONTINUOUS_PARAMETER value[%li] : %f\n", i, ((float*)value)[i]));
1277 		}
1278 		info.item_count = 1;
1279 		values[0].id = control_id;
1280 		values[0].gain = ((float*)value)[0];
1281 
1282 		if (parameter->CountChannels() == 2) {
1283 			info.item_count = 2;
1284 			values[1].id = controls[id + 1 - 100].id;
1285 			values[1].gain = ((float*)value)[1];
1286 		}
1287 	} else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) {
1288 		for (uint32 i = 0; i < size / sizeof(int32); i++) {
1289 			PRINT(("SetParameterValue B_DISCRETE_PARAMETER value[%li] : %li\n", i, ((int32*)value)[i]));
1290 		}
1291 
1292 		BDiscreteParameter* discrete = (BDiscreteParameter*)parameter;
1293 		if (discrete->CountItems() <= 2) {
1294 			info.item_count = 1;
1295 			values[0].id = control_id;
1296 			values[0].enable = ((int32*)value)[0] == 1;
1297 		} else {
1298 			info.item_count = 1;
1299 			values[0].id = control_id;
1300 			values[0].mux = ((uint32*)value)[0];
1301 		}
1302 	}
1303 
1304 	if (info.item_count > 0) {
1305 		status_t status = fDevice->SetMix(&info);
1306 		if (status != B_OK)
1307 			fprintf(stderr, "Failed on DRIVER_SET_MIX\n");
1308 	}
1309 }
1310 
1311 
1312 BParameterWeb*
1313 MultiAudioNode::MakeParameterWeb()
1314 {
1315 	CALLED();
1316 	BParameterWeb* web = new BParameterWeb;
1317 
1318 	PRINT(("MixControlInfo().control_count : %li\n",
1319 		fDevice->MixControlInfo().control_count));
1320 
1321 	multi_mix_control* controls = fDevice->MixControlInfo().controls;
1322 
1323 	for (int i = 0; i < fDevice->MixControlInfo().control_count; i++) {
1324 		if (controls[i].flags & B_MULTI_MIX_GROUP && controls[i].parent == 0) {
1325 			PRINT(("NEW_GROUP\n"));
1326 			BParameterGroup* child = web->MakeGroup(
1327 				_GetControlName(controls[i]));
1328 
1329 			int32 numParameters = 0;
1330 			_ProcessGroup(child, i, numParameters);
1331 		}
1332 	}
1333 
1334 	return web;
1335 }
1336 
1337 
1338 const char*
1339 MultiAudioNode::_GetControlName(multi_mix_control& control)
1340 {
1341 	if (control.string != S_null)
1342 		return kMultiControlString[control.string];
1343 
1344 	return control.name;
1345 }
1346 
1347 
1348 void
1349 MultiAudioNode::_ProcessGroup(BParameterGroup* group, int32 index,
1350 	int32& numParameters)
1351 {
1352 	CALLED();
1353 	multi_mix_control* parent = &fDevice->MixControlInfo().controls[index];
1354 	multi_mix_control* controls = fDevice->MixControlInfo().controls;
1355 
1356 	for (int32 i = 0; i < fDevice->MixControlInfo().control_count; i++) {
1357 		if (controls[i].parent != parent->id)
1358 			continue;
1359 
1360 		const char* name = _GetControlName(controls[i]);
1361 
1362 		if (controls[i].flags & B_MULTI_MIX_GROUP) {
1363 			PRINT(("NEW_GROUP\n"));
1364 			BParameterGroup* child = group->MakeGroup(name);
1365 			child->MakeNullParameter(100 + i, B_MEDIA_RAW_AUDIO, name,
1366 				B_WEB_BUFFER_OUTPUT);
1367 
1368 			int32 num = 1;
1369 			_ProcessGroup(child, i, num);
1370 		} else if (controls[i].flags & B_MULTI_MIX_MUX) {
1371 			PRINT(("NEW_MUX\n"));
1372 			BDiscreteParameter* parameter = group->MakeDiscreteParameter(
1373 				100 + i, B_MEDIA_RAW_AUDIO, name, B_INPUT_MUX);
1374 			if (numParameters > 0) {
1375 				(group->ParameterAt(numParameters - 1))->AddOutput(
1376 					group->ParameterAt(numParameters));
1377 				numParameters++;
1378 			}
1379 			_ProcessMux(parameter, i);
1380 		} else if (controls[i].flags & B_MULTI_MIX_GAIN) {
1381 			PRINT(("NEW_GAIN\n"));
1382 			group->MakeContinuousParameter(100 + i,
1383 				B_MEDIA_RAW_AUDIO, "", B_MASTER_GAIN, "dB",
1384 				controls[i].gain.min_gain, controls[i].gain.max_gain,
1385 				controls[i].gain.granularity);
1386 
1387 			if (i + 1 < fDevice->MixControlInfo().control_count
1388 				&& controls[i + 1].master == controls[i].id
1389 				&& controls[i + 1].flags & B_MULTI_MIX_GAIN) {
1390 				group->ParameterAt(numParameters)->SetChannelCount(
1391 					group->ParameterAt(numParameters)->CountChannels() + 1);
1392 				i++;
1393 			}
1394 
1395 			PRINT(("num parameters : %ld\n", numParameters));
1396 			if (numParameters > 0) {
1397 				(group->ParameterAt(numParameters - 1))->AddOutput(
1398 					group->ParameterAt(numParameters));
1399 				numParameters++;
1400 			}
1401 		} else if (controls[i].flags & B_MULTI_MIX_ENABLE) {
1402 			PRINT(("NEW_ENABLE\n"));
1403 			if (controls[i].string == S_MUTE) {
1404 				group->MakeDiscreteParameter(100 + i,
1405 					B_MEDIA_RAW_AUDIO, name, B_MUTE);
1406 			} else {
1407 				group->MakeDiscreteParameter(100 + i,
1408 					B_MEDIA_RAW_AUDIO, name, B_ENABLE);
1409 			}
1410 			if (numParameters > 0) {
1411 				(group->ParameterAt(numParameters - 1))->AddOutput(
1412 					group->ParameterAt(numParameters));
1413 				numParameters++;
1414 			}
1415 		}
1416 	}
1417 }
1418 
1419 
1420 void
1421 MultiAudioNode::_ProcessMux(BDiscreteParameter* parameter, int32 index)
1422 {
1423 	CALLED();
1424 	multi_mix_control* parent = &fDevice->MixControlInfo().controls[index];
1425 	multi_mix_control* controls = fDevice->MixControlInfo().controls;
1426 	int32 itemIndex = 0;
1427 
1428 	for (int32 i = 0; i < fDevice->MixControlInfo().control_count; i++) {
1429 		if (controls[i].parent != parent->id)
1430 			continue;
1431 
1432 		if (controls[i].flags & B_MULTI_MIX_MUX_VALUE) {
1433 			PRINT(("NEW_MUX_VALUE\n"));
1434 			parameter->AddItem(itemIndex, _GetControlName(controls[i]));
1435 			itemIndex++;
1436 		}
1437 	}
1438 }
1439 
1440 
1441 //	#pragma mark - MultiAudioNode specific functions
1442 
1443 
1444 int32
1445 MultiAudioNode::_RunThread()
1446 {
1447 	CALLED();
1448 	multi_buffer_info bufferInfo;
1449 	bufferInfo.info_size = sizeof(multi_buffer_info);
1450 	bufferInfo._reserved_0 = 0;
1451 	bufferInfo._reserved_1 = 2;
1452 	bufferInfo.playback_buffer_cycle = 0;
1453 	bufferInfo.record_buffer_cycle = 0;
1454 
1455 	while (true) {
1456 		// TODO: why this semaphore??
1457 		if (acquire_sem_etc(fBufferFreeSem, 1, B_RELATIVE_TIMEOUT, 0)
1458 				== B_BAD_SEM_ID)
1459 			return B_OK;
1460 
1461 		// send buffer
1462 		fDevice->BufferExchange(&bufferInfo);
1463 
1464 		//PRINT(("MultiAudioNode::RunThread: buffer exchanged\n"));
1465 		//PRINT(("MultiAudioNode::RunThread: played_real_time : %Ld\n", bufferInfo.played_real_time));
1466 		//PRINT(("MultiAudioNode::RunThread: played_frames_count : %Ld\n", bufferInfo.played_frames_count));
1467 		//PRINT(("MultiAudioNode::RunThread: buffer_cycle : %li\n", bufferInfo.playback_buffer_cycle));
1468 
1469 		for (int32 i = 0; i < fInputs.CountItems(); i++) {
1470 			node_input* input = (node_input*)fInputs.ItemAt(i);
1471 
1472 			if (bufferInfo._reserved_0 == input->fChannelId
1473 				&& bufferInfo.playback_buffer_cycle >= 0
1474 				&& bufferInfo.playback_buffer_cycle
1475 						< fDevice->BufferList().return_playback_buffers
1476 				&& (input->fOldBufferInfo.playback_buffer_cycle
1477 						!= bufferInfo.playback_buffer_cycle
1478 					|| fDevice->BufferList().return_playback_buffers == 1)
1479 				&& (input->fInput.source != media_source::null
1480 					|| input->fChannelId == 0)) {
1481 				//PRINT(("playback_buffer_cycle ok input : %li %ld\n", i, bufferInfo.playback_buffer_cycle));
1482 
1483 				input->fBufferCycle = (bufferInfo.playback_buffer_cycle - 1
1484 						+ fDevice->BufferList().return_playback_buffers)
1485 					% fDevice->BufferList().return_playback_buffers;
1486 
1487 				// update the timesource
1488 				if (input->fChannelId == 0) {
1489 					//PRINT(("updating timesource\n"));
1490 					_UpdateTimeSource(bufferInfo, input->fOldBufferInfo,
1491 						*input);
1492 				}
1493 
1494 				input->fOldBufferInfo = bufferInfo;
1495 
1496 				if (input->fBuffer != NULL) {
1497 					_FillNextBuffer(*input, input->fBuffer);
1498 					input->fBuffer->Recycle();
1499 					input->fBuffer = NULL;
1500 				} else {
1501 					// put zeros in current buffer
1502 					if (input->fInput.source != media_source::null)
1503 						_WriteZeros(*input, input->fBufferCycle);
1504 					//PRINT(("MultiAudioNode::Runthread WriteZeros\n"));
1505 				}
1506 
1507 				// mark buffer free
1508 				release_sem(fBufferFreeSem);
1509 			} else {
1510 				//PRINT(("playback_buffer_cycle non ok input : %i\n", i));
1511 			}
1512 		}
1513 
1514 		PRINT(("MultiAudioNode::RunThread: recorded_real_time : %Ld\n", bufferInfo.recorded_real_time));
1515 		PRINT(("MultiAudioNode::RunThread: recorded_frames_count : %Ld\n", bufferInfo.recorded_frames_count));
1516 		PRINT(("MultiAudioNode::RunThread: record_buffer_cycle : %li\n", bufferInfo.record_buffer_cycle));
1517 
1518 		for (int32 i = 0; i < fOutputs.CountItems(); i++) {
1519 			node_output* output = (node_output*)fOutputs.ItemAt(i);
1520 
1521 			// make sure we're both started *and* connected before delivering a
1522 			// buffer
1523 			if (RunState() == BMediaEventLooper::B_STARTED
1524 				&& output->fOutput.destination != media_destination::null) {
1525 				if (bufferInfo._reserved_1 == output->fChannelId
1526 					&& bufferInfo.record_buffer_cycle >= 0
1527 					&& bufferInfo.record_buffer_cycle
1528 							< fDevice->BufferList().return_record_buffers
1529 					&& (output->fOldBufferInfo.record_buffer_cycle
1530 							!= bufferInfo.record_buffer_cycle
1531 						|| fDevice->BufferList().return_record_buffers == 1)) {
1532 					//PRINT(("record_buffer_cycle ok\n"));
1533 
1534 					// Get the next buffer of data
1535 					BBuffer* buffer = _FillNextBuffer(bufferInfo, *output);
1536 					if (buffer != NULL) {
1537 						// send the buffer downstream if and only if output is
1538 						// enabled
1539 						status_t err = B_ERROR;
1540 						if (output->fOutputEnabled) {
1541 							err = SendBuffer(buffer,
1542 								output->fOutput.destination);
1543 						}
1544 						if (err) {
1545 							buffer->Recycle();
1546 						} else {
1547 							// track how much media we've delivered so far
1548 							size_t numSamples
1549 								= output->fOutput.format.u.raw_audio.buffer_size
1550 								/ (output->fOutput.format.u.raw_audio.format
1551 									& media_raw_audio_format::B_AUDIO_SIZE_MASK);
1552 							output->fSamplesSent += numSamples;
1553 						}
1554 					}
1555 
1556 					output->fOldBufferInfo = bufferInfo;
1557 				} else {
1558 					//PRINT(("record_buffer_cycle non ok\n"));
1559 				}
1560 			}
1561 		}
1562 	}
1563 
1564 	return B_OK;
1565 }
1566 
1567 
1568 void
1569 MultiAudioNode::_WriteZeros(node_input& input, uint32 bufferCycle)
1570 {
1571 	//CALLED();
1572 	/*int32 samples = input.fInput.format.u.raw_audio.buffer_size;
1573 	if(input.fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_UCHAR) {
1574 		uint8 *sample = (uint8*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base;
1575 		for(int32 i = samples-1; i>=0; i--)
1576 			*sample++ = 128;
1577 	} else {
1578 		int32 *sample = (int32*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base;
1579 		for(int32 i = (samples / 4)-1; i>=0; i--)
1580 			*sample++ = 0;
1581 	}*/
1582 
1583 	uint32 channelCount = input.fFormat.u.raw_audio.channel_count;
1584 	uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size;
1585 	size_t stride = fDevice->BufferList().playback_buffers[bufferCycle]
1586 		[input.fChannelId].stride;
1587 
1588 	switch (input.fFormat.u.raw_audio.format) {
1589 		case media_raw_audio_format::B_AUDIO_FLOAT:
1590 			for (uint32 channel = 0; channel < channelCount; channel++) {
1591 				char* dest = _PlaybackBuffer(bufferCycle,
1592 					input.fChannelId + channel);
1593 				for (uint32 i = bufferSize; i > 0; i--) {
1594 					*(float*)dest = 0;
1595 					dest += stride;
1596 				}
1597 			}
1598 			break;
1599 
1600 		case media_raw_audio_format::B_AUDIO_INT:
1601 			for (uint32 channel = 0; channel < channelCount; channel++) {
1602 				char* dest = _PlaybackBuffer(bufferCycle,
1603 					input.fChannelId + channel);
1604 				for (uint32 i = bufferSize; i > 0; i--) {
1605 					*(int32*)dest = 0;
1606 					dest += stride;
1607 				}
1608 			}
1609 			break;
1610 
1611 		case media_raw_audio_format::B_AUDIO_SHORT:
1612 			for (uint32 channel = 0; channel < channelCount; channel++) {
1613 				char* dest = _PlaybackBuffer(bufferCycle,
1614 					input.fChannelId + channel);
1615 				for (uint32 i = bufferSize; i > 0; i--) {
1616 					*(int16*)dest = 0;
1617 					dest += stride;
1618 				}
1619 			}
1620 			break;
1621 
1622 		default:
1623 			fprintf(stderr, "ERROR in WriteZeros format not handled\n");
1624 	}
1625 }
1626 
1627 
1628 void
1629 MultiAudioNode::_FillWithZeros(node_input& input)
1630 {
1631 	CALLED();
1632 	for (int32 i = 0; i < fDevice->BufferList().return_playback_buffers; i++) {
1633 		_WriteZeros(input, i);
1634 	}
1635 }
1636 
1637 
1638 void
1639 MultiAudioNode::_FillNextBuffer(node_input& input, BBuffer* buffer)
1640 {
1641 	// TODO: simplify this, or put it into a static function to remove
1642 	// the need for checking all over again
1643 
1644 	uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size;
1645 
1646 	switch (input.fInput.format.u.raw_audio.format) {
1647 		case media_raw_audio_format::B_AUDIO_FLOAT:
1648 			switch (input.fFormat.u.raw_audio.format) {
1649 				case media_raw_audio_format::B_AUDIO_FLOAT:
1650 				{
1651 					size_t frameSize = input.fInput.format.u.raw_audio
1652 						.channel_count * sizeof(float);
1653 					size_t stride = _PlaybackStride(input.fBufferCycle,
1654 						input.fChannelId);
1655 					//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
1656 					for (uint32 channel = 0; channel
1657 							< input.fInput.format.u.raw_audio.channel_count;
1658 							channel++) {
1659 						char* dest = _PlaybackBuffer(input.fBufferCycle,
1660 							input.fChannelId + channel);
1661 						char* src = (char*)buffer->Data()
1662 							+ channel * sizeof(float);
1663 
1664 						for (uint32 i = bufferSize; i > 0; i--) {
1665 							*(float *)dest = *(float *)src;
1666 							dest += stride;
1667 							src += frameSize;
1668 						}
1669 					}
1670 					break;
1671 				}
1672 
1673 				case media_raw_audio_format::B_AUDIO_SHORT:
1674 					if (input.fInput.format.u.raw_audio.channel_count == 2) {
1675 						int16* dest1 = (int16*)_PlaybackBuffer(
1676 							input.fBufferCycle, input.fChannelId);
1677 						int16* dest2 = (int16*)_PlaybackBuffer(
1678 							input.fBufferCycle, input.fChannelId + 1);
1679 						float* src = (float*)buffer->Data();
1680 						if (_PlaybackStride(input.fBufferCycle,
1681 									input.fChannelId) == sizeof(int16)
1682 							&& _PlaybackStride(input.fBufferCycle,
1683 									input.fChannelId + 1) == sizeof(int16)) {
1684 							//PRINT(("FillNextBuffer : 2 channels strides 2\n"));
1685 							for (uint32 i = bufferSize; i > 0; i--) {
1686 								*dest1++ = int16(32767 * *src++);
1687 								*dest2++ = int16(32767 * *src++);
1688 							}
1689 						} else if (_PlaybackStride(input.fBufferCycle,
1690 									input.fChannelId) == 2 * sizeof(int16)
1691 							&& _PlaybackStride(input.fBufferCycle,
1692 									input.fChannelId + 1) == 2 * sizeof(int16)
1693 							&& dest1 + 1 == dest2) {
1694 							//PRINT(("FillNextBuffer : 2 channels strides 4\n"));
1695 							for (uint32 i = 2 * bufferSize; i > 0; i--)
1696 								*dest1++ = int16(32767 * *src++);
1697 						} else {
1698 							//PRINT(("FillNextBuffer : 2 channels strides != 2\n"));
1699 							size_t stride1 = _PlaybackStride(input.fBufferCycle,
1700 								input.fChannelId) / sizeof(int16);
1701 							size_t stride2 = _PlaybackStride(input.fBufferCycle,
1702 								input.fChannelId + 1) / sizeof(int16);
1703 							for (uint32 i = bufferSize; i > 0; i--) {
1704 								*dest1 = int16(32767 * *src++);
1705 								*dest2 = int16(32767 * *src++);
1706 								dest1 += stride1;
1707 								dest2 += stride2;
1708 							}
1709 						}
1710 					} else {
1711 						size_t frameSize = input.fInput.format.u
1712 							.raw_audio.channel_count * sizeof(int16);
1713 						size_t stride = _PlaybackStride(input.fBufferCycle,
1714 							input.fChannelId);
1715 						//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
1716 						for (uint32 channel = 0; channel <
1717 								input.fInput.format.u.raw_audio.channel_count;
1718 								channel++) {
1719 							char* dest = _PlaybackBuffer(input.fBufferCycle,
1720 								input.fChannelId + channel);
1721 							char* src = (char*)buffer->Data()
1722 								+ channel * sizeof(int16);
1723 
1724 							for (uint32 i = bufferSize; i > 0; i--) {
1725 								*(int16*)dest = int16(32767 * *(float*)src);
1726 								dest += stride;
1727 								src += frameSize;
1728 							}
1729 						}
1730 					}
1731 					break;
1732 
1733 				case media_raw_audio_format::B_AUDIO_INT:
1734 				default:
1735 					break;
1736 			}
1737 			break;
1738 
1739 		case media_raw_audio_format::B_AUDIO_INT:
1740 			switch (input.fFormat.u.raw_audio.format) {
1741 				case media_raw_audio_format::B_AUDIO_INT:
1742 				{
1743 					size_t frameSize = input.fInput.format.u.raw_audio
1744 						.channel_count * sizeof(int32);
1745 					size_t stride = _PlaybackStride(input.fBufferCycle,
1746 						input.fChannelId);
1747 					//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
1748 					for (uint32 channel = 0; channel
1749 							< input.fInput.format.u.raw_audio.channel_count;
1750 							channel++) {
1751 						char* dest = _PlaybackBuffer(input.fBufferCycle,
1752 							input.fChannelId + channel);
1753 						char* src = (char*)buffer->Data()
1754 							+ channel * sizeof(int32);
1755 
1756 						for (uint32 i = bufferSize; i > 0; i--) {
1757 							*(int32 *)dest = *(int32 *)src;
1758 							dest += stride;
1759 							src += frameSize;
1760 						}
1761 					}
1762 					break;
1763 				}
1764 				case media_raw_audio_format::B_AUDIO_SHORT:
1765 				case media_raw_audio_format::B_AUDIO_FLOAT:
1766 				default:
1767 					break;
1768 			}
1769 			break;
1770 
1771 		case media_raw_audio_format::B_AUDIO_SHORT:
1772 			switch (input.fFormat.u.raw_audio.format) {
1773 				case media_raw_audio_format::B_AUDIO_SHORT:
1774 					if (input.fInput.format.u.raw_audio.channel_count == 2) {
1775 						int16* dest1 = (int16*)_PlaybackBuffer(
1776 							input.fBufferCycle, input.fChannelId);
1777 						int16* dest2 = (int16*)_PlaybackBuffer(
1778 							input.fBufferCycle, input.fChannelId + 1);
1779 						int16* src = (int16*)buffer->Data();
1780 						if (_PlaybackStride(input.fBufferCycle,
1781 								input.fChannelId) == sizeof(int16)
1782 							&& _PlaybackStride(input.fBufferCycle,
1783 								input.fChannelId + 1) == sizeof(int16)) {
1784 							//PRINT(("FillNextBuffer : 2 channels strides 2\n"));
1785 							for (uint32 i = bufferSize; i > 0; i--) {
1786 								*dest1++ = *src++;
1787 								*dest2++ = *src++;
1788 							}
1789 						} else if (_PlaybackStride(input.fBufferCycle,
1790 								input.fChannelId) == 2 * sizeof(int16)
1791 							&& _PlaybackStride(input.fBufferCycle,
1792 								input.fChannelId + 1) == 2 * sizeof(int16)
1793 							&& dest1 + 1 == dest2) {
1794 								//PRINT(("FillNextBuffer : 2 channels strides 4\n"));
1795 								memcpy(dest1, src,
1796 									bufferSize * 2 * sizeof(int16));
1797 							} else {
1798 								//PRINT(("FillNextBuffer : 2 channels strides != 2\n"));
1799 								size_t stride1 = _PlaybackStride(
1800 									input.fBufferCycle, input.fChannelId) / 2;
1801 								size_t stride2 = _PlaybackStride(
1802 									input.fBufferCycle, input.fChannelId + 1)
1803 									/ 2;
1804 
1805 								for (uint32 i = bufferSize; i > 0; i--) {
1806 									*dest1 = *src++;
1807 									*dest2 = *src++;
1808 									dest1 += stride1;
1809 									dest2 += stride2;
1810 								}
1811 							}
1812 					} else {
1813 						size_t frameSize = input.fInput.format.u
1814 							.raw_audio.channel_count * sizeof(int16);
1815 						size_t stride = _PlaybackStride(input.fBufferCycle,
1816 							input.fChannelId);
1817 						//PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size));
1818 						for (uint32 channel = 0; channel
1819 								< input.fInput.format.u.raw_audio.channel_count;
1820 								channel++) {
1821 							char* dest = _PlaybackBuffer(input.fBufferCycle,
1822 								input.fChannelId + channel);
1823 							char* src = (char*)buffer->Data()
1824 								+ channel * sizeof(int16);
1825 
1826 							for (uint32 i = bufferSize; i > 0; i--) {
1827 								*(int16*)dest = *(int16*)src;
1828 								dest += stride;
1829 								src += frameSize;
1830 							}
1831 						}
1832 					}
1833 					break;
1834 
1835 				case media_raw_audio_format::B_AUDIO_FLOAT:
1836 				case media_raw_audio_format::B_AUDIO_INT:
1837 				default:
1838 					break;
1839 			}
1840 			break;
1841 
1842 		case media_raw_audio_format::B_AUDIO_UCHAR:
1843 		default:
1844 			break;
1845 	}
1846 }
1847 
1848 
1849 status_t
1850 MultiAudioNode::_StartThread()
1851 {
1852 	CALLED();
1853 	// the thread is already started ?
1854 	if (fThread > B_OK)
1855 		return B_OK;
1856 
1857 	// allocate buffer free semaphore
1858 	fBufferFreeSem = create_sem(
1859 		fDevice->BufferList().return_playback_buffers - 1,
1860 		"multi_audio out buffer free");
1861 	if (fBufferFreeSem < B_OK)
1862 		return fBufferFreeSem;
1863 
1864 	PublishTime(-50, 0, 0);
1865 
1866 	fThread = spawn_thread(_run_thread_, "multi_audio audio output",
1867 		B_REAL_TIME_PRIORITY, this);
1868 	if (fThread < B_OK) {
1869 		delete_sem(fBufferFreeSem);
1870 		return fThread;
1871 	}
1872 
1873 	resume_thread(fThread);
1874 	return B_OK;
1875 }
1876 
1877 
1878 status_t
1879 MultiAudioNode::_StopThread()
1880 {
1881 	CALLED();
1882 	delete_sem(fBufferFreeSem);
1883 
1884 	wait_for_thread(fThread, &fThread);
1885 	return B_OK;
1886 }
1887 
1888 
1889 void
1890 MultiAudioNode::_AllocateBuffers(node_output &channel)
1891 {
1892 	CALLED();
1893 
1894 	// allocate enough buffers to span our downstream latency, plus one
1895 	size_t size = channel.fOutput.format.u.raw_audio.buffer_size;
1896 	int32 count = int32(fLatency / BufferDuration() + 1 + 1);
1897 
1898 	PRINT(("\tlatency = %Ld, buffer duration = %Ld\n", fLatency, BufferDuration()));
1899 	PRINT(("\tcreating group of %ld buffers, size = %lu\n", count, size));
1900 	channel.fBufferGroup = new BBufferGroup(size, count);
1901 }
1902 
1903 
1904 void
1905 MultiAudioNode::_UpdateTimeSource(multi_buffer_info& info,
1906 	multi_buffer_info& oldInfo, node_input& input)
1907 {
1908 	//CALLED();
1909 	if (!fTimeSourceStarted || oldInfo.played_real_time == 0)
1910 		return;
1911 
1912 	bigtime_t performanceTime = (bigtime_t)(info.played_frames_count /
1913 		input.fInput.format.u.raw_audio.frame_rate * 1000000LL);
1914 	bigtime_t realTime = info.played_real_time;
1915 	float drift = ((info.played_frames_count - oldInfo.played_frames_count)
1916 		/ input.fInput.format.u.raw_audio.frame_rate * 1000000LL)
1917 		/ (info.played_real_time - oldInfo.played_real_time);
1918 
1919 	PublishTime(performanceTime, realTime, drift);
1920 	//PRINT(("_UpdateTimeSource() perf_time : %lli, real_time : %lli, drift : %f\n", performanceTime, realTime, drift));
1921 }
1922 
1923 
1924 BBuffer*
1925 MultiAudioNode::_FillNextBuffer(multi_buffer_info &info, node_output &channel)
1926 {
1927 	//CALLED();
1928 	// get a buffer from our buffer group
1929 	//PRINT(("buffer size : %i, buffer duration : %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration()));
1930 	//PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle));
1931 	//PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time));
1932 	//PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count));
1933 	if (!channel.fBufferGroup)
1934 		return NULL;
1935 
1936 	BBuffer* buffer = channel.fBufferGroup->RequestBuffer(
1937 		channel.fOutput.format.u.raw_audio.buffer_size, BufferDuration());
1938 	if (buffer == NULL) {
1939 		// If we fail to get a buffer (for example, if the request times out),
1940 		// we skip this buffer and go on to the next, to avoid locking up the
1941 		// control thread.
1942 		return NULL;
1943 	}
1944 
1945 	if (fDevice == NULL)
1946 		fprintf(stderr, "fDevice NULL\n");
1947 	if (buffer->Header() == NULL)
1948 		fprintf(stderr, "buffer->Header() NULL\n");
1949 	if (TimeSource() == NULL)
1950 		fprintf(stderr, "TimeSource() NULL\n");
1951 
1952 	// now fill it with data, continuing where the last buffer left off
1953 	memcpy(buffer->Data(),
1954 		fDevice->BufferList().record_buffers[info.record_buffer_cycle]
1955 			[channel.fChannelId - fDevice->Description().output_channel_count].base,
1956 		channel.fOutput.format.u.raw_audio.buffer_size);
1957 
1958 	// fill in the buffer header
1959 	media_header* header = buffer->Header();
1960 	header->type = B_MEDIA_RAW_AUDIO;
1961 	header->size_used = channel.fOutput.format.u.raw_audio.buffer_size;
1962 	header->time_source = TimeSource()->ID();
1963 	header->start_time = PerformanceTimeFor(info.recorded_real_time);
1964 
1965 	return buffer;
1966 }
1967 
1968 
1969 status_t
1970 MultiAudioNode::GetConfigurationFor(BMessage* message)
1971 {
1972 	CALLED();
1973 
1974 	BParameter *parameter = NULL;
1975 	void *buffer;
1976 	size_t bufferSize = 128;
1977 	bigtime_t lastChange;
1978 	status_t err;
1979 
1980 	if (message == NULL)
1981 		return B_BAD_VALUE;
1982 
1983 	buffer = malloc(bufferSize);
1984 	if (buffer == NULL)
1985 		return B_NO_MEMORY;
1986 
1987 	for (int32 i = 0; i < fWeb->CountParameters(); i++) {
1988 		parameter = fWeb->ParameterAt(i);
1989 		if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER
1990 			&& parameter->Type() != BParameter::B_DISCRETE_PARAMETER)
1991 			continue;
1992 
1993 		PRINT(("getting parameter %li\n", parameter->ID()));
1994 		size_t size = bufferSize;
1995 		while ((err = GetParameterValue(parameter->ID(), &lastChange, buffer,
1996 				&size)) == B_NO_MEMORY && bufferSize < 128 * 1024) {
1997 			bufferSize += 128;
1998 			free(buffer);
1999 			buffer = malloc(bufferSize);
2000 			if (buffer == NULL)
2001 				return B_NO_MEMORY;
2002 		}
2003 
2004 		if (err == B_OK && size > 0) {
2005 			message->AddInt32("parameterID", parameter->ID());
2006 			message->AddData("parameterData", B_RAW_TYPE, buffer, size, false);
2007 		} else {
2008 			PRINT(("parameter err : %s\n", strerror(err)));
2009 		}
2010 	}
2011 
2012 	free(buffer);
2013 	PRINT_OBJECT(*message);
2014 	return B_OK;
2015 }
2016 
2017 
2018 node_output*
2019 MultiAudioNode::_FindOutput(media_source source)
2020 {
2021 	node_output* channel = NULL;
2022 
2023 	for (int32 i = 0; i < fOutputs.CountItems(); i++) {
2024 		channel = (node_output*)fOutputs.ItemAt(i);
2025 		if (source == channel->fOutput.source)
2026 			break;
2027 	}
2028 
2029 	if (source != channel->fOutput.source)
2030 		return NULL;
2031 
2032 	return channel;
2033 }
2034 
2035 
2036 node_input*
2037 MultiAudioNode::_FindInput(media_destination dest)
2038 {
2039 	node_input* channel = NULL;
2040 
2041 	for (int32 i = 0; i < fInputs.CountItems(); i++) {
2042 		channel = (node_input*)fInputs.ItemAt(i);
2043 		if (dest == channel->fInput.destination)
2044 			break;
2045 	}
2046 
2047 	if (dest != channel->fInput.destination)
2048 		return NULL;
2049 
2050 	return channel;
2051 }
2052 
2053 
2054 node_input*
2055 MultiAudioNode::_FindInput(int32 destinationId)
2056 {
2057 	node_input* channel = NULL;
2058 
2059 	for (int32 i = 0; i < fInputs.CountItems(); i++) {
2060 		channel = (node_input*)fInputs.ItemAt(i);
2061 		if (destinationId == channel->fInput.destination.id)
2062 			break;
2063 	}
2064 
2065 	if (destinationId != channel->fInput.destination.id)
2066 		return NULL;
2067 
2068 	return channel;
2069 }
2070 
2071 
2072 /*static*/ status_t
2073 MultiAudioNode::_run_thread_(void* data)
2074 {
2075 	CALLED();
2076 	return static_cast<MultiAudioNode*>(data)->_RunThread();
2077 }
2078 
2079 
2080 void
2081 MultiAudioNode::GetFlavor(flavor_info* info, int32 id)
2082 {
2083 	CALLED();
2084 	if (info == NULL)
2085 		return;
2086 
2087 	info->flavor_flags = 0;
2088 	info->possible_count = 1;	// one flavor at a time
2089 	info->in_format_count = 0; // no inputs
2090 	info->in_formats = 0;
2091 	info->out_format_count = 0; // no outputs
2092 	info->out_formats = 0;
2093 	info->internal_id = id;
2094 
2095 	info->name = "MultiAudioNode Node";
2096 	info->info = "The MultiAudioNode node outputs to multi_audio drivers.";
2097 	info->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE
2098 		| B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE;
2099 	info->in_format_count = 1; // 1 input
2100 	media_format* inFormats = new media_format[info->in_format_count];
2101 	GetFormat(&inFormats[0]);
2102 	info->in_formats = inFormats;
2103 
2104 	info->out_format_count = 1; // 1 output
2105 	media_format* outFormats = new media_format[info->out_format_count];
2106 	GetFormat(&outFormats[0]);
2107 	info->out_formats = outFormats;
2108 }
2109 
2110 
2111 void
2112 MultiAudioNode::GetFormat(media_format* format)
2113 {
2114 	CALLED();
2115 	if (format == NULL)
2116 		return;
2117 
2118 	format->type = B_MEDIA_RAW_AUDIO;
2119 	format->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
2120 	format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
2121 	format->u.raw_audio = media_raw_audio_format::wildcard;
2122 }
2123 
2124