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.
39class node_input {
40public:
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.
57class node_output {
58public:
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
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 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
140node_input::~node_input()
141{
142	CALLED();
143}
144
145
146//	#pragma mark -
147
148
149node_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
163node_output::~node_output()
164{
165	CALLED();
166}
167
168
169//	#pragma mark -
170
171
172MultiAudioNode::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
259MultiAudioNode::~MultiAudioNode()
260{
261	CALLED();
262	fAddOn->GetConfigurationFor(this, NULL);
263
264	_StopOutputThread();
265	BMediaEventLooper::Quit();
266}
267
268
269status_t
270MultiAudioNode::InitCheck() const
271{
272	CALLED();
273	return fInitStatus;
274}
275
276
277void
278MultiAudioNode::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
314void
315MultiAudioNode::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
331BMediaAddOn*
332MultiAudioNode::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
343void
344MultiAudioNode::Preroll()
345{
346	CALLED();
347	// TODO: Performance opportunity
348	BMediaNode::Preroll();
349}
350
351
352status_t
353MultiAudioNode::HandleMessage(int32 message, const void* data, size_t size)
354{
355	CALLED();
356	return B_ERROR;
357}
358
359
360void
361MultiAudioNode::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
518status_t
519MultiAudioNode::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
550void
551MultiAudioNode::SetTimeSource(BTimeSource* timeSource)
552{
553	CALLED();
554}
555
556
557//	#pragma mark - BBufferConsumer
558
559
560status_t
561MultiAudioNode::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
583status_t
584MultiAudioNode::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
602void
603MultiAudioNode::DisposeInputCookie(int32 cookie)
604{
605	CALLED();
606	// nothing to do since our cookies are just integers
607}
608
609
610void
611MultiAudioNode::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
651void
652MultiAudioNode::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
668status_t
669MultiAudioNode::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
686status_t
687MultiAudioNode::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
722void
723MultiAudioNode::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
741status_t
742MultiAudioNode::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
761status_t
762MultiAudioNode::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
775status_t
776MultiAudioNode::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
805status_t
806MultiAudioNode::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
837status_t
838MultiAudioNode::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
849status_t
850MultiAudioNode::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
864status_t
865MultiAudioNode::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
873status_t
874MultiAudioNode::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
921status_t
922MultiAudioNode::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
960void
961MultiAudioNode::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
1021void
1022MultiAudioNode::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
1051void
1052MultiAudioNode::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
1093void
1094MultiAudioNode::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
1110void
1111MultiAudioNode::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
1124void
1125MultiAudioNode::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
1159status_t
1160MultiAudioNode::_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
1206status_t
1207MultiAudioNode::_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
1226status_t
1227MultiAudioNode::_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
1237status_t
1238MultiAudioNode::_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
1249status_t
1250MultiAudioNode::_HandleWarp(const media_timed_event* event, bigtime_t lateness,
1251	bool realTimeEvent)
1252{
1253	CALLED();
1254	return B_OK;
1255}
1256
1257
1258status_t
1259MultiAudioNode::_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
1272status_t
1273MultiAudioNode::_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
1284void
1285MultiAudioNode::SetRunMode(run_mode mode)
1286{
1287	CALLED();
1288	PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode));
1289	//BTimeSource::SetRunMode(mode);
1290}
1291
1292
1293status_t
1294MultiAudioNode::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
1342status_t
1343MultiAudioNode::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
1441void
1442MultiAudioNode::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
1611BParameterWeb*
1612MultiAudioNode::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
1653const char*
1654MultiAudioNode::_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
1663void
1664MultiAudioNode::_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
1735void
1736MultiAudioNode::_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
1756void
1757MultiAudioNode::_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
1779int32
1780MultiAudioNode::_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
1905void
1906MultiAudioNode::_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
1988void
1989MultiAudioNode::_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
1997void
1998MultiAudioNode::_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
2034status_t
2035MultiAudioNode::_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
2054status_t
2055MultiAudioNode::_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
2066void
2067MultiAudioNode::_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
2083void
2084MultiAudioNode::_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
2097BBuffer*
2098MultiAudioNode::_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
2161status_t
2162MultiAudioNode::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
2206node_output*
2207MultiAudioNode::_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
2224node_input*
2225MultiAudioNode::_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
2242node_input*
2243MultiAudioNode::_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
2261MultiAudioNode::_OutputThreadEntry(void* data)
2262{
2263	CALLED();
2264	return static_cast<MultiAudioNode*>(data)->_OutputThread();
2265}
2266
2267
2268status_t
2269MultiAudioNode::_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
2323status_t
2324MultiAudioNode::_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
2377void
2378MultiAudioNode::_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