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