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:
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user