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