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