allocate mixer buffers of the correct size,
place incoming data in input specific mix buffer git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3646 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
299d70ad2d
commit
7b0daf5cca
@ -334,7 +334,7 @@ AudioMixer::FormatChanged(const media_source &producer, const media_destination
|
||||
|
||||
// tell core about format change
|
||||
fCore->Lock();
|
||||
fCore->InputFormatChanged(consumer.id, &format);
|
||||
fCore->InputFormatChanged(consumer.id, format.u.raw_audio);
|
||||
fCore->Unlock();
|
||||
|
||||
return B_OK;
|
||||
@ -420,7 +420,7 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
|
||||
|
||||
// apply format change
|
||||
fCore->Lock();
|
||||
fCore->OutputFormatChanged(io_format);
|
||||
fCore->OutputFormatChanged(io_format->u.raw_audio);
|
||||
fCore->Unlock();
|
||||
|
||||
return B_OK;
|
||||
@ -617,7 +617,7 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
||||
fCore->Output()->MediaOutput().destination = dest;
|
||||
|
||||
fCore->EnableOutput(true);
|
||||
fCore->SetTimeSource(TimeSource()->ID());
|
||||
fCore->SetTimeSource(TimeSource());
|
||||
fCore->SetOutputBufferGroup(fBufferGroup);
|
||||
fCore->Unlock();
|
||||
}
|
||||
@ -710,7 +710,7 @@ AudioMixer::SetTimeSource(BTimeSource * time_source)
|
||||
{
|
||||
printf("AudioMixer::SetTimeSource: timesource is now %ld\n", time_source->ID());
|
||||
fCore->Lock();
|
||||
fCore->SetTimeSource(time_source->ID());
|
||||
fCore->SetTimeSource(time_source);
|
||||
fCore->Unlock();
|
||||
}
|
||||
|
||||
|
@ -1,30 +1,46 @@
|
||||
#include <RealtimeAlloc.h>
|
||||
#include <MediaNode.h>
|
||||
#include <TimeSource.h>
|
||||
#include <Buffer.h>
|
||||
#include <BufferGroup.h>
|
||||
#include "MixerCore.h"
|
||||
#include "MixerInput.h"
|
||||
#include "MixerOutput.h"
|
||||
#include "MixerUtils.h"
|
||||
#include "Debug.h"
|
||||
|
||||
#define MAX_OUTPUT_BUFFER_LENGTH 50000LL /* 50 ms */
|
||||
#define DOUBLE_RATE_MIXING 1
|
||||
|
||||
#define ASSERT_LOCKED() if (fLocker->IsLocked()) {} else debugger("core not locked, meltdown occurred")
|
||||
|
||||
/* Mixer channels are identified by a type number, each type number corresponds
|
||||
* to the one of the channel masks of enum media_multi_channels.
|
||||
*
|
||||
* The mixer buffer uses either the same frame rate and same count of frames as the
|
||||
* output buffer, or the double frame rate and frame count.
|
||||
*
|
||||
* All mixer input ring buffers must be an exact multiple of the mixer buffer size,
|
||||
* so that we do not get any buffer wrap around during reading from the input buffers.
|
||||
* The mixer input is told by constructor (or after a format change by SetMixBufferFormat())
|
||||
* of the current mixer buffer propertys, and must allocate a buffer that is an exact multiple,
|
||||
*/
|
||||
|
||||
|
||||
MixerCore::MixerCore()
|
||||
: fLocker(new BLocker),
|
||||
fOutputBufferLength(MAX_OUTPUT_BUFFER_LENGTH),
|
||||
fInputBufferLength(3 * MAX_OUTPUT_BUFFER_LENGTH),
|
||||
fMixFrameRate(96000),
|
||||
fMixStartTime(0),
|
||||
fInputs(new BList),
|
||||
fOutput(0),
|
||||
fNextInputID(1),
|
||||
fRunning(false)
|
||||
fRunning(false),
|
||||
fMixBuffer(0),
|
||||
fMixBufferFrameRate(0),
|
||||
fMixBufferFrameCount(0),
|
||||
fMixBufferChannelTypes(0),
|
||||
fMixBufferChannelCount(0),
|
||||
fDoubleRateMixing(DOUBLE_RATE_MIXING),
|
||||
fLastMixStartTime(0),
|
||||
fBufferGroup(0),
|
||||
fTimeSource(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -32,13 +48,21 @@ MixerCore::~MixerCore()
|
||||
{
|
||||
delete fLocker;
|
||||
delete fInputs;
|
||||
|
||||
if (fMixBuffer)
|
||||
rtm_free(fMixBuffer);
|
||||
|
||||
if (fTimeSource)
|
||||
fTimeSource->Release();
|
||||
|
||||
delete fMixBufferChannelTypes;
|
||||
}
|
||||
|
||||
bool
|
||||
MixerCore::AddInput(const media_input &input)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
fInputs->AddItem(new MixerInput(this, input, fMixFrameRate, frames_for_duration(fMixFrameRate, fInputBufferLength), fMixStartTime));
|
||||
fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -49,6 +73,8 @@ MixerCore::AddOutput(const media_output &output)
|
||||
if (fOutput)
|
||||
return false;
|
||||
fOutput = new MixerOutput(this, output);
|
||||
// the output format might have been adjusted inside MixerOutput
|
||||
OutputFormatChanged(fOutput->MediaOutput().format.u.raw_audio);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -114,36 +140,77 @@ MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness)
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::InputFormatChanged(int32 inputID, const media_format *format)
|
||||
MixerCore::InputFormatChanged(int32 inputID, const media_multi_audio_format &format)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
printf("MixerCore::InputFormatChanged not handled\n");
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::OutputFormatChanged(const media_format *format)
|
||||
MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
|
||||
// void ChangeMixBufferFormat(float samplerate, int32 frames, int32 channelcount, uint32 channel_mask);
|
||||
|
||||
if (fMixBuffer)
|
||||
rtm_free(fMixBuffer);
|
||||
|
||||
delete fMixBufferChannelTypes;
|
||||
|
||||
fMixBufferFrameRate = (int32)format.frame_rate;
|
||||
fMixBufferFrameCount = frames_per_buffer(format);
|
||||
if (fDoubleRateMixing) {
|
||||
fMixBufferFrameRate *= 2;
|
||||
fMixBufferFrameCount *= 2;
|
||||
}
|
||||
fMixBufferChannelCount = format.channel_count;
|
||||
fMixBufferChannelTypes = new int32 [format.channel_count];
|
||||
|
||||
for (int i = 0; i < fMixBufferChannelCount; i++)
|
||||
fMixBufferChannelTypes[i] = ChannelMaskToChannelType(GetChannelMask(i, format.channel_mask));
|
||||
|
||||
fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount);
|
||||
|
||||
printf("MixerCore::OutputFormatChanged:\n");
|
||||
printf(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate);
|
||||
printf(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount);
|
||||
printf(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount);
|
||||
for (int i = 0; i < fMixBufferChannelCount; i++)
|
||||
printf(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]);
|
||||
|
||||
MixerInput *input;
|
||||
for (int i = 0; (input = Input(i)); i++)
|
||||
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime);
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::SetOutputBufferGroup(BBufferGroup *group)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
|
||||
fBufferGroup = group;
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::SetTimeSource(media_node_id id)
|
||||
MixerCore::SetTimeSource(BTimeSource *ts)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
|
||||
if (fTimeSource)
|
||||
fTimeSource->Release();
|
||||
|
||||
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
|
||||
fLastMixStartTime = fTimeSource->Now();
|
||||
|
||||
MixerInput *input;
|
||||
for (int i = 0; (input = Input(i)); i++)
|
||||
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime);
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::EnableOutput(bool enabled)
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
printf("MixerCore::EnableOutput %d\n", enabled);
|
||||
}
|
||||
|
||||
void
|
||||
@ -170,7 +237,9 @@ uint32
|
||||
MixerCore::OutputBufferSize()
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
return 1;
|
||||
|
||||
uint32 size = sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount;
|
||||
return fDoubleRateMixing ? (size / 2) : size;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -180,11 +249,6 @@ MixerCore::IsStarted()
|
||||
return fRunning;
|
||||
}
|
||||
|
||||
void
|
||||
MixerCore::OutputBufferLengthChanged(bigtime_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void BufferReceived(BBuffer *buffer, bigtime_t lateness);
|
||||
@ -225,4 +289,4 @@ AudioMixer::MixThread()
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
*/
|
||||
|
@ -28,11 +28,11 @@ public:
|
||||
|
||||
void BufferReceived(BBuffer *buffer, bigtime_t lateness);
|
||||
|
||||
void InputFormatChanged(int32 inputID, const media_format *format);
|
||||
void OutputFormatChanged(const media_format *format);
|
||||
void InputFormatChanged(int32 inputID, const media_multi_audio_format &format);
|
||||
void OutputFormatChanged(const media_multi_audio_format &format);
|
||||
|
||||
void SetOutputBufferGroup(BBufferGroup *group);
|
||||
void SetTimeSource(media_node_id id);
|
||||
void SetTimeSource(BTimeSource *ts);
|
||||
void EnableOutput(bool enabled);
|
||||
void Start(bigtime_t time);
|
||||
void Stop();
|
||||
@ -43,7 +43,6 @@ public:
|
||||
uint32 OutputChannelCount();
|
||||
|
||||
private:
|
||||
void OutputBufferLengthChanged(bigtime_t length);
|
||||
// handle mixing in separate thread
|
||||
// not implemented (yet)
|
||||
|
||||
@ -54,15 +53,21 @@ private:
|
||||
private:
|
||||
BLocker *fLocker;
|
||||
|
||||
bigtime_t fOutputBufferLength;
|
||||
bigtime_t fInputBufferLength;
|
||||
float fMixFrameRate;
|
||||
bigtime_t fMixStartTime;
|
||||
|
||||
BList *fInputs;
|
||||
MixerOutput *fOutput;
|
||||
int32 fNextInputID;
|
||||
bool fRunning;
|
||||
|
||||
float *fMixBuffer;
|
||||
int32 fMixBufferFrameRate;
|
||||
int32 fMixBufferFrameCount;
|
||||
int32 fMixBufferChannelCount;
|
||||
int32 *fMixBufferChannelTypes; //array
|
||||
bool fDoubleRateMixing;
|
||||
bigtime_t fLastMixStartTime;
|
||||
|
||||
BBufferGroup *fBufferGroup;
|
||||
BTimeSource *fTimeSource;
|
||||
};
|
||||
|
||||
|
||||
@ -77,4 +82,3 @@ inline void MixerCore::Unlock()
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
#include <MediaNode.h>
|
||||
#include <Buffer.h>
|
||||
#include <RealtimeAlloc.h>
|
||||
#include <string.h>
|
||||
#include "MixerInput.h"
|
||||
#include "MixerCore.h"
|
||||
#include "MixerUtils.h"
|
||||
#include "Resampler.h"
|
||||
#include "ByteSwap.h"
|
||||
#include "debug.h"
|
||||
|
||||
template<class t> const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; }
|
||||
|
||||
MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampleRate, int32 mixFramesCount, bigtime_t mixStartTime)
|
||||
: fCore(core),
|
||||
fInput(input),
|
||||
@ -17,9 +21,10 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampl
|
||||
fMixerChannelInfo(0),
|
||||
fMixerChannelCount(0),
|
||||
fMixBuffer(0),
|
||||
fMixBufferSampleRate(0),
|
||||
fMixBufferFrames(0),
|
||||
fMixBufferFrameRate(0),
|
||||
fMixBufferFrameCount(0),
|
||||
fMixBufferStartTime(0),
|
||||
fResampler(0),
|
||||
fUserOverridesChannelDesignations(false)
|
||||
{
|
||||
fix_multiaudio_format(&fInput.format.u.raw_audio);
|
||||
@ -47,6 +52,11 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampl
|
||||
fInputChannelInfo[i].designations = 0; // will be set by UpdateChannelDesignations()
|
||||
fInputChannelInfo[i].gain = 1.0;
|
||||
}
|
||||
|
||||
// create resamplers
|
||||
fResampler = new Resampler * [fInputChannelCount];
|
||||
for (int i = 0; i < fInputChannelCount; i++)
|
||||
fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, media_raw_audio_format::B_AUDIO_FLOAT);
|
||||
|
||||
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels()
|
||||
|
||||
@ -69,6 +79,11 @@ MixerInput::~MixerInput()
|
||||
rtm_free(fMixBuffer);
|
||||
delete [] fInputChannelInfo;
|
||||
delete [] fMixerChannelInfo;
|
||||
|
||||
// delete resamplers
|
||||
for (int i = 0; i < fInputChannelCount; i++)
|
||||
delete fResampler[i];
|
||||
delete [] fResampler;
|
||||
}
|
||||
|
||||
void
|
||||
@ -88,8 +103,54 @@ MixerInput::BufferReceived(BBuffer *buffer)
|
||||
if (fInputByteSwap)
|
||||
fInputByteSwap->Swap(data, size);
|
||||
|
||||
int32 offset = frames_for_duration(fMixBufferFrameRate, start - fMixBufferStartTime) % fMixBufferFrameCount;
|
||||
|
||||
printf("MixerInput::BufferReceived: mix buffer start %14Ld, buffer start %14Ld, offset %6d\n", fMixBufferStartTime, start, offset);
|
||||
|
||||
int in_frames = frames_per_buffer(fInput.format.u.raw_audio); // XXX use size
|
||||
int out_frames = (int)((in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate); // XXX losing fractions
|
||||
|
||||
printf("mix buffer start %14Ld, buffer start %14Ld\n", fMixBufferStartTime, start);
|
||||
if (offset + out_frames > fMixBufferFrameCount) {
|
||||
|
||||
int out_frames1 = fMixBufferFrameCount - offset;
|
||||
int out_frames2 = out_frames - out_frames1;
|
||||
int in_frames1 = (out_frames1 * in_frames) / out_frames;
|
||||
int in_frames2 = in_frames - in_frames1;
|
||||
|
||||
printf(" in_frames %5d, out_frames %5d, in_frames1 %5d, out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n",
|
||||
in_frames, out_frames, in_frames1, out_frames1, in_frames2, out_frames2);
|
||||
|
||||
for (int i = 0; i < fInputChannelCount; i++) {
|
||||
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_frame(fInput.format.u.raw_audio),
|
||||
fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio),
|
||||
in_frames1,
|
||||
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount),
|
||||
fInputChannelCount * sizeof(float),
|
||||
out_frames1,
|
||||
fInputChannelInfo[i].gain);
|
||||
|
||||
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_frame(fInput.format.u.raw_audio),
|
||||
fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio),
|
||||
in_frames2,
|
||||
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base),
|
||||
fInputChannelCount * sizeof(float),
|
||||
out_frames2,
|
||||
fInputChannelInfo[i].gain);
|
||||
}
|
||||
} else {
|
||||
|
||||
printf(" in_frames %5d, out_frames %5d\n", in_frames, out_frames);
|
||||
|
||||
for (int i = 0; i < fInputChannelCount; i++) {
|
||||
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_frame(fInput.format.u.raw_audio),
|
||||
fInputChannelCount * bytes_per_frame(fInput.format.u.raw_audio),
|
||||
in_frames,
|
||||
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount),
|
||||
fInputChannelCount * sizeof(float),
|
||||
out_frames,
|
||||
fInputChannelInfo[i].gain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
media_input &
|
||||
@ -303,11 +364,12 @@ MixerInput::GetMixerChannelCount()
|
||||
}
|
||||
|
||||
void
|
||||
MixerInput::GetMixerChannelInfo(int channel, const float **buffer, uint32 *sample_offset, int *type, float *gain)
|
||||
MixerInput::GetMixerChannelInfo(int channel, int64 framepos, const float **buffer, uint32 *sample_offset, int *type, float *gain)
|
||||
{
|
||||
ASSERT(fMixBuffer);
|
||||
ASSERT(channel >= 0 && channel < fMixerChannelCount);
|
||||
*buffer = fMixerChannelInfo[channel].buffer_base;
|
||||
int32 offset = framepos % fMixBufferFrameCount;
|
||||
*buffer = reinterpret_cast<float *>(reinterpret_cast<char *>(fMixerChannelInfo[channel].buffer_base) + (offset * sizeof(float) * fInputChannelCount));
|
||||
*sample_offset = sizeof(float) * fInputChannelCount;
|
||||
*type = fMixerChannelInfo[channel].type;
|
||||
*gain = fMixerChannelInfo[channel].gain;
|
||||
@ -332,16 +394,35 @@ MixerInput::GetMixerChannelGain(int channel)
|
||||
}
|
||||
|
||||
void
|
||||
MixerInput::SetMixBufferFormat(float samplerate, int32 frames, bigtime_t starttime)
|
||||
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttime)
|
||||
{
|
||||
fMixBufferSampleRate = samplerate;
|
||||
fMixBufferFrames = frames;
|
||||
fMixBufferFrameRate = framerate;
|
||||
fMixBufferStartTime = starttime;
|
||||
|
||||
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld, starttime %Ld\n", framerate, frames, starttime);
|
||||
|
||||
// make fMixBufferFrameCount an integral multiple of frames,
|
||||
// but at least 3 times duration of our input buffer
|
||||
// and at least 2 times duration of the output buffer
|
||||
bigtime_t inputBufferLength = duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio));
|
||||
bigtime_t outputBufferLength = duration_for_frames(framerate, frames);
|
||||
bigtime_t mixerBufferLength = max_c(3 * inputBufferLength, 2 * outputBufferLength);
|
||||
int temp = frames_for_duration(framerate, mixerBufferLength);
|
||||
fMixBufferFrameCount = ((temp / frames) + 1) * frames;
|
||||
|
||||
printf(" inputBufferLength %10Ld\n", inputBufferLength);
|
||||
printf(" outputBufferLength %10Ld\n", outputBufferLength);
|
||||
printf(" mixerBufferLength %10Ld\n", mixerBufferLength);
|
||||
printf(" fMixBufferFrameCount %10ld\n", fMixBufferFrameCount);
|
||||
|
||||
if (fMixBuffer)
|
||||
rtm_free(fMixBuffer);
|
||||
fMixBuffer = (float *)rtm_alloc(NULL, sizeof(float) * fInputChannelCount * fMixBufferFrames);
|
||||
int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
|
||||
fMixBuffer = (float *)rtm_alloc(NULL, size);
|
||||
ASSERT(fMixBuffer);
|
||||
|
||||
memset(fMixBuffer, 0, size);
|
||||
|
||||
for (int i = 0; i < fInputChannelCount; i++)
|
||||
fInputChannelInfo[i].buffer_base = &fMixBuffer[i * fMixBufferFrames];
|
||||
fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
class MixerCore;
|
||||
class ByteSwap;
|
||||
class Resampler;
|
||||
|
||||
class MixerInput
|
||||
{
|
||||
@ -17,7 +18,7 @@ public:
|
||||
media_input & MediaInput();
|
||||
|
||||
uint32 GetMixerChannelCount();
|
||||
void GetMixerChannelInfo(int channel, const float **buffer, uint32 *sample_offset, int *type, float *gain);
|
||||
void GetMixerChannelInfo(int channel, int64 framepos, const float **buffer, uint32 *sample_offset, int *type, float *gain);
|
||||
void SetMixerChannelGain(int channel, float gain);
|
||||
float GetMixerChannelGain(int channel);
|
||||
|
||||
@ -30,7 +31,7 @@ public:
|
||||
|
||||
protected:
|
||||
friend class MixerCore;
|
||||
void SetMixBufferFormat(float samplerate, int32 frames, bigtime_t starttime);
|
||||
void SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttime);
|
||||
|
||||
private:
|
||||
void UpdateChannelDesignations();
|
||||
@ -62,9 +63,11 @@ private:
|
||||
|
||||
float *fMixBuffer;
|
||||
|
||||
float fMixBufferSampleRate;
|
||||
uint32 fMixBufferFrames;
|
||||
float fMixBufferFrameRate;
|
||||
uint32 fMixBufferFrameCount;
|
||||
bigtime_t fMixBufferStartTime;
|
||||
|
||||
Resampler **fResampler; // array
|
||||
|
||||
bool fUserOverridesChannelDesignations;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user