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