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