multiple bugfixes, but still many pops in output audio stream
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3725 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
#include "MixerCore.h"
|
#include "MixerCore.h"
|
||||||
#include "MixerInput.h"
|
#include "MixerInput.h"
|
||||||
#include "MixerOutput.h"
|
#include "MixerOutput.h"
|
||||||
|
#include "MixerUtils.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#define USE_MEDIA_FORMAT_WORKAROUND 1
|
#define USE_MEDIA_FORMAT_WORKAROUND 1
|
||||||
@@ -334,6 +335,8 @@ AudioMixer::FormatChanged(const media_source &producer, const media_destination
|
|||||||
{
|
{
|
||||||
// at some point in the future (indicated by change_tag and RequestCompleted()),
|
// at some point in the future (indicated by change_tag and RequestCompleted()),
|
||||||
// we will receive buffers in a different format
|
// we will receive buffers in a different format
|
||||||
|
|
||||||
|
printf("AudioMixer::FormatChanged\n");
|
||||||
|
|
||||||
if (consumer.port != ControlPort() || consumer.id == 0)
|
if (consumer.port != ControlPort() || consumer.id == 0)
|
||||||
return B_MEDIA_BAD_DESTINATION;
|
return B_MEDIA_BAD_DESTINATION;
|
||||||
@@ -400,7 +403,12 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
|
|||||||
// another format, we need to check if the format is acceptable and
|
// another format, we need to check if the format is acceptable and
|
||||||
// remove any wildcards before returning OK.
|
// remove any wildcards before returning OK.
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
fCore->Lock();
|
fCore->Lock();
|
||||||
|
|
||||||
|
printf("AudioMixer::FormatChangeRequested\n");
|
||||||
|
|
||||||
MixerOutput *output = fCore->Output();
|
MixerOutput *output = fCore->Output();
|
||||||
if (!output) {
|
if (!output) {
|
||||||
ERROR("AudioMixer::FormatChangeRequested: no output\n");
|
ERROR("AudioMixer::FormatChangeRequested: no output\n");
|
||||||
@@ -411,8 +419,15 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (destination != output->MediaOutput().destination) {
|
if (destination != output->MediaOutput().destination) {
|
||||||
ERROR("AudioMixer::FormatChangeRequested: wrong output destination\n");
|
ERROR("AudioMixer::FormatChangeRequested: wrong output destination (port %ld, id %ld), our is (port %ld, id %ld)\n", destination.port, destination.id, output->MediaOutput().destination.port, output->MediaOutput().destination.id);
|
||||||
goto err;
|
if (destination.port == output->MediaOutput().destination.port && destination.id == output->MediaOutput().destination.id + 1) {
|
||||||
|
ERROR("AudioMixer::FormatChangeRequested: this might be the broken R5 multi audio add-on\n");
|
||||||
|
goto err;
|
||||||
|
// fCore->Unlock();
|
||||||
|
// return B_OK;
|
||||||
|
} else {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (io_format->type != B_MEDIA_RAW_AUDIO && io_format->type != B_MEDIA_UNKNOWN_TYPE) {
|
if (io_format->type != B_MEDIA_RAW_AUDIO && io_format->type != B_MEDIA_UNKNOWN_TYPE) {
|
||||||
ERROR("AudioMixer::FormatChangeRequested: wrong format type\n");
|
ERROR("AudioMixer::FormatChangeRequested: wrong format type\n");
|
||||||
@@ -426,11 +441,34 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
|
|||||||
io_format->SpecializeTo(&fDefaultFormat);
|
io_format->SpecializeTo(&fDefaultFormat);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// apply format change
|
media_node_id id;
|
||||||
fCore->Lock();
|
FindLatencyFor(destination, &fDownstreamLatency, &id);
|
||||||
fCore->OutputFormatChanged(io_format->u.raw_audio);
|
printf("AudioMixer: Downstream Latency is %Ld usecs\n", fDownstreamLatency);
|
||||||
fCore->Unlock();
|
|
||||||
|
// SetDuration of one buffer
|
||||||
|
SetBufferDuration(buffer_duration(io_format->u.raw_audio));
|
||||||
|
printf("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
|
||||||
|
|
||||||
|
// Our internal latency is at least the length of a full output buffer
|
||||||
|
fInternalLatency = bigtime_t(1.2 * BufferDuration());
|
||||||
|
printf("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
|
||||||
|
|
||||||
|
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||||
|
|
||||||
|
//printf("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
|
||||||
|
//SendLatencyChange(source, destination, EventLatency());
|
||||||
|
|
||||||
|
delete fBufferGroup;
|
||||||
|
fBufferGroup = CreateBufferGroup();
|
||||||
|
fCore->SetOutputBufferGroup(fBufferGroup);
|
||||||
|
|
||||||
|
// apply latency change
|
||||||
|
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
|
||||||
|
|
||||||
|
// apply format change
|
||||||
|
fCore->OutputFormatChanged(io_format->u.raw_audio);
|
||||||
|
|
||||||
|
fCore->Unlock();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -473,6 +511,7 @@ AudioMixer::DisposeOutputCookie(int32 cookie)
|
|||||||
status_t
|
status_t
|
||||||
AudioMixer::SetBufferGroup(const media_source &for_source, BBufferGroup *newGroup)
|
AudioMixer::SetBufferGroup(const media_source &for_source, BBufferGroup *newGroup)
|
||||||
{
|
{
|
||||||
|
printf("#############################AudioMixer::SetBufferGroup\n");
|
||||||
// the downstream consumer (soundcard) node asks us to use another
|
// the downstream consumer (soundcard) node asks us to use another
|
||||||
// BBufferGroup (might be NULL). We only have one output (id 0)
|
// BBufferGroup (might be NULL). We only have one output (id 0)
|
||||||
if (for_source.port != ControlPort() || for_source.id != 0)
|
if (for_source.port != ControlPort() || for_source.id != 0)
|
||||||
@@ -590,19 +629,18 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
|||||||
printf("AudioMixer: Downstream Latency is %Ld usecs\n", fDownstreamLatency);
|
printf("AudioMixer: Downstream Latency is %Ld usecs\n", fDownstreamLatency);
|
||||||
|
|
||||||
// SetDuration of one buffer
|
// SetDuration of one buffer
|
||||||
SetBufferDuration((1000000 * (format.u.raw_audio.buffer_size / ((format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * format.u.raw_audio.channel_count))) / format.u.raw_audio.frame_rate);
|
SetBufferDuration(buffer_duration(format.u.raw_audio));
|
||||||
|
|
||||||
printf("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
|
printf("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration());
|
||||||
|
|
||||||
// Our internal latency is at least the length of a full output buffer
|
// Our internal latency is at least the length of a full output buffer
|
||||||
// XXX we use two for now
|
fInternalLatency = bigtime_t(1.2 * BufferDuration());
|
||||||
fInternalLatency = 2 * BufferDuration();
|
|
||||||
printf("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
|
printf("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency);
|
||||||
|
|
||||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||||
|
|
||||||
printf("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
|
//printf("AudioMixer: SendLatencyChange %Ld\n", EventLatency());
|
||||||
SendLatencyChange(source, dest, EventLatency());
|
//SendLatencyChange(source, dest, EventLatency());
|
||||||
|
|
||||||
// Set up the buffer group for our connection, as long as nobody handed us a
|
// Set up the buffer group for our connection, as long as nobody handed us a
|
||||||
// buffer group (via SetBufferGroup()) prior to this. That can happen, for example,
|
// buffer group (via SetBufferGroup()) prior to this. That can happen, for example,
|
||||||
@@ -625,7 +663,7 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
|||||||
fCore->Output()->MediaOutput().destination = dest;
|
fCore->Output()->MediaOutput().destination = dest;
|
||||||
|
|
||||||
fCore->EnableOutput(true);
|
fCore->EnableOutput(true);
|
||||||
fCore->SetTimeSource(TimeSource());
|
fCore->SetTimingInfo(TimeSource(), fDownstreamLatency);
|
||||||
fCore->SetOutputBufferGroup(fBufferGroup);
|
fCore->SetOutputBufferGroup(fBufferGroup);
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
}
|
}
|
||||||
@@ -709,8 +747,8 @@ void
|
|||||||
AudioMixer::NodeRegistered()
|
AudioMixer::NodeRegistered()
|
||||||
{
|
{
|
||||||
Run();
|
Run();
|
||||||
SetPriority(8);
|
|
||||||
// SetPriority(120);
|
// SetPriority(120);
|
||||||
|
SetPriority(12);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -718,7 +756,7 @@ AudioMixer::SetTimeSource(BTimeSource * time_source)
|
|||||||
{
|
{
|
||||||
printf("AudioMixer::SetTimeSource: timesource is now %ld\n", time_source->ID());
|
printf("AudioMixer::SetTimeSource: timesource is now %ld\n", time_source->ID());
|
||||||
fCore->Lock();
|
fCore->Lock();
|
||||||
fCore->SetTimeSource(time_source);
|
fCore->SetTimingInfo(time_source, fDownstreamLatency);
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,7 +818,7 @@ AudioMixer::CreateBufferGroup()
|
|||||||
int32 count = int32(fDownstreamLatency / BufferDuration()) + 2;
|
int32 count = int32(fDownstreamLatency / BufferDuration()) + 2;
|
||||||
|
|
||||||
fCore->Lock();
|
fCore->Lock();
|
||||||
uint32 size = fCore->OutputBufferSize();
|
uint32 size = fCore->Output()->MediaOutput().format.u.raw_audio.buffer_size;
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
|
|
||||||
printf("AudioMixer: allocating %ld buffers of %ld bytes each\n", count, size);
|
printf("AudioMixer: allocating %ld buffers of %ld bytes each\n", count, size);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#include "Resampler.h"
|
#include "Resampler.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
#define DOUBLE_RATE_MIXING 0
|
#define DOUBLE_RATE_MIXING 1
|
||||||
|
|
||||||
#define ASSERT_LOCKED() if (fLocker->IsLocked()) {} else debugger("core not locked, meltdown occurred")
|
#define ASSERT_LOCKED() if (fLocker->IsLocked()) {} else debugger("core not locked, meltdown occurred")
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ MixerCore::MixerCore(AudioMixer *node)
|
|||||||
fMixBufferChannelTypes(0),
|
fMixBufferChannelTypes(0),
|
||||||
fMixBufferChannelCount(0),
|
fMixBufferChannelCount(0),
|
||||||
fDoubleRateMixing(DOUBLE_RATE_MIXING),
|
fDoubleRateMixing(DOUBLE_RATE_MIXING),
|
||||||
fMixStartTime(0),
|
fDownstreamLatency(1),
|
||||||
fNode(node),
|
fNode(node),
|
||||||
fBufferGroup(0),
|
fBufferGroup(0),
|
||||||
fTimeSource(0),
|
fTimeSource(0),
|
||||||
@@ -80,7 +80,7 @@ bool
|
|||||||
MixerCore::AddInput(const media_input &input)
|
MixerCore::AddInput(const media_input &input)
|
||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount, fMixStartTime));
|
fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ MixerCore::AddOutput(const media_output &output)
|
|||||||
return false;
|
return false;
|
||||||
fOutput = new MixerOutput(this, output);
|
fOutput = new MixerOutput(this, output);
|
||||||
// the output format might have been adjusted inside MixerOutput
|
// the output format might have been adjusted inside MixerOutput
|
||||||
OutputFormatChanged(fOutput->MediaOutput().format.u.raw_audio);
|
ApplyOutputFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -169,6 +169,25 @@ MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
|
|||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
|
|
||||||
|
bool wasrunning = fRunning;
|
||||||
|
|
||||||
|
if (wasrunning)
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
fOutput->ChangeFormat(format);
|
||||||
|
ApplyOutputFormat();
|
||||||
|
|
||||||
|
if (wasrunning)
|
||||||
|
Start(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerCore::ApplyOutputFormat()
|
||||||
|
{
|
||||||
|
ASSERT_LOCKED();
|
||||||
|
|
||||||
|
media_multi_audio_format format = fOutput->MediaOutput().format.u.raw_audio;
|
||||||
|
|
||||||
if (fMixBuffer)
|
if (fMixBuffer)
|
||||||
rtm_free(fMixBuffer);
|
rtm_free(fMixBuffer);
|
||||||
|
|
||||||
@@ -209,7 +228,7 @@ MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
|
|||||||
|
|
||||||
MixerInput *input;
|
MixerInput *input;
|
||||||
for (int i = 0; (input = Input(i)); i++)
|
for (int i = 0; (input = Input(i)); i++)
|
||||||
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fMixStartTime);
|
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -221,7 +240,7 @@ MixerCore::SetOutputBufferGroup(BBufferGroup *group)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MixerCore::SetTimeSource(BTimeSource *ts)
|
MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency)
|
||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
|
|
||||||
@@ -229,13 +248,9 @@ MixerCore::SetTimeSource(BTimeSource *ts)
|
|||||||
fTimeSource->Release();
|
fTimeSource->Release();
|
||||||
|
|
||||||
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
|
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
|
||||||
// fMixStartTime = fTimeSource->Now();
|
fDownstreamLatency = downstream_latency;
|
||||||
|
|
||||||
printf("MixerCore::SetTimeSource, now = %Ld\n", fTimeSource->Now());
|
printf("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n", fTimeSource->Now(), fDownstreamLatency);
|
||||||
|
|
||||||
// MixerInput *input;
|
|
||||||
// for (int i = 0; (input = Input(i)); i++)
|
|
||||||
// input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fMixStartTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -279,15 +294,6 @@ MixerCore::Stop()
|
|||||||
fRunning = false;
|
fRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
|
||||||
MixerCore::OutputBufferSize()
|
|
||||||
{
|
|
||||||
ASSERT_LOCKED();
|
|
||||||
|
|
||||||
uint32 size = sizeof(float) * fMixBufferFrameCount * fMixBufferChannelCount;
|
|
||||||
return fDoubleRateMixing ? (size / 2) : size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MixerCore::IsStarted()
|
MixerCore::IsStarted()
|
||||||
{
|
{
|
||||||
@@ -308,83 +314,96 @@ MixerCore::MixThread()
|
|||||||
bigtime_t event_time;
|
bigtime_t event_time;
|
||||||
bigtime_t time_base;
|
bigtime_t time_base;
|
||||||
bigtime_t latency;
|
bigtime_t latency;
|
||||||
|
bigtime_t start;
|
||||||
int64 frame_base;
|
int64 frame_base;
|
||||||
int64 frame_pos;
|
int64 frame_pos;
|
||||||
|
|
||||||
latency = 30000;
|
// The broken BeOS R5 multiaudio node starts with time 0,
|
||||||
|
// then publishes negative times for about 50ms, publishes 0
|
||||||
while (fTimeSource->Now() <= 0) {
|
// again until it finally reaches time values > 0
|
||||||
printf("delay MixThread start, now %Ld\n", (int64)fTimeSource->Now());
|
start = fTimeSource->Now();
|
||||||
|
while (start <= 0) {
|
||||||
|
printf("MixerCore: delaying MixThread start, timesource is at %Ld\n", start);
|
||||||
snooze(1000);
|
snooze(1000);
|
||||||
|
start = fTimeSource->Now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
latency = bigtime_t(0.2 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio));
|
||||||
|
|
||||||
printf("starting MixThread, now %Ld\n", (int64)fTimeSource->Now());
|
printf("MixerCore: starting MixThread at %Ld with latency %Ld and downstream latency %Ld\n", start, latency, fDownstreamLatency);
|
||||||
|
|
||||||
/* We must read from the input buffer at a position (pos) that is always a multiple of fMixBufferFrameCount.
|
/* We must read from the input buffer at a position (pos) that is always a multiple of fMixBufferFrameCount.
|
||||||
*/
|
*/
|
||||||
int64 temp = frames_for_duration(fMixBufferFrameRate, fTimeSource->Now() - fMixStartTime);
|
int64 temp = frames_for_duration(fMixBufferFrameRate, start );
|
||||||
frame_base = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount;
|
frame_base = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount;
|
||||||
time_base = duration_for_frames(fMixBufferFrameRate, frame_base) + fMixStartTime;
|
time_base = duration_for_frames(fMixBufferFrameRate, frame_base);
|
||||||
|
|
||||||
printf("starting MixThread, now %Ld, time_base %Ld, fMixStartTime %Ld, frame_base %Ld\n", fTimeSource->Now(), time_base, fMixStartTime, frame_base);
|
printf("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
|
||||||
|
|
||||||
event_time = time_base;
|
event_time = time_base;
|
||||||
frame_pos = 0;
|
frame_pos = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
status_t rv;
|
status_t rv;
|
||||||
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, latency));
|
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, latency + fDownstreamLatency));
|
||||||
if (rv == B_INTERRUPTED)
|
if (rv == B_INTERRUPTED)
|
||||||
continue;
|
continue;
|
||||||
if (rv != B_TIMED_OUT && rv < B_OK)
|
if (rv != B_TIMED_OUT && rv < B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!LockWithTimeout(10000))
|
||||||
|
continue;
|
||||||
|
|
||||||
// mix all data from all inputs into the mix buffer
|
// mix all data from all inputs into the mix buffer
|
||||||
ASSERT((frame_base + frame_pos) % fMixBufferFrameCount == 0);
|
ASSERT((frame_base + frame_pos) % fMixBufferFrameCount == 0);
|
||||||
|
|
||||||
// printf("create new buffer event at %Ld, reading input frames at %Ld\n", event_time, frame_base + frame_pos);
|
// printf("create new buffer event at %Ld, reading input frames at %Ld\n", event_time, frame_base + frame_pos);
|
||||||
/*
|
|
||||||
for (int i = 0; i < fMixBufferChannelCount; i++) {
|
// XXX this is a test, copy the the left and right channel from input 1 or 0
|
||||||
for (int j = 0; j < fMixBufferFrameCount; j++) {
|
|
||||||
fMixBuffer[(i * fMixBufferChannelCount)+j] = (i*j) / (float)(fMixBufferChannelCount * fMixBufferFrameCount);
|
if (fMixBufferChannelCount > 2)
|
||||||
}
|
memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
|
||||||
}
|
|
||||||
*/
|
|
||||||
// XXX this is a test, copy the the left channel from input 1 or 0
|
|
||||||
Lock();
|
|
||||||
|
|
||||||
MixerInput *input = Input(1);
|
MixerInput *input = Input(1);
|
||||||
if (!input)
|
if (!input)
|
||||||
input = Input(0);
|
input = Input(0);
|
||||||
|
|
||||||
if (input) {
|
if (fMixBufferChannelCount > 2 || !input)
|
||||||
const float *buffer;
|
|
||||||
uint32 src_sample_offset;
|
|
||||||
int type;
|
|
||||||
float gain;
|
|
||||||
|
|
||||||
printf("data reading for %15Ld to %15Ld, ", event_time, event_time + duration_for_frames(fMixBufferFrameRate, fMixBufferFrameCount));
|
|
||||||
|
|
||||||
int64 cur_framepos = frame_base + frame_pos;
|
|
||||||
input->GetMixerChannelInfo(0, cur_framepos, &buffer, &src_sample_offset, &type, &gain);
|
|
||||||
|
|
||||||
memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
|
memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float));
|
||||||
|
|
||||||
uint32 dst_sample_offset;
|
if (input) {
|
||||||
|
|
||||||
|
printf("at %10Ld, data reading for %10Ld to %10Ld, ", fTimeSource->Now(), event_time, event_time + duration_for_frames(fMixBufferFrameRate, fMixBufferFrameCount));
|
||||||
|
|
||||||
|
int64 cur_framepos = frame_base + frame_pos;
|
||||||
|
|
||||||
char *src = (char *)buffer;
|
for (int chan = 0; chan < 2; chan++) {
|
||||||
char *dst = (char *)fMixBuffer;
|
|
||||||
dst_sample_offset = fMixBufferChannelCount * sizeof(float);
|
const float *buffer;
|
||||||
|
uint32 src_sample_offset;
|
||||||
|
uint32 dst_sample_offset;
|
||||||
|
int type;
|
||||||
|
float gain;
|
||||||
|
|
||||||
for (int i = 0; i < fMixBufferFrameCount; i++) {
|
input->GetMixerChannelInfo(chan, cur_framepos, &buffer, &src_sample_offset, &type, &gain);
|
||||||
*(float *)dst = *(float *)src;
|
dst_sample_offset = fMixBufferChannelCount * sizeof(float);
|
||||||
dst += dst_sample_offset;
|
|
||||||
src += src_sample_offset;
|
char *src = (char *)buffer;
|
||||||
|
char *dst = (char *)fMixBuffer;
|
||||||
|
|
||||||
|
src += chan * sizeof(float);
|
||||||
|
dst += chan * sizeof(float);
|
||||||
|
|
||||||
|
for (int i = 0; i < fMixBufferFrameCount; i++) {
|
||||||
|
*(float *)dst = *(float *)src;
|
||||||
|
dst += dst_sample_offset;
|
||||||
|
src += src_sample_offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Unlock();
|
|
||||||
|
|
||||||
// request a buffer
|
// request a buffer
|
||||||
BBuffer* buf = fBufferGroup->RequestBuffer(fOutput->MediaOutput().format.u.raw_audio.buffer_size, 10000);
|
BBuffer* buf = fBufferGroup->RequestBuffer(fOutput->MediaOutput().format.u.raw_audio.buffer_size, 5000);
|
||||||
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
|
|
||||||
// copy data from mix buffer into output buffer
|
// copy data from mix buffer into output buffer
|
||||||
@@ -397,6 +416,7 @@ MixerCore::MixThread()
|
|||||||
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
|
frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio),
|
||||||
1.0);
|
1.0);
|
||||||
}
|
}
|
||||||
|
// printf("send buffer, inframes %ld, outframes %ld\n",fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio));
|
||||||
|
|
||||||
// fill in the buffer header
|
// fill in the buffer header
|
||||||
media_header* hdr = buf->Header();
|
media_header* hdr = buf->Header();
|
||||||
@@ -407,13 +427,16 @@ MixerCore::MixThread()
|
|||||||
|
|
||||||
// send the buffer
|
// send the buffer
|
||||||
if (B_OK != fNode->SendBuffer(buf, fOutput->MediaOutput().destination)) {
|
if (B_OK != fNode->SendBuffer(buf, fOutput->MediaOutput().destination)) {
|
||||||
printf("SendBuffer failed\n");
|
printf("MixerCore: #### SendBuffer failed\n");
|
||||||
buf->Recycle();
|
buf->Recycle();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
printf("MixerCore: #### RequestBuffer failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// schedule next event
|
// schedule next event
|
||||||
frame_pos += fMixBufferFrameCount;
|
frame_pos += fMixBufferFrameCount;
|
||||||
event_time = time_base + bigtime_t((1000000LL * frame_pos) / fMixBufferFrameRate);
|
event_time = time_base + bigtime_t((1000000LL * frame_pos) / fMixBufferFrameRate);
|
||||||
|
Unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
MixerOutput *Output();
|
MixerOutput *Output();
|
||||||
|
|
||||||
void Lock();
|
void Lock();
|
||||||
|
bool LockWithTimeout(bigtime_t timeout);
|
||||||
void Unlock();
|
void Unlock();
|
||||||
|
|
||||||
void BufferReceived(BBuffer *buffer, bigtime_t lateness);
|
void BufferReceived(BBuffer *buffer, bigtime_t lateness);
|
||||||
@@ -34,17 +35,17 @@ public:
|
|||||||
void OutputFormatChanged(const media_multi_audio_format &format);
|
void OutputFormatChanged(const media_multi_audio_format &format);
|
||||||
|
|
||||||
void SetOutputBufferGroup(BBufferGroup *group);
|
void SetOutputBufferGroup(BBufferGroup *group);
|
||||||
void SetTimeSource(BTimeSource *ts);
|
void SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency);
|
||||||
void EnableOutput(bool enabled);
|
void EnableOutput(bool enabled);
|
||||||
void Start(bigtime_t time);
|
void Start(bigtime_t time);
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
uint32 OutputBufferSize();
|
|
||||||
bool IsStarted();
|
bool IsStarted();
|
||||||
|
|
||||||
uint32 OutputChannelCount();
|
uint32 OutputChannelCount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ApplyOutputFormat();
|
||||||
static int32 _mix_thread_(void *arg);
|
static int32 _mix_thread_(void *arg);
|
||||||
void MixThread();
|
void MixThread();
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ private:
|
|||||||
int32 fNextInputID;
|
int32 fNextInputID;
|
||||||
bool fRunning;
|
bool fRunning;
|
||||||
|
|
||||||
Resampler **fResampler; // array
|
Resampler **fResampler; // array
|
||||||
|
|
||||||
float *fMixBuffer;
|
float *fMixBuffer;
|
||||||
int32 fMixBufferFrameRate;
|
int32 fMixBufferFrameRate;
|
||||||
@@ -64,7 +65,9 @@ private:
|
|||||||
int32 fMixBufferChannelCount;
|
int32 fMixBufferChannelCount;
|
||||||
int32 *fMixBufferChannelTypes; //array
|
int32 *fMixBufferChannelTypes; //array
|
||||||
bool fDoubleRateMixing;
|
bool fDoubleRateMixing;
|
||||||
bigtime_t fMixStartTime;
|
bigtime_t fDownstreamLatency;
|
||||||
|
|
||||||
|
friend class MixerInput; // XXX debug only
|
||||||
|
|
||||||
AudioMixer *fNode;
|
AudioMixer *fNode;
|
||||||
BBufferGroup *fBufferGroup;
|
BBufferGroup *fBufferGroup;
|
||||||
@@ -79,6 +82,11 @@ inline void MixerCore::Lock()
|
|||||||
fLocker->Lock();
|
fLocker->Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool MixerCore::LockWithTimeout(bigtime_t timeout)
|
||||||
|
{
|
||||||
|
return B_OK == fLocker->LockWithTimeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
inline void MixerCore::Unlock()
|
inline void MixerCore::Unlock()
|
||||||
{
|
{
|
||||||
fLocker->Unlock();
|
fLocker->Unlock();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <Buffer.h>
|
#include <Buffer.h>
|
||||||
#include <RealtimeAlloc.h>
|
#include <RealtimeAlloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <TimeSource.h> // XXX debug only
|
||||||
#include "MixerInput.h"
|
#include "MixerInput.h"
|
||||||
#include "MixerCore.h"
|
#include "MixerCore.h"
|
||||||
#include "MixerUtils.h"
|
#include "MixerUtils.h"
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
|
|
||||||
template<class t> const t & max(const t &t1, const t &t2) { return (t1 > t2) ? t1 : t2; }
|
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 mixFrameRate, int32 mixFrameCount, bigtime_t mixStartTime)
|
MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount)
|
||||||
: fCore(core),
|
: fCore(core),
|
||||||
fInput(input),
|
fInput(input),
|
||||||
fInputByteSwap(0),
|
fInputByteSwap(0),
|
||||||
@@ -23,7 +24,6 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
|
|||||||
fMixBuffer(0),
|
fMixBuffer(0),
|
||||||
fMixBufferFrameRate(0),
|
fMixBufferFrameRate(0),
|
||||||
fMixBufferFrameCount(0),
|
fMixBufferFrameCount(0),
|
||||||
fMixBufferStartTime(0),
|
|
||||||
fResampler(0),
|
fResampler(0),
|
||||||
fUserOverridesChannelDesignations(false)
|
fUserOverridesChannelDesignations(false)
|
||||||
{
|
{
|
||||||
@@ -60,17 +60,19 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrame
|
|||||||
|
|
||||||
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels()
|
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels()
|
||||||
|
|
||||||
SetMixBufferFormat(mixFrameRate, mixFrameCount, mixStartTime);
|
SetMixBufferFormat(mixFrameRate, mixFrameCount);
|
||||||
UpdateChannelDesignations();
|
UpdateChannelDesignations();
|
||||||
UpdateMixerChannels();
|
UpdateMixerChannels();
|
||||||
|
|
||||||
|
|
||||||
// XXX a test:
|
// XXX a test:
|
||||||
|
/*
|
||||||
SetMixerChannelGain(0, 0.222);
|
SetMixerChannelGain(0, 0.222);
|
||||||
SetMixerChannelGain(1, 0.444);
|
SetMixerChannelGain(1, 0.444);
|
||||||
AddInputChannelDesignation(0, B_CHANNEL_REARRIGHT);
|
AddInputChannelDesignation(0, B_CHANNEL_REARRIGHT);
|
||||||
SetMixerChannelGain(2, 0.666);
|
SetMixerChannelGain(2, 0.666);
|
||||||
AddInputChannelDesignation(1, B_CHANNEL_REARLEFT);
|
AddInputChannelDesignation(1, B_CHANNEL_REARLEFT);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
MixerInput::~MixerInput()
|
MixerInput::~MixerInput()
|
||||||
@@ -98,19 +100,29 @@ MixerInput::BufferReceived(BBuffer *buffer)
|
|||||||
data = buffer->Data();
|
data = buffer->Data();
|
||||||
size = buffer->SizeUsed();
|
size = buffer->SizeUsed();
|
||||||
start = buffer->Header()->start_time;
|
start = buffer->Header()->start_time;
|
||||||
|
if (start < 0) {
|
||||||
|
printf("MixerInput::BufferReceived: buffer with negative start time of %Ld dropped\n", start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// swap the byte order of this buffer, if necessary
|
// swap the byte order of this buffer, if necessary
|
||||||
if (fInputByteSwap)
|
if (fInputByteSwap)
|
||||||
fInputByteSwap->Swap(data, size);
|
fInputByteSwap->Swap(data, size);
|
||||||
|
|
||||||
int32 offset = frames_for_duration(fMixBufferFrameRate, start - fMixBufferStartTime) % fMixBufferFrameCount;
|
int32 offset = frames_for_duration(fMixBufferFrameRate, start) % fMixBufferFrameCount;
|
||||||
|
|
||||||
|
// XXX test code! This will place the data earlier into the buffer then the supposed
|
||||||
|
// arrival time
|
||||||
|
// offset -= debugMixBufferFrames;
|
||||||
|
// if (offset < 0)
|
||||||
|
// offset += fMixBufferFrameCount;
|
||||||
|
|
||||||
// printf("MixerInput::BufferReceived: mix buffer start %14Ld, buffer start %14Ld, offset %6d\n", fMixBufferStartTime, start, offset);
|
// 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 in_frames = buffer->SizeUsed() / bytes_per_frame(fInput.format.u.raw_audio);
|
||||||
int out_frames = (int)((in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate); // XXX losing fractions
|
int out_frames = (int)((in_frames * fMixBufferFrameRate) / fInput.format.u.raw_audio.frame_rate); // XXX losing fractions
|
||||||
|
|
||||||
//printf("data arrived for %15Ld to %15Ld, storing at frames %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames);
|
//printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames);
|
||||||
|
|
||||||
if (offset + out_frames > fMixBufferFrameCount) {
|
if (offset + out_frames > fMixBufferFrameCount) {
|
||||||
|
|
||||||
@@ -119,16 +131,20 @@ MixerInput::BufferReceived(BBuffer *buffer)
|
|||||||
int in_frames1 = (out_frames1 * in_frames) / out_frames;
|
int in_frames1 = (out_frames1 * in_frames) / out_frames;
|
||||||
int in_frames2 = in_frames - in_frames1;
|
int in_frames2 = in_frames - in_frames1;
|
||||||
|
|
||||||
printf("data arrived for %15Ld to %15Ld, storing at frames %ld to %ld and %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames1, 0, out_frames2);
|
printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames1, 0, out_frames2);
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
|
||||||
|
|
||||||
// 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++) {
|
for (int i = 0; i < fInputChannelCount; i++) {
|
||||||
|
|
||||||
|
|
||||||
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
|
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
|
||||||
bytes_per_frame(fInput.format.u.raw_audio),
|
bytes_per_frame(fInput.format.u.raw_audio),
|
||||||
in_frames1,
|
in_frames1,
|
||||||
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount),
|
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
|
||||||
fInputChannelCount * sizeof(float),
|
fInputChannelCount * sizeof(float),
|
||||||
out_frames1,
|
out_frames1,
|
||||||
fInputChannelInfo[i].gain);
|
fInputChannelInfo[i].gain);
|
||||||
@@ -143,14 +159,16 @@ MixerInput::BufferReceived(BBuffer *buffer)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// printf(" in_frames %5d, out_frames %5d\n", in_frames, out_frames);
|
printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", fCore->fTimeSource->Now(), start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames);
|
||||||
printf("data arrived for %15Ld to %15Ld, storing at frames %ld to %ld\n", start, start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, frames_per_buffer(fInput.format.u.raw_audio)), offset, offset + out_frames);
|
//printf(" in_frames %5d, out_frames %5d\n", in_frames, out_frames);
|
||||||
|
|
||||||
|
offset *= sizeof(float) * fInputChannelCount; // convert offset from frames into bytes
|
||||||
|
|
||||||
for (int i = 0; i < fInputChannelCount; i++) {
|
for (int i = 0; i < fInputChannelCount; i++) {
|
||||||
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
|
fResampler[i]->Resample(reinterpret_cast<char *>(data) + i * bytes_per_sample(fInput.format.u.raw_audio),
|
||||||
bytes_per_frame(fInput.format.u.raw_audio),
|
bytes_per_frame(fInput.format.u.raw_audio),
|
||||||
in_frames,
|
in_frames,
|
||||||
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + (offset * sizeof(float) * fInputChannelCount),
|
reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) + offset,
|
||||||
fInputChannelCount * sizeof(float),
|
fInputChannelCount * sizeof(float),
|
||||||
out_frames,
|
out_frames,
|
||||||
fInputChannelInfo[i].gain);
|
fInputChannelInfo[i].gain);
|
||||||
@@ -374,7 +392,7 @@ MixerInput::GetMixerChannelInfo(int channel, int64 framepos, const float **buffe
|
|||||||
ASSERT(fMixBuffer);
|
ASSERT(fMixBuffer);
|
||||||
ASSERT(channel >= 0 && channel < fMixerChannelCount);
|
ASSERT(channel >= 0 && channel < fMixerChannelCount);
|
||||||
int32 offset = framepos % fMixBufferFrameCount;
|
int32 offset = framepos % fMixBufferFrameCount;
|
||||||
printf("GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + debugMixBufferFrames);
|
if (channel == 0) printf("GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + debugMixBufferFrames);
|
||||||
*buffer = reinterpret_cast<float *>(reinterpret_cast<char *>(fMixerChannelInfo[channel].buffer_base) + (offset * sizeof(float) * fInputChannelCount));
|
*buffer = reinterpret_cast<float *>(reinterpret_cast<char *>(fMixerChannelInfo[channel].buffer_base) + (offset * sizeof(float) * fInputChannelCount));
|
||||||
*sample_offset = sizeof(float) * fInputChannelCount;
|
*sample_offset = sizeof(float) * fInputChannelCount;
|
||||||
*type = fMixerChannelInfo[channel].type;
|
*type = fMixerChannelInfo[channel].type;
|
||||||
@@ -400,13 +418,12 @@ MixerInput::GetMixerChannelGain(int channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttime)
|
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
|
||||||
{
|
{
|
||||||
fMixBufferFrameRate = framerate;
|
fMixBufferFrameRate = framerate;
|
||||||
fMixBufferStartTime = starttime;
|
|
||||||
debugMixBufferFrames = frames;
|
debugMixBufferFrames = frames;
|
||||||
|
|
||||||
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld, starttime %Ld\n", framerate, frames, starttime);
|
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
|
||||||
|
|
||||||
// make fMixBufferFrameCount an integral multiple of frames,
|
// make fMixBufferFrameCount an integral multiple of frames,
|
||||||
// but at least 3 times duration of our input buffer
|
// but at least 3 times duration of our input buffer
|
||||||
@@ -422,6 +439,8 @@ MixerInput::SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttim
|
|||||||
printf(" mixerBufferLength %10Ld\n", mixerBufferLength);
|
printf(" mixerBufferLength %10Ld\n", mixerBufferLength);
|
||||||
printf(" fMixBufferFrameCount %10ld\n", fMixBufferFrameCount);
|
printf(" fMixBufferFrameCount %10ld\n", fMixBufferFrameCount);
|
||||||
|
|
||||||
|
ASSERT((fMixBufferFrameCount % frames) == 0);
|
||||||
|
|
||||||
if (fMixBuffer)
|
if (fMixBuffer)
|
||||||
rtm_free(fMixBuffer);
|
rtm_free(fMixBuffer);
|
||||||
int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
|
int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Resampler;
|
|||||||
class MixerInput
|
class MixerInput
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount, bigtime_t mixStartTime);
|
MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount);
|
||||||
~MixerInput();
|
~MixerInput();
|
||||||
|
|
||||||
int32 ID();
|
int32 ID();
|
||||||
@@ -31,7 +31,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class MixerCore;
|
friend class MixerCore;
|
||||||
void SetMixBufferFormat(int32 framerate, int32 frames, bigtime_t starttime);
|
void SetMixBufferFormat(int32 framerate, int32 frames);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateChannelDesignations();
|
void UpdateChannelDesignations();
|
||||||
@@ -65,7 +65,6 @@ private:
|
|||||||
|
|
||||||
float fMixBufferFrameRate;
|
float fMixBufferFrameRate;
|
||||||
uint32 fMixBufferFrameCount;
|
uint32 fMixBufferFrameCount;
|
||||||
bigtime_t fMixBufferStartTime;
|
|
||||||
|
|
||||||
Resampler **fResampler; // array
|
Resampler **fResampler; // array
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user