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