some workarounds, fMixStartTime is now always 0,

delay mix thread if timesource has negative time,
calculate correct time and frame base for mix thread


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3663 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-06-25 16:21:41 +00:00
parent c8c8057167
commit 16cecbde36
6 changed files with 78 additions and 30 deletions
@@ -31,7 +31,7 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn)
BControllable(), BControllable(),
BMediaEventLooper(), BMediaEventLooper(),
fAddOn(addOn), fAddOn(addOn),
fCore(new MixerCore), fCore(new MixerCore(this)),
fWeb(0), fWeb(0),
fBufferGroup(0), fBufferGroup(0),
fDownstreamLatency(1), fDownstreamLatency(1),
@@ -57,6 +57,14 @@ AudioMixer::~AudioMixer()
BMediaEventLooper::Quit(); BMediaEventLooper::Quit();
SetParameterWeb(NULL); SetParameterWeb(NULL);
// stop the mixer
fCore->Lock();
fCore->Stop();
fCore->Unlock();
// disconnect all nodes from the mixer
// XXX todo
delete fCore; delete fCore;
delete fBufferGroup; delete fBufferGroup;
@@ -715,7 +723,7 @@ AudioMixer::SetTimeSource(BTimeSource * time_source)
} }
void void
AudioMixer::HandleEvent( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent) AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool realTimeEvent)
{ {
switch (event->type) switch (event->type)
{ {
@@ -729,6 +737,7 @@ AudioMixer::HandleEvent( const media_timed_event *event, bigtime_t lateness, boo
case BTimedEventQueue::B_START: case BTimedEventQueue::B_START:
{ {
printf("AudioMixer::HandleEvent: B_START\n");
if (RunState() != B_STARTED) { if (RunState() != B_STARTED) {
fCore->Lock(); fCore->Lock();
fCore->Start(event->event_time); fCore->Start(event->event_time);
@@ -739,6 +748,7 @@ AudioMixer::HandleEvent( const media_timed_event *event, bigtime_t lateness, boo
case BTimedEventQueue::B_STOP: case BTimedEventQueue::B_STOP:
{ {
printf("AudioMixer::HandleEvent: B_STOP\n");
// stopped - don't process any more buffers, flush all buffers from eventqueue // stopped - don't process any more buffers, flush all buffers from eventqueue
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
fCore->Lock(); fCore->Lock();
@@ -59,6 +59,8 @@ class AudioMixer :
void NodeRegistered(); void NodeRegistered();
void Stop(bigtime_t performance_time, bool immediate); void Stop(bigtime_t performance_time, bool immediate);
void SetTimeSource(BTimeSource * time_source); void SetTimeSource(BTimeSource * time_source);
using BBufferProducer::SendBuffer;
protected: protected:
@@ -1,5 +1,6 @@
#include <RealtimeAlloc.h> #include <RealtimeAlloc.h>
#include <MediaNode.h> #include <MediaNode.h>
#include <BufferProducer.h>
#include <TimeSource.h> #include <TimeSource.h>
#include <Buffer.h> #include <Buffer.h>
#include <BufferGroup.h> #include <BufferGroup.h>
@@ -7,6 +8,7 @@
#include "MixerInput.h" #include "MixerInput.h"
#include "MixerOutput.h" #include "MixerOutput.h"
#include "MixerUtils.h" #include "MixerUtils.h"
#include "AudioMixer.h"
#include "Debug.h" #include "Debug.h"
#define DOUBLE_RATE_MIXING 1 #define DOUBLE_RATE_MIXING 1
@@ -26,7 +28,7 @@
*/ */
MixerCore::MixerCore() MixerCore::MixerCore(AudioMixer *node)
: fLocker(new BLocker), : fLocker(new BLocker),
fInputs(new BList), fInputs(new BList),
fOutput(0), fOutput(0),
@@ -38,7 +40,8 @@ MixerCore::MixerCore()
fMixBufferChannelTypes(0), fMixBufferChannelTypes(0),
fMixBufferChannelCount(0), fMixBufferChannelCount(0),
fDoubleRateMixing(DOUBLE_RATE_MIXING), fDoubleRateMixing(DOUBLE_RATE_MIXING),
fLastMixStartTime(0), fMixStartTime(0),
fNode(node),
fBufferGroup(0), fBufferGroup(0),
fTimeSource(0), fTimeSource(0),
fMixThread(-1), fMixThread(-1),
@@ -67,7 +70,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, fLastMixStartTime)); fInputs->AddItem(new MixerInput(this, input, fMixBufferFrameRate, fMixBufferFrameCount, fMixStartTime));
return true; return true;
} }
@@ -184,7 +187,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, fLastMixStartTime); input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fMixStartTime);
} }
void void
@@ -204,11 +207,13 @@ MixerCore::SetTimeSource(BTimeSource *ts)
fTimeSource->Release(); fTimeSource->Release();
fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire()); fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire());
fLastMixStartTime = fTimeSource->Now(); // fMixStartTime = fTimeSource->Now();
MixerInput *input; printf("MixerCore::SetTimeSource, now = %Ld\n", fTimeSource->Now());
for (int i = 0; (input = Input(i)); i++)
input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fLastMixStartTime); // MixerInput *input;
// for (int i = 0; (input = Input(i)); i++)
// input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount, fMixStartTime);
} }
void void
@@ -222,6 +227,7 @@ void
MixerCore::Start(bigtime_t time) MixerCore::Start(bigtime_t time)
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
printf("MixerCore::Start\n");
if (fRunning) if (fRunning)
return; return;
@@ -235,6 +241,7 @@ void
MixerCore::Stop() MixerCore::Stop()
{ {
ASSERT_LOCKED(); ASSERT_LOCKED();
printf("MixerCore::Stop\n");
if (!fRunning) if (!fRunning)
return; return;
@@ -277,39 +284,66 @@ void
MixerCore::MixThread() MixerCore::MixThread()
{ {
bigtime_t event_time; bigtime_t event_time;
bigtime_t base; bigtime_t time_base;
bigtime_t latency; bigtime_t latency;
int64 pos; int64 frame_base;
int64 frame_pos;
pos = 0;
latency = 30000; latency = 30000;
base = event_time = fTimeSource->Now();
while (fTimeSource->Now() <= 0) {
printf("delay MixThread start, now %Ld\n", (int64)fTimeSource->Now());
snooze(1000);
}
printf("starting MixThread, now %Ld\n", (int64)fTimeSource->Now());
/* 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);
frame_base = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount;
time_base = duration_for_frames(fMixBufferFrameRate, frame_base) + fMixStartTime;
printf("starting MixThread, now %Ld, time_base %Ld, fMixStartTime %Ld, frame_base %Ld\n", fTimeSource->Now(), time_base, fMixStartTime, frame_base);
event_time = time_base;
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));
if (rv == B_INTERRUPTED) if (rv == B_INTERRUPTED)
continue; continue;
if (rv < B_OK) if (rv != B_TIMED_OUT && rv < B_OK)
return; return;
// 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);
printf("create new buffer event at %Ld, reading input frames at %Ld\n", event_time, frame_base + frame_pos);
// 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, 10000);
if (buf) {
// copy data from mix buffer into output buffer // copy data from mix buffer into output buffer
// fill in the buffer header // fill in the buffer header
media_header* hdr = buf->Header(); media_header* hdr = buf->Header();
hdr->type = B_MEDIA_RAW_AUDIO; hdr->type = B_MEDIA_RAW_AUDIO;
hdr->size_used = fOutput->MediaOutput().format.u.raw_audio.buffer_size; hdr->size_used = fOutput->MediaOutput().format.u.raw_audio.buffer_size;
hdr->time_source = fTimeSource->ID(); hdr->time_source = fTimeSource->ID();
hdr->start_time = event_time; hdr->start_time = event_time;
// send the buffer // send the buffer
if (B_OK != fNode->SendBuffer(buf, fOutput->MediaOutput().destination)) {
printf("SendBuffer failed\n");
buf->Recycle();
}
}
// shedule next event // shedule next event
pos += fMixBufferFrameCount; frame_pos += fMixBufferFrameCount;
event_time = base + bigtime_t((1000000LL * pos) / fMixBufferFrameRate); event_time = time_base + bigtime_t((1000000LL * frame_pos) / fMixBufferFrameRate);
} }
} }
@@ -3,13 +3,14 @@
#include <Locker.h> #include <Locker.h>
class AudioMixer;
class MixerInput; class MixerInput;
class MixerOutput; class MixerOutput;
class MixerCore class MixerCore
{ {
public: public:
MixerCore(); MixerCore(AudioMixer *node);
~MixerCore(); ~MixerCore();
bool AddInput(const media_input &input); bool AddInput(const media_input &input);
@@ -60,8 +61,9 @@ private:
int32 fMixBufferChannelCount; int32 fMixBufferChannelCount;
int32 *fMixBufferChannelTypes; //array int32 *fMixBufferChannelTypes; //array
bool fDoubleRateMixing; bool fDoubleRateMixing;
bigtime_t fLastMixStartTime; bigtime_t fMixStartTime;
AudioMixer *fNode;
BBufferGroup *fBufferGroup; BBufferGroup *fBufferGroup;
BTimeSource *fTimeSource; BTimeSource *fTimeSource;
thread_id fMixThread; thread_id fMixThread;
@@ -11,7 +11,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 mixSampleRate, int32 mixFramesCount, bigtime_t mixStartTime) MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount, bigtime_t mixStartTime)
: fCore(core), : fCore(core),
fInput(input), fInput(input),
fInputByteSwap(0), fInputByteSwap(0),
@@ -60,7 +60,7 @@ MixerInput::MixerInput(MixerCore *core, const media_input &input, float mixSampl
// fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels() // fMixerChannelInfo and fMixerChannelCount will be initialized by UpdateMixerChannels()
SetMixBufferFormat(mixSampleRate, mixFramesCount, mixStartTime); SetMixBufferFormat(mixFrameRate, mixFrameCount, mixStartTime);
UpdateChannelDesignations(); UpdateChannelDesignations();
UpdateMixerChannels(); UpdateMixerChannels();
@@ -8,7 +8,7 @@ class Resampler;
class MixerInput class MixerInput
{ {
public: public:
MixerInput(MixerCore *core, const media_input &input, float mixSampleRate, int32 mixFramesCount, bigtime_t mixStartTime); MixerInput(MixerCore *core, const media_input &input, float mixFrameRate, int32 mixFrameCount, bigtime_t mixStartTime);
~MixerInput(); ~MixerInput();
int32 ID(); int32 ID();