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