1bf7ab50dSStephan Aßmus/*
2bf7ab50dSStephan Aßmus * Copyright 2002 David Shipman,
3bf7ab50dSStephan Aßmus * Copyright 2003-2007 Marcus Overhagen
4ba5e652dSAdrien Destugues * Copyright 2007-2011 Haiku Inc. All rights reserved.
5e7cdf7f3SAxel Dörfler *
6bf7ab50dSStephan Aßmus * Distributed under the terms of the MIT License.
77ee2c804Sbeveloper */
8e7cdf7f3SAxel Dörfler
9a9cf57cfSAxel Dörfler
10be2a2489Sbeveloper#include "AudioMixer.h"
11a9cf57cfSAxel Dörfler
12a9cf57cfSAxel Dörfler#include <math.h>
13a9cf57cfSAxel Dörfler#include <stdio.h>
14a9cf57cfSAxel Dörfler#include <stdlib.h>
15a9cf57cfSAxel Dörfler#include <string.h>
1600cffa1cSbeveloper
17bf7ab50dSStephan Aßmus#include <Buffer.h>
186fd240c2SAdrien Destugues#include <Catalog.h>
19bf7ab50dSStephan Aßmus#include <FindDirectory.h>
206d2f2ec1SDario Casalinuovo#include <MediaDefs.h>
21bf7ab50dSStephan Aßmus#include <MediaRoster.h>
22bf7ab50dSStephan Aßmus#include <ParameterWeb.h>
23bf7ab50dSStephan Aßmus#include <Path.h>
24bf7ab50dSStephan Aßmus#include <RealtimeAlloc.h>
25bf7ab50dSStephan Aßmus#include <TimeSource.h>
26bf7ab50dSStephan Aßmus
27a9cf57cfSAxel Dörfler#include "MixerCore.h"
28a9cf57cfSAxel Dörfler#include "MixerInput.h"
29a9cf57cfSAxel Dörfler#include "MixerOutput.h"
30a9cf57cfSAxel Dörfler#include "MixerUtils.h"
31a9cf57cfSAxel Dörfler
32a9cf57cfSAxel Dörfler
33546208a5SOliver Tappe#undef B_TRANSLATION_CONTEXT
34546208a5SOliver Tappe#define B_TRANSLATION_CONTEXT "AudioMixer"
356fd240c2SAdrien Destugues
366fd240c2SAdrien Destugues
374224efc3Sbeveloper// the range of the gain sliders (in dB)
384224efc3Sbeveloper#define DB_MAX	18.0
394224efc3Sbeveloper#define DB_MIN	-60.0
404224efc3Sbeveloper// when using non linear sliders, we use a power function with
414224efc3Sbeveloper#define DB_EXPONENT_POSITIVE 1.4	// for dB values > 0
424224efc3Sbeveloper#define DB_EXPONENT_NEGATIVE 1.8	// for dB values < 0
434224efc3Sbeveloper
44e6c7c99fSbeveloper#define USE_MEDIA_FORMAT_WORKAROUND 1
45e6c7c99fSbeveloper
46e7cdf7f3SAxel Dörfler#define DB_TO_GAIN(db)			dB_to_Gain((db))
47e7cdf7f3SAxel Dörfler#define GAIN_TO_DB(gain)		Gain_to_dB((gain))
48e7cdf7f3SAxel Dörfler#define PERCENT_TO_GAIN(pct)	((pct) / 100.0)
49e7cdf7f3SAxel Dörfler#define GAIN_TO_PERCENT(gain)	((gain)  * 100.0)
50e7cdf7f3SAxel Dörfler
51e7cdf7f3SAxel Dörfler// the id is encoded with 16 bits
52e7cdf7f3SAxel Dörfler// then chan and src (or dst) are encoded with 6 bits
53e7cdf7f3SAxel Dörfler// the unique number with 4 bits
54e7cdf7f3SAxel Dörfler// the PARAM_ETC etc is encoded with 26 bits
55e7cdf7f3SAxel Dörfler#define PARAM_SRC_ENABLE(id, chan, src)		(((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x1)
56e7cdf7f3SAxel Dörfler#define PARAM_SRC_GAIN(id, chan, src)		(((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x2)
57e7cdf7f3SAxel Dörfler#define PARAM_DST_ENABLE(id, chan, dst)		(((id) << 16) | ((chan) << 10) | ((dst) << 4) | 0x3)
58e7cdf7f3SAxel Dörfler#define PARAM_ETC(etc)						(((etc) << 16) | 0x4)
59e7cdf7f3SAxel Dörfler#define PARAM_SRC_STR(id, chan)				(((id) << 16) | ((chan) << 10) | 0x5)
60e7cdf7f3SAxel Dörfler#define PARAM_DST_STR(id, chan)				(((id) << 16) | ((chan) << 10) | 0x6)
61e7cdf7f3SAxel Dörfler#define PARAM_MUTE(id)						(((id) << 16) | 0x7)
62e7cdf7f3SAxel Dörfler#define PARAM_GAIN(id)						(((id) << 16) | 0x8)
63e7cdf7f3SAxel Dörfler#define PARAM_BALANCE(id)					(((id) << 16) | 0x9)
64e7cdf7f3SAxel Dörfler#define PARAM_STR1(id)						(((id) << 16) | ((1) << 10) | 0xa)
65e7cdf7f3SAxel Dörfler#define PARAM_STR2(id)						(((id) << 16) | ((2) << 10) | 0xa)
66e7cdf7f3SAxel Dörfler#define PARAM_STR3(id)						(((id) << 16) | ((3) << 10) | 0xa)
67e7cdf7f3SAxel Dörfler#define PARAM_STR4(id)						(((id) << 16) | ((4) << 10) | 0xa)
68e7cdf7f3SAxel Dörfler#define PARAM_STR5(id)						(((id) << 16) | ((5) << 10) | 0xa)
69e7cdf7f3SAxel Dörfler#define PARAM_STR6(id)						(((id) << 16) | ((6) << 10) | 0xa)
70e7cdf7f3SAxel Dörfler#define PARAM_STR7(id)						(((id) << 16) | ((7) << 10) | 0xa)
71e7cdf7f3SAxel Dörfler
72e7cdf7f3SAxel Dörfler#define PARAM(id)							((id) >> 16)
73e7cdf7f3SAxel Dörfler#define ETC(id)								((id) >> 16)
74e7cdf7f3SAxel Dörfler#define PARAM_CHAN(id)						(((id) >> 10) & 0x3f)
75e7cdf7f3SAxel Dörfler#define PARAM_SRC(id)						(((id) >> 4) & 0x3f)
76e7cdf7f3SAxel Dörfler#define PARAM_DST(id)						(((id) >> 4) & 0x3f)
77e7cdf7f3SAxel Dörfler#define PARAM_IS_SRC_ENABLE(id)				(((id) & 0xf) == 0x1)
78e7cdf7f3SAxel Dörfler#define PARAM_IS_SRC_GAIN(id)				(((id) & 0xf) == 0x2)
79e7cdf7f3SAxel Dörfler#define PARAM_IS_DST_ENABLE(id)				(((id) & 0xf) == 0x3)
80e7cdf7f3SAxel Dörfler#define PARAM_IS_ETC(id)					(((id) & 0xf) == 0x4)
81e7cdf7f3SAxel Dörfler#define PARAM_IS_MUTE(id)					(((id) & 0xf) == 0x7)
82e7cdf7f3SAxel Dörfler#define PARAM_IS_GAIN(id)					(((id) & 0xf) == 0x8)
83e7cdf7f3SAxel Dörfler#define PARAM_IS_BALANCE(id)				(((id) & 0xf) == 0x9)
84e7cdf7f3SAxel Dörfler
85e6c7c99fSbeveloper#if USE_MEDIA_FORMAT_WORKAROUND
86e7cdf7f3SAxel Dörflerstatic void
87bf7ab50dSStephan Aßmusmulti_audio_format_specialize(media_multi_audio_format *format,
88e7cdf7f3SAxel Dörfler	const media_multi_audio_format *other);
89e6c7c99fSbeveloper#endif
90e6c7c99fSbeveloper
91c3b1c2a6Sbeveloper#define FORMAT_USER_DATA_TYPE 		0x7294a8f3
92c3b1c2a6Sbeveloper#define FORMAT_USER_DATA_MAGIC_1	0xc84173bd
93c3b1c2a6Sbeveloper#define FORMAT_USER_DATA_MAGIC_2	0x4af62b7d
94c3b1c2a6Sbeveloper
95e7cdf7f3SAxel Dörfler
96d0085d25SAxel Dörflerconst static bigtime_t kMaxLatency = 150000;
97d0085d25SAxel Dörfler	// 150 ms is the maximum latency we publish
98d0085d25SAxel Dörfler
992d4ce064SAxel Dörflerconst bigtime_t kMinMixingTime = 3500;
1002d4ce064SAxel Dörflerconst bigtime_t kMaxJitter = 1500;
1012d4ce064SAxel Dörfler
102d0085d25SAxel Dörfler
1031165d5e1SbeveloperAudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
104a9cf57cfSAxel Dörfler	:
105a9cf57cfSAxel Dörfler	BMediaNode("Audio Mixer"),
106e7cdf7f3SAxel Dörfler	BBufferConsumer(B_MEDIA_RAW_AUDIO),
107e7cdf7f3SAxel Dörfler	BBufferProducer(B_MEDIA_RAW_AUDIO),
108e7cdf7f3SAxel Dörfler	BControllable(),
109e7cdf7f3SAxel Dörfler	BMediaEventLooper(),
110e7cdf7f3SAxel Dörfler	fAddOn(addOn),
111e7cdf7f3SAxel Dörfler	fCore(new MixerCore(this)),
1128c19f07fSDario Casalinuovo	fWeb(NULL),
1138c19f07fSDario Casalinuovo	fBufferGroup(NULL),
114e7cdf7f3SAxel Dörfler	fDownstreamLatency(1),
115e7cdf7f3SAxel Dörfler	fInternalLatency(1),
116b289aaf6SAxel Dörfler	fDisableStop(false),
117ba5e652dSAdrien Destugues	fLastLateNotification(0),
118ba5e652dSAdrien Destugues	fLastLateness(0)
11900cffa1cSbeveloper{
12000cffa1cSbeveloper	BMediaNode::AddNodeKind(B_SYSTEM_MIXER);
12100cffa1cSbeveloper
122be2a2489Sbeveloper	// this is the default format used for all wildcard format SpecializeTo()s
123be2a2489Sbeveloper	fDefaultFormat.type = B_MEDIA_RAW_AUDIO;
124be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.frame_rate = 96000;
125be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.channel_count = 2;
126be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
127be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
128be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.buffer_size = 4096;
129be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.channel_mask = 0;
130be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.valid_bits = 0;
131be2a2489Sbeveloper	fDefaultFormat.u.raw_audio.matrix_mask = 0;
132e7cdf7f3SAxel Dörfler
1331165d5e1Sbeveloper	if (isSystemMixer) {
1341165d5e1Sbeveloper		// to get persistent settings, assign a settings file
1351165d5e1Sbeveloper		BPath path;
1361165d5e1Sbeveloper		if (B_OK != find_directory (B_USER_SETTINGS_DIRECTORY, &path))
1371165d5e1Sbeveloper			path.SetTo("/boot/home/config/settings/");
1381165d5e1Sbeveloper		path.Append("System Audio Mixer");
1391165d5e1Sbeveloper		fCore->Settings()->SetSettingsFile(path.Path());
140e7cdf7f3SAxel Dörfler
1411165d5e1Sbeveloper		// disable stop on the auto started (system) mixer
1421165d5e1Sbeveloper		DisableNodeStop();
1431165d5e1Sbeveloper	}
144e7cdf7f3SAxel Dörfler
14526bf7cd3Sbeveloper	ApplySettings();
14600cffa1cSbeveloper}
14700cffa1cSbeveloper
148e7cdf7f3SAxel Dörfler
14900cffa1cSbeveloperAudioMixer::~AudioMixer()
15000cffa1cSbeveloper{
15100cffa1cSbeveloper	BMediaEventLooper::Quit();
152e7cdf7f3SAxel Dörfler	SetParameterWeb(NULL);
15300cffa1cSbeveloper
15416cecbdeSbeveloper	// stop the mixer
15516cecbdeSbeveloper	fCore->Lock();
15616cecbdeSbeveloper	fCore->Stop();
15716cecbdeSbeveloper	fCore->Unlock();
15816cecbdeSbeveloper
15916cecbdeSbeveloper	// disconnect all nodes from the mixer
16016cecbdeSbeveloper	// XXX todo
161e7cdf7f3SAxel Dörfler
1627ee2c804Sbeveloper	delete fCore;
1637ee2c804Sbeveloper	delete fBufferGroup;
164e7cdf7f3SAxel Dörfler
1657ee2c804Sbeveloper	DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0);
16600cffa1cSbeveloper}
16700cffa1cSbeveloper
168e7cdf7f3SAxel Dörfler
16926bf7cd3Sbevelopervoid
17026bf7cd3SbeveloperAudioMixer::ApplySettings()
17126bf7cd3Sbeveloper{
17226bf7cd3Sbeveloper	fCore->Lock();
17326bf7cd3Sbeveloper	fCore->SetOutputAttenuation(fCore->Settings()->AttenuateOutput() ? 0.708 : 1.0);
17426bf7cd3Sbeveloper	fCore->Unlock();
17526bf7cd3Sbeveloper}
17626bf7cd3Sbeveloper
177e7cdf7f3SAxel Dörfler
178545124e6Sbevelopervoid
179545124e6SbeveloperAudioMixer::DisableNodeStop()
180545124e6Sbeveloper{
181545124e6Sbeveloper	fDisableStop = true;
182545124e6Sbeveloper}
183545124e6Sbeveloper
184be2a2489Sbeveloper
185e7cdf7f3SAxel Dörfler//	#pragma mark - BMediaNode methods
186e7cdf7f3SAxel Dörfler
187e7cdf7f3SAxel Dörfler
188e7cdf7f3SAxel Dörflervoid
189e7cdf7f3SAxel DörflerAudioMixer::Stop(bigtime_t performance_time, bool immediate)
190545124e6Sbeveloper{
191545124e6Sbeveloper	if (fDisableStop) {
192a2ca4723Sbeveloper		TRACE("AudioMixer STOP is disabled\n");
193545124e6Sbeveloper		return;
194545124e6Sbeveloper	} else {
195545124e6Sbeveloper		BMediaEventLooper::Stop(performance_time, immediate);
196545124e6Sbeveloper	}
197545124e6Sbeveloper}
198545124e6Sbeveloper
199e7cdf7f3SAxel Dörfler
200e7cdf7f3SAxel DörflerBMediaAddOn*
20100cffa1cSbeveloperAudioMixer::AddOn(int32 *internal_id) const
20200cffa1cSbeveloper{
2037ee2c804Sbeveloper	*internal_id = 0;
2047ee2c804Sbeveloper	return fAddOn;
20500cffa1cSbeveloper}
20600cffa1cSbeveloper
207e7cdf7f3SAxel Dörfler
208e7cdf7f3SAxel Dörfler//	#pragma mark - BBufferConsumer methods
209e7cdf7f3SAxel Dörfler
21000cffa1cSbeveloper
21100cffa1cSbeveloperstatus_t
2127ee2c804SbeveloperAudioMixer::HandleMessage(int32 message, const void *data, size_t size)
21300cffa1cSbeveloper{
21400cffa1cSbeveloper	// since we're using a mediaeventlooper, there shouldn't be any messages
215b0dd37b7SDario Casalinuovo	// except the message we are using to schedule output events for the
216b0dd37b7SDario Casalinuovo	// process thread.
217b0dd37b7SDario Casalinuovo
218b0dd37b7SDario Casalinuovo	if (message == MIXER_SCHEDULE_EVENT) {
219b0dd37b7SDario Casalinuovo		RealTimeQueue()->AddEvent(*(const media_timed_event*)data);
220b0dd37b7SDario Casalinuovo		return B_OK;
221b0dd37b7SDario Casalinuovo	}
222b0dd37b7SDario Casalinuovo
22300cffa1cSbeveloper	return B_ERROR;
22400cffa1cSbeveloper}
22500cffa1cSbeveloper
226e7cdf7f3SAxel Dörfler
22700cffa1cSbeveloperstatus_t
228be2a2489SbeveloperAudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat)
22900cffa1cSbeveloper{
2309c5b691fSshatty	PRINT_FORMAT("AudioMixer::AcceptFormat: ", *ioFormat);
2319c5b691fSshatty
2329bedd42cSbeveloper	// check that the specified format is reasonable for the specified destination, and
233e7cdf7f3SAxel Dörfler	// fill in any wildcard fields for which our BBufferConsumer has specific requirements.
23400cffa1cSbeveloper
235be2a2489Sbeveloper	// we have multiple inputs with different IDs, but
236be2a2489Sbeveloper	// the port number must match our ControlPort()
237be2a2489Sbeveloper	if (dest.port != ControlPort())
238e7cdf7f3SAxel Dörfler		return B_MEDIA_BAD_DESTINATION;
23900cffa1cSbeveloper
240be2a2489Sbeveloper	// specialize to raw audio format if necessary
241be2a2489Sbeveloper	if (ioFormat->type == B_MEDIA_UNKNOWN_TYPE)
242be2a2489Sbeveloper		ioFormat->type = B_MEDIA_RAW_AUDIO;
243e7cdf7f3SAxel Dörfler
244be2a2489Sbeveloper	// we require a raw audio format
245be2a2489Sbeveloper	if (ioFormat->type != B_MEDIA_RAW_AUDIO)
2469bedd42cSbeveloper		return B_MEDIA_BAD_FORMAT;
247e7cdf7f3SAxel Dörfler
248c3b1c2a6Sbeveloper	// We do not have special requirements, but just in case
24944327fe2Sbeveloper	// another mixer is connecting to us and may need a hint
250c3b1c2a6Sbeveloper	// to create a connection at optimal frame rate and
251c3b1c2a6Sbeveloper	// channel count, we place this information in the user_data
252c3b1c2a6Sbeveloper	fCore->Lock();
253c3b1c2a6Sbeveloper	MixerOutput *output = fCore->Output();
254c3b1c2a6Sbeveloper	uint32 channel_count = output ? output->MediaOutput().format.u.raw_audio.channel_count : 0;
255c3b1c2a6Sbeveloper	float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 0.0;
256c3b1c2a6Sbeveloper	fCore->Unlock();
257c3b1c2a6Sbeveloper	ioFormat->user_data_type = FORMAT_USER_DATA_TYPE;
258c3b1c2a6Sbeveloper	*(uint32 *)&ioFormat->user_data[0] = FORMAT_USER_DATA_MAGIC_1;
259c3b1c2a6Sbeveloper	*(uint32 *)&ioFormat->user_data[4] = channel_count;
260c3b1c2a6Sbeveloper	*(float *)&ioFormat->user_data[20] = frame_rate;
261c3b1c2a6Sbeveloper	*(uint32 *)&ioFormat->user_data[44] = FORMAT_USER_DATA_MAGIC_2;
262c3b1c2a6Sbeveloper
263be2a2489Sbeveloper	return B_OK;
26400cffa1cSbeveloper}
26500cffa1cSbeveloper
266e7cdf7f3SAxel Dörfler
26700cffa1cSbeveloperstatus_t
26800cffa1cSbeveloperAudioMixer::GetNextInput(int32 *cookie, media_input *out_input)
26900cffa1cSbeveloper{
2709c5b691fSshatty	TRACE("AudioMixer::GetNextInput\n");
271e7cdf7f3SAxel Dörfler
272be2a2489Sbeveloper	// our 0th input is always a wildcard and free one
273be2a2489Sbeveloper	if (*cookie == 0) {
274be2a2489Sbeveloper		out_input->node = Node();
275be2a2489Sbeveloper		out_input->source = media_source::null;
276be2a2489Sbeveloper		out_input->destination.port = ControlPort();
277be2a2489Sbeveloper		out_input->destination.id = 0;
2785b88998bSMurai Takashi		out_input->format.Clear();
279be2a2489Sbeveloper		out_input->format.type = B_MEDIA_RAW_AUDIO;
280be2a2489Sbeveloper		strcpy(out_input->name, "Free Input");
28100cffa1cSbeveloper		*cookie += 1;
28200cffa1cSbeveloper		return B_OK;
28300cffa1cSbeveloper	}
284be2a2489Sbeveloper
285be2a2489Sbeveloper	// the other inputs are the currently connected ones
286be2a2489Sbeveloper	fCore->Lock();
287be2a2489Sbeveloper	MixerInput *input;
288be2a2489Sbeveloper	input = fCore->Input(*cookie - 1);
289be2a2489Sbeveloper	if (!input) {
290be2a2489Sbeveloper		fCore->Unlock();
29100cffa1cSbeveloper		return B_BAD_INDEX;
292be2a2489Sbeveloper	}
293be2a2489Sbeveloper	*out_input = input->MediaInput();
294be2a2489Sbeveloper	*cookie += 1;
295be2a2489Sbeveloper	fCore->Unlock();
296be2a2489Sbeveloper	return B_OK;
29700cffa1cSbeveloper}
29800cffa1cSbeveloper
299e7cdf7f3SAxel Dörfler
30000cffa1cSbevelopervoid
30100cffa1cSbeveloperAudioMixer::DisposeInputCookie(int32 cookie)
30200cffa1cSbeveloper{
303be2a2489Sbeveloper	// nothing to do
30400cffa1cSbeveloper}
30500cffa1cSbeveloper
306e7cdf7f3SAxel Dörfler
30700cffa1cSbevelopervoid
30800cffa1cSbeveloperAudioMixer::BufferReceived(BBuffer *buffer)
30900cffa1cSbeveloper{
310545124e6Sbeveloper
3119bedd42cSbeveloper	if (buffer->Header()->type == B_MEDIA_PARAMETERS) {
312a2ca4723Sbeveloper		TRACE("Control Buffer Received\n");
3139bedd42cSbeveloper		ApplyParameterData(buffer->Data(), buffer->SizeUsed());
3149bedd42cSbeveloper		buffer->Recycle();
3159bedd42cSbeveloper		return;
3169bedd42cSbeveloper	}
3171ab3e018Sbeveloper
318a2ca4723Sbeveloper	//PRINT(4, "buffer received at %12Ld, should arrive at %12Ld, delta %12Ld\n", TimeSource()->Now(), buffer->Header()->start_time, TimeSource()->Now() - buffer->Header()->start_time);
319cb595db7Sbeveloper
3209bedd42cSbeveloper	// to receive the buffer at the right time,
3219bedd42cSbeveloper	// push it through the event looper
3229bedd42cSbeveloper	media_timed_event event(buffer->Header()->start_time,
323e7cdf7f3SAxel Dörfler		BTimedEventQueue::B_HANDLE_BUFFER, buffer,
324e7cdf7f3SAxel Dörfler		BTimedEventQueue::B_RECYCLE_BUFFER);
3259bedd42cSbeveloper	EventQueue()->AddEvent(event);
3269bedd42cSbeveloper}
32700cffa1cSbeveloper
3289bedd42cSbeveloper
3299bedd42cSbevelopervoid
330b289aaf6SAxel DörflerAudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
3319bedd42cSbeveloper{
3321fe3cb87SDario Casalinuovo	bigtime_t variation = 0;
3331fe3cb87SDario Casalinuovo	if (lateness > fLastLateness)
3341fe3cb87SDario Casalinuovo		variation = lateness-fLastLateness;
3351fe3cb87SDario Casalinuovo
3361fe3cb87SDario Casalinuovo	if (variation > kMaxJitter) {
33708a65695SDario Casalinuovo		TRACE("AudioMixer: Dequeued input buffer %" B_PRIdBIGTIME
338973f1214SJérôme Duval			" usec late\n", lateness);
339b289aaf6SAxel Dörfler		if (RunMode() == B_DROP_DATA || RunMode() == B_DECREASE_PRECISION
340b289aaf6SAxel Dörfler			|| RunMode() == B_INCREASE_LATENCY) {
34108a65695SDario Casalinuovo			TRACE("AudioMixer: sending notify\n");
342d0085d25SAxel Dörfler
343b289aaf6SAxel Dörfler			// Build a media_source out of the header data
344b289aaf6SAxel Dörfler			media_source source = media_source::null;
345b289aaf6SAxel Dörfler			source.port = buffer->Header()->source_port;
346b289aaf6SAxel Dörfler			source.id = buffer->Header()->source;
347b289aaf6SAxel Dörfler
3481fe3cb87SDario Casalinuovo			NotifyLateProducer(source, variation, TimeSource()->Now());
349b289aaf6SAxel Dörfler
350b289aaf6SAxel Dörfler			if (RunMode() == B_DROP_DATA) {
35108a65695SDario Casalinuovo				TRACE("AudioMixer: dropping buffer\n");
352b289aaf6SAxel Dörfler				return;
353b289aaf6SAxel Dörfler			}
35400cffa1cSbeveloper		}
355be2a2489Sbeveloper	}
3561fe3cb87SDario Casalinuovo
357ba5e652dSAdrien Destugues	fLastLateness = lateness;
358e7cdf7f3SAxel Dörfler
359e6c7c99fSbeveloper	fCore->Lock();
360be2a2489Sbeveloper	fCore->BufferReceived(buffer, lateness);
361e6c7c99fSbeveloper	fCore->Unlock();
3621ab3e018Sbeveloper}
3639bedd42cSbeveloper
364e7cdf7f3SAxel Dörfler
36500cffa1cSbevelopervoid
366e7cdf7f3SAxel DörflerAudioMixer::ProducerDataStatus(const media_destination& for_whom,
367e7cdf7f3SAxel Dörfler	int32 status, bigtime_t at_performance_time)
36800cffa1cSbeveloper{
369e7cdf7f3SAxel Dörfler/*
37000cffa1cSbeveloper	if (IsValidDest(for_whom))
37100cffa1cSbeveloper	{
37200cffa1cSbeveloper		media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
373ea83877fSbeveloper			(void *)(&for_whom), BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
37400cffa1cSbeveloper		EventQueue()->AddEvent(event);
375e7cdf7f3SAxel Dörfler
376ea83877fSbeveloper		// FIX_THIS
377ea83877fSbeveloper		// the for_whom destination is not being sent correctly - verify in HandleEvent loop
378e7cdf7f3SAxel Dörfler
37900cffa1cSbeveloper	}
380be2a2489Sbeveloper*/
38100cffa1cSbeveloper}
38200cffa1cSbeveloper
383e7cdf7f3SAxel Dörfler
38400cffa1cSbeveloperstatus_t
385be2a2489SbeveloperAudioMixer::GetLatencyFor(const media_destination &for_whom,
386e7cdf7f3SAxel Dörfler	bigtime_t *out_latency, media_node_id *out_timesource)
38700cffa1cSbeveloper{
388be2a2489Sbeveloper	// we have multiple inputs with different IDs, but
389be2a2489Sbeveloper	// the port number must match our ControlPort()
390be2a2489Sbeveloper	if (for_whom.port != ControlPort())
391e7cdf7f3SAxel Dörfler		return B_MEDIA_BAD_DESTINATION;
392e7cdf7f3SAxel Dörfler
393e7cdf7f3SAxel Dörfler	// return our event latency - this includes our internal + downstream
394ea83877fSbeveloper	// latency, but _not_ the scheduling latency
395ea83877fSbeveloper	*out_latency = EventLatency();
39600cffa1cSbeveloper	*out_timesource = TimeSource()->ID();
39700cffa1cSbeveloper
398973f1214SJérôme Duval	printf("AudioMixer::GetLatencyFor %" B_PRIdBIGTIME ", timesource is %"
399973f1214SJérôme Duval		B_PRId32 "\n", *out_latency, *out_timesource);
4001ab3e018Sbeveloper
40100cffa1cSbeveloper	return B_OK;
40200cffa1cSbeveloper}
40300cffa1cSbeveloper
404e7cdf7f3SAxel Dörfler
40500cffa1cSbeveloperstatus_t
406e7cdf7f3SAxel DörflerAudioMixer::Connected(const media_source &producer,
407e7cdf7f3SAxel Dörfler	const media_destination &where, const media_format &with_format,
408e7cdf7f3SAxel Dörfler	media_input *out_input)
40900cffa1cSbeveloper{
4109c5b691fSshatty	PRINT_FORMAT("AudioMixer::Connected: ", with_format);
4119c5b691fSshatty
4129c5b691fSshatty	// workaround for a crashing bug in RealPlayer.  to be proper, RealPlayer's
4139c5b691fSshatty	// BBufferProducer::PrepareToConnect() should have removed all wildcards.
4149c5b691fSshatty	if (out_input->format.u.raw_audio.frame_rate == 0) {
415bf7ab50dSStephan Aßmus		fprintf(stderr, "Audio Mixer Warning: "
416973f1214SJérôme Duval			"Producer (port %" B_PRId32 ", id %" B_PRId32 ") connected with "
417973f1214SJérôme Duval			"frame_rate=0\n", producer.port, producer.id);
4189c5b691fSshatty		MixerOutput *output = fCore->Output();
419e7cdf7f3SAxel Dörfler		float frame_rate = output
420e7cdf7f3SAxel Dörfler			? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f;
4219c5b691fSshatty		out_input->format.u.raw_audio.frame_rate = frame_rate;
4229c5b691fSshatty	}
423e7cdf7f3SAxel Dörfler
424bf7ab50dSStephan Aßmus	// a BBufferProducer is connecting to our BBufferConsumer
425e7cdf7f3SAxel Dörfler
426be2a2489Sbeveloper	// incoming connections should always have an incoming ID=0,
427be2a2489Sbeveloper	// and the port number must match our ControlPort()
428be2a2489Sbeveloper	if (where.id != 0 || where.port != ControlPort())
429be2a2489Sbeveloper		return B_MEDIA_BAD_DESTINATION;
430e7cdf7f3SAxel Dörfler
431be2a2489Sbeveloper	fCore->Lock();
432e7cdf7f3SAxel Dörfler
433be2a2489Sbeveloper	// we assign a new id (!= 0) to the newly created input
434be2a2489Sbeveloper	out_input->destination.id = fCore->CreateInputID();
43500cffa1cSbeveloper
436e7cdf7f3SAxel Dörfler	// We need to make sure that the outInput's name field contains a valid
437e7cdf7f3SAxel Dörfler	// name, the name given the connection by the producer may still be an
438e7cdf7f3SAxel Dörfler	// empty string.
439be2a2489Sbeveloper	// if the input has no name, assign one
440973f1214SJérôme Duval	if (strlen(out_input->name) == 0) {
441973f1214SJérôme Duval		sprintf(out_input->name, "Input %" B_PRId32,
442973f1214SJérôme Duval			out_input->destination.id);
443973f1214SJérôme Duval	}
444e7cdf7f3SAxel Dörfler
445be2a2489Sbeveloper	// add a new input to the mixer engine
4461165d5e1Sbeveloper	MixerInput *input;
4471165d5e1Sbeveloper	input = fCore->AddInput(*out_input);
4481165d5e1Sbeveloper
4491165d5e1Sbeveloper	fCore->Settings()->LoadConnectionSettings(input);
450ea83877fSbeveloper
451be2a2489Sbeveloper	fCore->Unlock();
452e7cdf7f3SAxel Dörfler
453e7cdf7f3SAxel Dörfler	// If we want the producer to use a specific BBufferGroup, we now need
454e7cdf7f3SAxel Dörfler	// to call BMediaRoster::SetOutputBuffersFor() here to set the producer's
455e7cdf7f3SAxel Dörfler	// buffer group.
456be2a2489Sbeveloper	// But we have no special buffer requirements anyway...
457bf7ab50dSStephan Aßmus
4589391f0a5Sbeveloper	UpdateParameterWeb();
459bf7ab50dSStephan Aßmus
46000cffa1cSbeveloper	return B_OK;
46100cffa1cSbeveloper}
46200cffa1cSbeveloper
463e7cdf7f3SAxel Dörfler
46400cffa1cSbevelopervoid
465e7cdf7f3SAxel DörflerAudioMixer::Disconnected(const media_source &producer,
466e7cdf7f3SAxel Dörfler	const media_destination &where)
46700cffa1cSbeveloper{
468ea83877fSbeveloper	// One of our inputs has been disconnected
469bf7ab50dSStephan Aßmus
470be2a2489Sbeveloper	// check if it is really belongs to us
471be2a2489Sbeveloper	if (where.port != ControlPort()) {
472be2a2489Sbeveloper		TRACE("AudioMixer::Disconnected wrong input port\n");
473be2a2489Sbeveloper		return;
474be2a2489Sbeveloper	}
475e7cdf7f3SAxel Dörfler
476be2a2489Sbeveloper	fCore->Lock();
477e7cdf7f3SAxel Dörfler
478be2a2489Sbeveloper	if (!fCore->RemoveInput(where.id)) {
479be2a2489Sbeveloper		TRACE("AudioMixer::Disconnected can't remove input\n");
480be2a2489Sbeveloper	}
481e7cdf7f3SAxel Dörfler
482be2a2489Sbeveloper	fCore->Unlock();
4839391f0a5Sbeveloper	UpdateParameterWeb();
48400cffa1cSbeveloper}
48500cffa1cSbeveloper
486e7cdf7f3SAxel Dörfler
48700cffa1cSbeveloperstatus_t
488e7cdf7f3SAxel DörflerAudioMixer::FormatChanged(const media_source &producer,
489e7cdf7f3SAxel Dörfler	const media_destination &consumer, int32 change_tag,
490e7cdf7f3SAxel Dörfler	const media_format &format)
49100cffa1cSbeveloper{
4927ee2c804Sbeveloper	// at some point in the future (indicated by change_tag and RequestCompleted()),
4937ee2c804Sbeveloper	// we will receive buffers in a different format
4948d28117fSbeveloper
495a2ca4723Sbeveloper	TRACE("AudioMixer::FormatChanged\n");
496bf7ab50dSStephan Aßmus
4977ee2c804Sbeveloper	if (consumer.port != ControlPort() || consumer.id == 0)
4987ee2c804Sbeveloper		return B_MEDIA_BAD_DESTINATION;
4995fa60b3bSbeveloper
5005fa60b3bSbeveloper	if (fCore->Settings()->RefuseInputFormatChange()) {
5015fa60b3bSbeveloper		TRACE("AudioMixer::FormatChanged: input format change refused\n");
50278a60972SStephan Aßmus		return B_NOT_ALLOWED;
5035fa60b3bSbeveloper	}
504e7cdf7f3SAxel Dörfler
50578a60972SStephan Aßmus	// TODO: We should not apply the format change at this point
50678a60972SStephan Aßmus	// TODO: At the moment, this is not implemented at the moment and will just
50778a60972SStephan Aßmus	// crash the media_server.
50878a60972SStephan Aßmus	return B_NOT_SUPPORTED;
50900cffa1cSbeveloper
5107ee2c804Sbeveloper	// tell core about format change
5117ee2c804Sbeveloper	fCore->Lock();
5127b0daf5cSbeveloper	fCore->InputFormatChanged(consumer.id, format.u.raw_audio);
5137ee2c804Sbeveloper	fCore->Unlock();
514e7cdf7f3SAxel Dörfler
5157ee2c804Sbeveloper	return B_OK;
51600cffa1cSbeveloper}
51700cffa1cSbeveloper
518e7cdf7f3SAxel Dörfler
519e7cdf7f3SAxel Dörfler//	#pragma mark - BBufferProducer methods
520e7cdf7f3SAxel Dörfler
52100cffa1cSbeveloper
52200cffa1cSbeveloperstatus_t
523e7cdf7f3SAxel DörflerAudioMixer::FormatSuggestionRequested(media_type type, int32 quality,
524e7cdf7f3SAxel Dörfler	media_format *format)
52500cffa1cSbeveloper{
5269c5b691fSshatty	TRACE("AudioMixer::FormatSuggestionRequested\n");
527e7cdf7f3SAxel Dörfler
528be2a2489Sbeveloper	// BBufferProducer function, a downstream consumer
529be2a2489Sbeveloper	// is asking for our output format
53000cffa1cSbeveloper
531be2a2489Sbeveloper	if (type != B_MEDIA_RAW_AUDIO && type != B_MEDIA_UNKNOWN_TYPE)
53200cffa1cSbeveloper		return B_MEDIA_BAD_FORMAT;
53300cffa1cSbeveloper
534be2a2489Sbeveloper	// we can produce any (wildcard) raw audio format
5355b88998bSMurai Takashi	format->Clear();
536be2a2489Sbeveloper	format->type = B_MEDIA_RAW_AUDIO;
537be2a2489Sbeveloper	return B_OK;
53800cffa1cSbeveloper}
53900cffa1cSbeveloper
540e7cdf7f3SAxel Dörfler
54100cffa1cSbeveloperstatus_t
542be2a2489SbeveloperAudioMixer::FormatProposal(const media_source &output, media_format *ioFormat)
54300cffa1cSbeveloper{
544be2a2489Sbeveloper	// BBufferProducer function, we implement this function to verify that the
545be2a2489Sbeveloper	// proposed media_format is suitable for the specified output. If any fields
546be2a2489Sbeveloper	// in the format are wildcards, and we have a specific requirement, adjust
547be2a2489Sbeveloper	// those fields to match our requirements before returning.
548e6c7c99fSbeveloper
549a2ca4723Sbeveloper	TRACE("AudioMixer::FormatProposal\n");
550e7cdf7f3SAxel Dörfler
551be2a2489Sbeveloper	// we only have one output (id=0, port=ControlPort())
552be2a2489Sbeveloper	if (output.id != 0 || output.port != ControlPort())
55300cffa1cSbeveloper		return B_MEDIA_BAD_SOURCE;
554be2a2489Sbeveloper
555be2a2489Sbeveloper	// specialize to raw audio format if necessary
556be2a2489Sbeveloper	if (ioFormat->type == B_MEDIA_UNKNOWN_TYPE)
557be2a2489Sbeveloper		ioFormat->type = B_MEDIA_RAW_AUDIO;
558e7cdf7f3SAxel Dörfler
559be2a2489Sbeveloper	// we require a raw audio format
560be2a2489Sbeveloper	if (ioFormat->type != B_MEDIA_RAW_AUDIO)
56100cffa1cSbeveloper		return B_MEDIA_BAD_FORMAT;
562c3b1c2a6Sbeveloper
563e6c7c99fSbeveloper	return B_OK;
56400cffa1cSbeveloper}
56500cffa1cSbeveloper
566e7cdf7f3SAxel Dörfler/*!	If the format isn't good, put a good format into *io_format and return error
567e7cdf7f3SAxel Dörfler	If format has wildcard, specialize to what you can do (and change).
568e7cdf7f3SAxel Dörfler	If you can change the format, return OK.
569e7cdf7f3SAxel Dörfler	The request comes from your destination sychronously, so you cannot ask it
570e7cdf7f3SAxel Dörfler	whether it likes it -- you should assume it will since it asked.
571e7cdf7f3SAxel Dörfler*/
57200cffa1cSbeveloperstatus_t
573e7cdf7f3SAxel DörflerAudioMixer::FormatChangeRequested(const media_source &source,
574e7cdf7f3SAxel Dörfler	const media_destination &destination, media_format *io_format,
575e7cdf7f3SAxel Dörfler	int32 *_deprecated_)
576be2a2489Sbeveloper{
577be2a2489Sbeveloper	// the downstream consumer node (soundcard) requested that we produce
5787ee2c804Sbeveloper	// another format, we need to check if the format is acceptable and
579be2a2489Sbeveloper	// remove any wildcards before returning OK.
580e7cdf7f3SAxel Dörfler
581a2ca4723Sbeveloper	TRACE("AudioMixer::FormatChangeRequested\n");
5825fa60b3bSbeveloper
5835fa60b3bSbeveloper	if (fCore->Settings()->RefuseOutputFormatChange()) {
5845fa60b3bSbeveloper		TRACE("AudioMixer::FormatChangeRequested: output format change refused\n");
5855fa60b3bSbeveloper		return B_ERROR;
5865fa60b3bSbeveloper	}
5875fa60b3bSbeveloper
5885fa60b3bSbeveloper	fCore->Lock();
5895fa60b3bSbeveloper
5908c19f07fSDario Casalinuovo	status_t status = B_OK;
5918c19f07fSDario Casalinuovo	BBufferGroup *group = NULL;
592be2a2489Sbeveloper	MixerOutput *output = fCore->Output();
593be2a2489Sbeveloper	if (!output) {
594e6c7c99fSbeveloper		ERROR("AudioMixer::FormatChangeRequested: no output\n");
595be2a2489Sbeveloper		goto err;
596be2a2489Sbeveloper	}
597be2a2489Sbeveloper	if (source != output->MediaOutput().source) {
598e6c7c99fSbeveloper		ERROR("AudioMixer::FormatChangeRequested: wrong output source\n");
599be2a2489Sbeveloper		goto err;
600be2a2489Sbeveloper	}
601be2a2489Sbeveloper	if (destination != output->MediaOutput().destination) {
602e7cdf7f3SAxel Dörfler		ERROR("AudioMixer::FormatChangeRequested: wrong output destination "
603e7cdf7f3SAxel Dörfler			"(port %ld, id %ld), our is (port %ld, id %ld)\n", destination.port,
604e7cdf7f3SAxel Dörfler			destination.id, output->MediaOutput().destination.port,
605e7cdf7f3SAxel Dörfler			output->MediaOutput().destination.id);
606e7cdf7f3SAxel Dörfler		if (destination.port == output->MediaOutput().destination.port
607e7cdf7f3SAxel Dörfler			&& destination.id == output->MediaOutput().destination.id + 1) {
608e7cdf7f3SAxel Dörfler			ERROR("AudioMixer::FormatChangeRequested: this might be the broken "
609e7cdf7f3SAxel Dörfler				"R5 multi audio add-on\n");
6108d28117fSbeveloper		}
611e7cdf7f3SAxel Dörfler		goto err;
612be2a2489Sbeveloper	}
613e7cdf7f3SAxel Dörfler	if (io_format->type != B_MEDIA_RAW_AUDIO
614e7cdf7f3SAxel Dörfler		&& io_format->type != B_MEDIA_UNKNOWN_TYPE) {
615e6c7c99fSbeveloper		ERROR("AudioMixer::FormatChangeRequested: wrong format type\n");
616be2a2489Sbeveloper		goto err;
617be2a2489Sbeveloper	}
618e7cdf7f3SAxel Dörfler
619be2a2489Sbeveloper	/* remove wildcards */
620e7cdf7f3SAxel Dörfler#if USE_MEDIA_FORMAT_WORKAROUND
621e7cdf7f3SAxel Dörfler	multi_audio_format_specialize(&io_format->u.raw_audio,
622e7cdf7f3SAxel Dörfler		&fDefaultFormat.u.raw_audio);
623e7cdf7f3SAxel Dörfler#else
624e7cdf7f3SAxel Dörfler	io_format->SpecializeTo(&fDefaultFormat);
625e7cdf7f3SAxel Dörfler#endif
626e7cdf7f3SAxel Dörfler
6278d28117fSbeveloper	media_node_id id;
6288d28117fSbeveloper	FindLatencyFor(destination, &fDownstreamLatency, &id);
629973f1214SJérôme Duval	TRACE("AudioMixer: Downstream Latency is %" B_PRIdBIGTIME " usecs\n",
630973f1214SJérôme Duval		fDownstreamLatency);
6318d28117fSbeveloper
6328d28117fSbeveloper	// SetDuration of one buffer
6338d28117fSbeveloper	SetBufferDuration(buffer_duration(io_format->u.raw_audio));
634973f1214SJérôme Duval	TRACE("AudioMixer: buffer duration is %" B_PRIdBIGTIME " usecs\n",
635973f1214SJérôme Duval		BufferDuration());
6368d28117fSbeveloper
6378d28117fSbeveloper	// Our internal latency is at least the length of a full output buffer
638e7cdf7f3SAxel Dörfler	fInternalLatency = BufferDuration()
639973f1214SJérôme Duval		+ max((bigtime_t)4500, bigtime_t(0.5 * BufferDuration()));
640973f1214SJérôme Duval	TRACE("AudioMixer: Internal latency is %" B_PRIdBIGTIME " usecs\n",
641973f1214SJérôme Duval		fInternalLatency);
642e7cdf7f3SAxel Dörfler
6438d28117fSbeveloper	SetEventLatency(fDownstreamLatency + fInternalLatency);
644e7cdf7f3SAxel Dörfler
645dfbe8043Sbeveloper	// we need to inform all connected *inputs* about *our* change in latency
646dfbe8043Sbeveloper	PublishEventLatencyChange();
647e7cdf7f3SAxel Dörfler
648e7cdf7f3SAxel Dörfler	// TODO: we might need to create more buffers, to span a larger downstream
649e7cdf7f3SAxel Dörfler	// latency
6508d28117fSbeveloper
6518d28117fSbeveloper	// apply latency change
6528d28117fSbeveloper	fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
6538d28117fSbeveloper
6547ee2c804Sbeveloper	// apply format change
6557b0daf5cSbeveloper	fCore->OutputFormatChanged(io_format->u.raw_audio);
6568d28117fSbeveloper
6578c19f07fSDario Casalinuovo	status = CreateBufferGroup(&group);
6588c19f07fSDario Casalinuovo	if (status != B_OK)
6598c19f07fSDario Casalinuovo		return status;
6608c19f07fSDario Casalinuovo	else {
6618c19f07fSDario Casalinuovo		delete fBufferGroup;
6628c19f07fSDario Casalinuovo		fBufferGroup = group;
6638c19f07fSDario Casalinuovo		fCore->SetOutputBufferGroup(fBufferGroup);
6648c19f07fSDario Casalinuovo	}
665fae6ce82Sbeveloper
666be2a2489Sbevelopererr:
667be2a2489Sbeveloper	fCore->Unlock();
6688c19f07fSDario Casalinuovo	return status;
66900cffa1cSbeveloper}
67000cffa1cSbeveloper
671e7cdf7f3SAxel Dörfler
672e7cdf7f3SAxel Dörflerstatus_t
673be2a2489SbeveloperAudioMixer::GetNextOutput(int32 *cookie, media_output *out_output)
67400cffa1cSbeveloper{
6759c5b691fSshatty	TRACE("AudioMixer::GetNextOutput\n");
6769c5b691fSshatty
677be2a2489Sbeveloper	if (*cookie != 0)
678be2a2489Sbeveloper		return B_BAD_INDEX;
67900cffa1cSbeveloper
680be2a2489Sbeveloper	fCore->Lock();
6817ee2c804Sbeveloper	MixerOutput *output = fCore->Output();
682be2a2489Sbeveloper	if (output) {
683be2a2489Sbeveloper		*out_output = output->MediaOutput();
684be2a2489Sbeveloper	} else {
685e6c7c99fSbeveloper		out_output->node = Node();
686be2a2489Sbeveloper		out_output->source.port = ControlPort();
687be2a2489Sbeveloper		out_output->source.id = 0;
688be2a2489Sbeveloper		out_output->destination = media_destination::null;
6895b88998bSMurai Takashi		out_output->format.Clear();
690be2a2489Sbeveloper		out_output->format.type = B_MEDIA_RAW_AUDIO;
691be2a2489Sbeveloper		strcpy(out_output->name, "Mixer Output");
69200cffa1cSbeveloper	}
693be2a2489Sbeveloper	fCore->Unlock();
694be2a2489Sbeveloper
695be2a2489Sbeveloper	*cookie += 1;
6967ee2c804Sbeveloper	return B_OK;
69700cffa1cSbeveloper}
69800cffa1cSbeveloper
699e7cdf7f3SAxel Dörfler
700e7cdf7f3SAxel Dörflerstatus_t
701be2a2489SbeveloperAudioMixer::DisposeOutputCookie(int32 cookie)
70200cffa1cSbeveloper{
703bf7ab50dSStephan Aßmus	// nothing to do
70400cffa1cSbeveloper	return B_OK;
70500cffa1cSbeveloper}
70600cffa1cSbeveloper
707e7cdf7f3SAxel Dörfler
708e7cdf7f3SAxel Dörflerstatus_t
709e7cdf7f3SAxel DörflerAudioMixer::SetBufferGroup(const media_source &for_source,
710e7cdf7f3SAxel Dörfler	BBufferGroup *newGroup)
71100cffa1cSbeveloper{
712cb7b1a3cSStephan Aßmus	TRACE("AudioMixer::SetBufferGroup\n");
7137ee2c804Sbeveloper	// the downstream consumer (soundcard) node asks us to use another
7147ee2c804Sbeveloper	// BBufferGroup (might be NULL). We only have one output (id 0)
7157ee2c804Sbeveloper	if (for_source.port != ControlPort() || for_source.id != 0)
71600cffa1cSbeveloper		return B_MEDIA_BAD_SOURCE;
71700cffa1cSbeveloper
718bf7ab50dSStephan Aßmus	if (newGroup == fBufferGroup) {
719bf7ab50dSStephan Aßmus		// we're already using this buffergroup
72000cffa1cSbeveloper		return B_OK;
721bf7ab50dSStephan Aßmus	}
722e7cdf7f3SAxel Dörfler
7237ee2c804Sbeveloper	fCore->Lock();
7248c19f07fSDario Casalinuovo	if (!newGroup) {
7258c19f07fSDario Casalinuovo		status_t status = CreateBufferGroup(&newGroup);
7268c19f07fSDario Casalinuovo		if (status != B_OK)
7278c19f07fSDario Casalinuovo			return status;
7288c19f07fSDario Casalinuovo	}
7297ee2c804Sbeveloper	fCore->SetOutputBufferGroup(newGroup);
7307ee2c804Sbeveloper	delete fBufferGroup;
7317ee2c804Sbeveloper	fBufferGroup = newGroup;
7327ee2c804Sbeveloper	fCore->Unlock();
73300cffa1cSbeveloper
73400cffa1cSbeveloper	return B_OK;
73500cffa1cSbeveloper}
73600cffa1cSbeveloper
737e7cdf7f3SAxel Dörfler
73800cffa1cSbeveloperstatus_t
73900cffa1cSbeveloperAudioMixer::GetLatency(bigtime_t *out_latency)
74000cffa1cSbeveloper{
74100cffa1cSbeveloper	// report our *total* latency:  internal plus downstream plus scheduling
74200cffa1cSbeveloper	*out_latency = EventLatency() + SchedulingLatency();
7431ab3e018Sbeveloper
744a2ca4723Sbeveloper	TRACE("AudioMixer::GetLatency %Ld\n", *out_latency);
7451ab3e018Sbeveloper
74600cffa1cSbeveloper	return B_OK;
74700cffa1cSbeveloper}
74800cffa1cSbeveloper
749e7cdf7f3SAxel Dörfler
750c3b1c2a6Sbevelopervoid
751e7cdf7f3SAxel DörflerAudioMixer::LatencyChanged(const media_source& source,
752e7cdf7f3SAxel Dörfler	const media_destination& destination, bigtime_t new_latency, uint32 flags)
753c3b1c2a6Sbeveloper{
754dfbe8043Sbeveloper	if (source.port != ControlPort() || source.id != 0) {
755e7cdf7f3SAxel Dörfler		ERROR("AudioMixer::LatencyChanged: received but has wrong source "
756e7cdf7f3SAxel Dörfler			"%ld/%ld\n", source.port, source.id);
757dfbe8043Sbeveloper		return;
758dfbe8043Sbeveloper	}
759dfbe8043Sbeveloper
760e7cdf7f3SAxel Dörfler	TRACE("AudioMixer::LatencyChanged: downstream latency from %ld/%ld to "
761e7cdf7f3SAxel Dörfler		"%ld/%ld changed from %Ld to %Ld\n", source.port, source.id,
762e7cdf7f3SAxel Dörfler		destination.port, destination.id, fDownstreamLatency, new_latency);
763dfbe8043Sbeveloper
764dfbe8043Sbeveloper#if DEBUG
765dfbe8043Sbeveloper	{
766dfbe8043Sbeveloper		media_node_id id;
767dfbe8043Sbeveloper		bigtime_t l;
768dfbe8043Sbeveloper		FindLatencyFor(destination, &l, &id);
769dfbe8043Sbeveloper		TRACE("AudioMixer: Reported downstream Latency is %Ld usecs\n", l);
770dfbe8043Sbeveloper	}
771dfbe8043Sbeveloper#endif
772c3b1c2a6Sbeveloper
773c3b1c2a6Sbeveloper	fDownstreamLatency = new_latency;
774c3b1c2a6Sbeveloper	SetEventLatency(fDownstreamLatency + fInternalLatency);
775dfbe8043Sbeveloper
776e7cdf7f3SAxel Dörfler	// XXX we might need to create more buffers, to span a larger downstream
777e7cdf7f3SAxel Dörfler	// latency
778e7cdf7f3SAxel Dörfler
779c3b1c2a6Sbeveloper	fCore->Lock();
780c3b1c2a6Sbeveloper	fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
781dfbe8043Sbeveloper	PublishEventLatencyChange();
782c3b1c2a6Sbeveloper	fCore->Unlock();
783c3b1c2a6Sbeveloper}
784c3b1c2a6Sbeveloper
78500cffa1cSbeveloperstatus_t
786e7cdf7f3SAxel DörflerAudioMixer::PrepareToConnect(const media_source &what,
787e7cdf7f3SAxel Dörfler	const media_destination &where, media_format *format,
788e7cdf7f3SAxel Dörfler	media_source *out_source, char *out_name)
78900cffa1cSbeveloper{
7909c5b691fSshatty	TRACE("AudioMixer::PrepareToConnect\n");
791e7cdf7f3SAxel Dörfler	// PrepareToConnect() is the second stage of format negotiations that
792e7cdf7f3SAxel Dörfler	// happens inside BMediaRoster::Connect(). At this point, the consumer's
793e7cdf7f3SAxel Dörfler	// AcceptFormat() method has been called, and that node has potentially
794e7cdf7f3SAxel Dörfler	// changed the proposed format.
795e7cdf7f3SAxel Dörfler	// It may also have left wildcards in the format. PrepareToConnect()
79600cffa1cSbeveloper	// *must* fully specialize the format before returning!
7977ee2c804Sbeveloper	// we also create the new output connection and return it in out_source.
79800cffa1cSbeveloper
799e6c7c99fSbeveloper	PRINT_FORMAT("AudioMixer::PrepareToConnect: suggested format", *format);
800b5a088d0Sbeveloper
801b5a088d0Sbeveloper	// avoid loop connections
802b5a088d0Sbeveloper	if (where.port == ControlPort())
803b5a088d0Sbeveloper		return B_MEDIA_BAD_SOURCE;
804b5a088d0Sbeveloper
8057ee2c804Sbeveloper	// is the source valid?
8067ee2c804Sbeveloper	if (what.port != ControlPort() || what.id != 0)
80700cffa1cSbeveloper		return B_MEDIA_BAD_SOURCE;
80800cffa1cSbeveloper
8097ee2c804Sbeveloper	// is the format acceptable?
810e7cdf7f3SAxel Dörfler	if (format->type != B_MEDIA_RAW_AUDIO
811e7cdf7f3SAxel Dörfler		&& format->type != B_MEDIA_UNKNOWN_TYPE) {
812e6c7c99fSbeveloper		PRINT_FORMAT("AudioMixer::PrepareToConnect: bad format", *format);
81300cffa1cSbeveloper		return B_MEDIA_BAD_FORMAT;
814e6c7c99fSbeveloper	}
81500cffa1cSbeveloper
8167ee2c804Sbeveloper	fCore->Lock();
81700cffa1cSbeveloper
8187ee2c804Sbeveloper	// are we already connected?
8197ee2c804Sbeveloper	if (fCore->Output() != 0) {
8207ee2c804Sbeveloper		fCore->Unlock();
821e6c7c99fSbeveloper		ERROR("AudioMixer::PrepareToConnect: already connected\n");
8227ee2c804Sbeveloper		return B_MEDIA_ALREADY_CONNECTED;
8237ee2c804Sbeveloper	}
82400cffa1cSbeveloper
825c3b1c2a6Sbeveloper	// It is possible that another mixer is connecting.
826c3b1c2a6Sbeveloper	// To avoid using the default format, we use one of
827c3b1c2a6Sbeveloper	// a) the format that it indicated as hint in the user_data,
828c3b1c2a6Sbeveloper	// b) the output format of the system audio mixer
829c3b1c2a6Sbeveloper	// c) the input format of the system DAC device
830c3b1c2a6Sbeveloper	// d) if everything failes, keep the wildcard
831c3b1c2a6Sbeveloper	if (format->u.raw_audio.channel_count == 0
832c3b1c2a6Sbeveloper		&& format->u.raw_audio.frame_rate < 1
833c3b1c2a6Sbeveloper		&& format->user_data_type == FORMAT_USER_DATA_TYPE
834c3b1c2a6Sbeveloper		&& *(uint32 *)&format->user_data[0] == FORMAT_USER_DATA_MAGIC_1
835c3b1c2a6Sbeveloper		&& *(uint32 *)&format->user_data[44] == FORMAT_USER_DATA_MAGIC_2) {
836c3b1c2a6Sbeveloper		// ok, a mixer is connecting
837c3b1c2a6Sbeveloper		uint32 channel_count = *(uint32 *)&format->user_data[4];
838c3b1c2a6Sbeveloper		float frame_rate = *(float *)&format->user_data[20];
839c3b1c2a6Sbeveloper		if (channel_count > 0 && frame_rate > 0) {
840c3b1c2a6Sbeveloper			// format is good, use it
841c3b1c2a6Sbeveloper			format->u.raw_audio.channel_count = channel_count;
842c3b1c2a6Sbeveloper			format->u.raw_audio.frame_rate = frame_rate;
843c3b1c2a6Sbeveloper		} else {
844c3b1c2a6Sbeveloper			// other mixer's output is probably not connected
845c3b1c2a6Sbeveloper			media_node node;
846c3b1c2a6Sbeveloper			BMediaRoster *roster = BMediaRoster::Roster();
847c3b1c2a6Sbeveloper			media_output out;
848c3b1c2a6Sbeveloper			media_input in;
849c3b1c2a6Sbeveloper			int32 count;
850e7cdf7f3SAxel Dörfler			if (roster->GetAudioMixer(&node) == B_OK
851e7cdf7f3SAxel Dörfler				&& roster->GetConnectedOutputsFor(node, &out, 1, &count)
852e7cdf7f3SAxel Dörfler						== B_OK
853e7cdf7f3SAxel Dörfler				&& count == 1) {
854c3b1c2a6Sbeveloper				// use mixer output format
855e7cdf7f3SAxel Dörfler				format->u.raw_audio.channel_count
856e7cdf7f3SAxel Dörfler					= out.format.u.raw_audio.channel_count;
857e7cdf7f3SAxel Dörfler				format->u.raw_audio.frame_rate
858e7cdf7f3SAxel Dörfler					= out.format.u.raw_audio.frame_rate;
859e7cdf7f3SAxel Dörfler			} else if (roster->GetAudioOutput(&node) == B_OK
860e7cdf7f3SAxel Dörfler				&& roster->GetAllInputsFor(node, &in, 1, &count) == B_OK
861e7cdf7f3SAxel Dörfler				&& count == 1) {
862c3b1c2a6Sbeveloper				// use DAC input format
863e7cdf7f3SAxel Dörfler				format->u.raw_audio.channel_count
864e7cdf7f3SAxel Dörfler					= in.format.u.raw_audio.channel_count;
865e7cdf7f3SAxel Dörfler				format->u.raw_audio.frame_rate
866e7cdf7f3SAxel Dörfler					= in.format.u.raw_audio.frame_rate;
867c3b1c2a6Sbeveloper			}
868c3b1c2a6Sbeveloper		}
869c3b1c2a6Sbeveloper	}
870c3b1c2a6Sbeveloper
8717ee2c804Sbeveloper	/* set source and suggest a name */
8727ee2c804Sbeveloper	*out_source = what;
8737ee2c804Sbeveloper	strcpy(out_name, "Mixer Output");
87400cffa1cSbeveloper
8757ee2c804Sbeveloper	/* remove wildcards */
876e7cdf7f3SAxel Dörfler#if USE_MEDIA_FORMAT_WORKAROUND
877e7cdf7f3SAxel Dörfler	multi_audio_format_specialize(&format->u.raw_audio,
878e7cdf7f3SAxel Dörfler		&fDefaultFormat.u.raw_audio);
879e7cdf7f3SAxel Dörfler#else
880e7cdf7f3SAxel Dörfler	format->SpecializeTo(&fDefaultFormat);
881e7cdf7f3SAxel Dörfler#endif
882e6c7c99fSbeveloper
883e6c7c99fSbeveloper	PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format);
88400cffa1cSbeveloper
885e7cdf7f3SAxel Dörfler	/* add output to core */
8867ee2c804Sbeveloper	media_output output;
8877ee2c804Sbeveloper	output.node = Node();
8887ee2c804Sbeveloper	output.source = *out_source;
8897ee2c804Sbeveloper	output.destination = where;
8907ee2c804Sbeveloper	output.format = *format;
8917ee2c804Sbeveloper	strcpy(output.name, out_name);
892e7cdf7f3SAxel Dörfler
8937ee2c804Sbeveloper	fCore->EnableOutput(false);
8947ee2c804Sbeveloper	fCore->AddOutput(output);
8957ee2c804Sbeveloper
8967ee2c804Sbeveloper	fCore->Unlock();
89700cffa1cSbeveloper	return B_OK;
89800cffa1cSbeveloper}
89900cffa1cSbeveloper
900e7cdf7f3SAxel Dörfler
901e7cdf7f3SAxel Dörflervoid
902e7cdf7f3SAxel DörflerAudioMixer::Connect(status_t error, const media_source &source,
903e7cdf7f3SAxel Dörfler	const media_destination &dest, const media_format &format, char *io_name)
90400cffa1cSbeveloper{
905a2ca4723Sbeveloper	TRACE("AudioMixer::Connect\n");
90600cffa1cSbeveloper
907cb595db7Sbeveloper	fCore->Lock();
908cb595db7Sbeveloper	// are we still connected?
909cb595db7Sbeveloper	if (fCore->Output() == 0) {
910cb595db7Sbeveloper		fCore->Unlock();
911cb595db7Sbeveloper		ERROR("AudioMixer::Connect: no longer connected\n");
912cb595db7Sbeveloper		return;
913cb595db7Sbeveloper	}
914cb595db7Sbeveloper	fCore->Unlock();
915cb595db7Sbeveloper
9167ee2c804Sbeveloper	if (error != B_OK) {
9177ee2c804Sbeveloper		// if an error occured, remove output from core
918e7cdf7f3SAxel Dörfler		ERROR("AudioMixer::Connect failed with error 0x%08lX, removing "
919e7cdf7f3SAxel Dörfler			"connection\n", error);
9207ee2c804Sbeveloper		fCore->Lock();
9217ee2c804Sbeveloper		fCore->RemoveOutput();
9227ee2c804Sbeveloper		fCore->Unlock();
92300cffa1cSbeveloper		return;
92400cffa1cSbeveloper	}
925cb595db7Sbeveloper
926b289aaf6SAxel Dörfler	// Switch our prefered format to have the same
927b289aaf6SAxel Dörfler	// frame_rate and channel count as the output.
928c3b1c2a6Sbeveloper	fDefaultFormat.u.raw_audio.frame_rate = format.u.raw_audio.frame_rate;
929c3b1c2a6Sbeveloper	fDefaultFormat.u.raw_audio.channel_count = format.u.raw_audio.channel_count;
930c3b1c2a6Sbeveloper
9317ee2c804Sbeveloper	// if the connection has no name, we set it now
9327ee2c804Sbeveloper	if (strlen(io_name) == 0)
9337ee2c804Sbeveloper		strcpy(io_name, "Mixer Output");
934e7cdf7f3SAxel Dörfler
93500cffa1cSbeveloper	// Now that we're connected, we can determine our downstream latency.
936