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