rewrote start and stop handling to allow connecting an input without
having an output, followed by starting the node. fix some bugs of handling an unconnected output added better locking to the mix thread git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3727 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -450,7 +450,7 @@ AudioMixer::FormatChangeRequested(const media_source &source, const media_destin
|
|||||||
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
|
||||||
fInternalLatency = bigtime_t(1.2 * BufferDuration());
|
fInternalLatency = bigtime_t(1.6 * 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);
|
||||||
@@ -634,7 +634,7 @@ AudioMixer::Connect(status_t error, const media_source &source, const media_dest
|
|||||||
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
|
||||||
fInternalLatency = bigtime_t(1.2 * BufferDuration());
|
fInternalLatency = bigtime_t(1.6 * 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);
|
||||||
@@ -778,7 +778,7 @@ AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, bool
|
|||||||
printf("AudioMixer::HandleEvent: B_START\n");
|
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();
|
||||||
fCore->Unlock();
|
fCore->Unlock();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ MixerCore::MixerCore(AudioMixer *node)
|
|||||||
fOutput(0),
|
fOutput(0),
|
||||||
fNextInputID(1),
|
fNextInputID(1),
|
||||||
fRunning(false),
|
fRunning(false),
|
||||||
|
fStarted(false),
|
||||||
|
fOutputEnabled(true),
|
||||||
fResampler(0),
|
fResampler(0),
|
||||||
fMixBuffer(0),
|
fMixBuffer(0),
|
||||||
fMixBufferFrameRate(0),
|
fMixBufferFrameRate(0),
|
||||||
@@ -93,6 +95,10 @@ MixerCore::AddOutput(const media_output &output)
|
|||||||
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
|
||||||
ApplyOutputFormat();
|
ApplyOutputFormat();
|
||||||
|
|
||||||
|
ASSERT(!fRunning);
|
||||||
|
if (fStarted && fOutputEnabled)
|
||||||
|
StartMixThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -116,8 +122,13 @@ MixerCore::RemoveOutput()
|
|||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
if (!fOutput)
|
if (!fOutput)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (fStarted)
|
||||||
|
StopMixThread();
|
||||||
|
|
||||||
delete fOutput;
|
delete fOutput;
|
||||||
fOutput = 0;
|
fOutput = 0;
|
||||||
|
fOutputEnabled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,16 +180,16 @@ MixerCore::OutputFormatChanged(const media_multi_audio_format &format)
|
|||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
|
|
||||||
bool wasrunning = fRunning;
|
bool was_started = fStarted;
|
||||||
|
|
||||||
if (wasrunning)
|
if (was_started)
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
fOutput->ChangeFormat(format);
|
fOutput->ChangeFormat(format);
|
||||||
ApplyOutputFormat();
|
ApplyOutputFormat();
|
||||||
|
|
||||||
if (wasrunning)
|
if (was_started)
|
||||||
Start(0);
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -258,16 +269,55 @@ MixerCore::EnableOutput(bool enabled)
|
|||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
printf("MixerCore::EnableOutput %d\n", enabled);
|
printf("MixerCore::EnableOutput %d\n", enabled);
|
||||||
|
fOutputEnabled = enabled;
|
||||||
|
|
||||||
|
if (fRunning && !fOutputEnabled)
|
||||||
|
StopMixThread();
|
||||||
|
|
||||||
|
if (!fRunning && fOutput && fStarted && fOutputEnabled)
|
||||||
|
StartMixThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
MixerCore::Start(bigtime_t time)
|
MixerCore::Start()
|
||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
printf("MixerCore::Start\n");
|
printf("MixerCore::Start\n");
|
||||||
if (fRunning)
|
if (fStarted)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
|
fStarted = true;
|
||||||
|
|
||||||
|
ASSERT(!fRunning);
|
||||||
|
|
||||||
|
// only start the mix thread if we have an output
|
||||||
|
if (fOutput && fOutputEnabled)
|
||||||
|
StartMixThread();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MixerCore::Stop()
|
||||||
|
{
|
||||||
|
ASSERT_LOCKED();
|
||||||
|
printf("MixerCore::Stop\n");
|
||||||
|
if (!fStarted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fRunning)
|
||||||
|
StopMixThread();
|
||||||
|
|
||||||
|
fStarted = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MixerCore::StartMixThread()
|
||||||
|
{
|
||||||
|
ASSERT(fOutputEnabled == true);
|
||||||
|
ASSERT(fRunning == false);
|
||||||
|
ASSERT(fOutput);
|
||||||
fRunning = true;
|
fRunning = true;
|
||||||
fMixThreadWaitSem = create_sem(0, "mix thread wait");
|
fMixThreadWaitSem = create_sem(0, "mix thread wait");
|
||||||
fMixThread = spawn_thread(_mix_thread_, "Yeah baby, very shagadelic", 12, this);
|
fMixThread = spawn_thread(_mix_thread_, "Yeah baby, very shagadelic", 12, this);
|
||||||
@@ -275,13 +325,9 @@ MixerCore::Start(bigtime_t time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MixerCore::Stop()
|
MixerCore::StopMixThread()
|
||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT(fRunning == true);
|
||||||
printf("MixerCore::Stop\n");
|
|
||||||
if (!fRunning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ASSERT(fMixThread > 0);
|
ASSERT(fMixThread > 0);
|
||||||
ASSERT(fMixThreadWaitSem > 0);
|
ASSERT(fMixThreadWaitSem > 0);
|
||||||
|
|
||||||
@@ -294,12 +340,14 @@ MixerCore::Stop()
|
|||||||
fRunning = false;
|
fRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bool
|
bool
|
||||||
MixerCore::IsStarted()
|
MixerCore::IsStarted()
|
||||||
{
|
{
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
return fRunning;
|
return fRunning;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int32
|
int32
|
||||||
MixerCore::_mix_thread_(void *arg)
|
MixerCore::_mix_thread_(void *arg)
|
||||||
@@ -321,14 +369,19 @@ MixerCore::MixThread()
|
|||||||
// The broken BeOS R5 multiaudio node starts with time 0,
|
// The broken BeOS R5 multiaudio node starts with time 0,
|
||||||
// then publishes negative times for about 50ms, publishes 0
|
// then publishes negative times for about 50ms, publishes 0
|
||||||
// again until it finally reaches time values > 0
|
// again until it finally reaches time values > 0
|
||||||
|
Lock();
|
||||||
start = fTimeSource->Now();
|
start = fTimeSource->Now();
|
||||||
|
Unlock();
|
||||||
while (start <= 0) {
|
while (start <= 0) {
|
||||||
printf("MixerCore: delaying MixThread start, timesource is at %Ld\n", start);
|
printf("MixerCore: delaying MixThread start, timesource is at %Ld\n", start);
|
||||||
snooze(1000);
|
snooze(1000);
|
||||||
|
Lock();
|
||||||
start = fTimeSource->Now();
|
start = fTimeSource->Now();
|
||||||
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
latency = bigtime_t(0.2 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio));
|
Lock();
|
||||||
|
latency = bigtime_t(0.4 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio));
|
||||||
|
|
||||||
printf("MixerCore: starting MixThread at %Ld with latency %Ld and downstream latency %Ld\n", start, latency, fDownstreamLatency);
|
printf("MixerCore: starting MixThread at %Ld with latency %Ld and downstream latency %Ld\n", start, latency, fDownstreamLatency);
|
||||||
|
|
||||||
@@ -337,6 +390,7 @@ MixerCore::MixThread()
|
|||||||
int64 temp = frames_for_duration(fMixBufferFrameRate, start );
|
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);
|
time_base = duration_for_frames(fMixBufferFrameRate, frame_base);
|
||||||
|
Unlock();
|
||||||
|
|
||||||
printf("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
|
printf("starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base);
|
||||||
|
|
||||||
@@ -344,7 +398,8 @@ MixerCore::MixThread()
|
|||||||
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 + fDownstreamLatency));
|
// rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, latency + fDownstreamLatency));
|
||||||
|
rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, fTimeSource->RealTimeFor(event_time, 0) - 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)
|
||||||
|
|||||||
@@ -37,10 +37,13 @@ public:
|
|||||||
void SetOutputBufferGroup(BBufferGroup *group);
|
void SetOutputBufferGroup(BBufferGroup *group);
|
||||||
void SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency);
|
void SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency);
|
||||||
void EnableOutput(bool enabled);
|
void EnableOutput(bool enabled);
|
||||||
void Start(bigtime_t time);
|
bool Start();
|
||||||
void Stop();
|
bool Stop();
|
||||||
|
|
||||||
|
void StartMixThread();
|
||||||
|
void StopMixThread();
|
||||||
|
|
||||||
bool IsStarted();
|
// bool IsStarted();
|
||||||
|
|
||||||
uint32 OutputChannelCount();
|
uint32 OutputChannelCount();
|
||||||
|
|
||||||
@@ -55,7 +58,9 @@ private:
|
|||||||
BList *fInputs;
|
BList *fInputs;
|
||||||
MixerOutput *fOutput;
|
MixerOutput *fOutput;
|
||||||
int32 fNextInputID;
|
int32 fNextInputID;
|
||||||
bool fRunning;
|
bool fRunning; // true = the mix thread is running
|
||||||
|
bool fStarted; // true = mix thread should be started of it is not running
|
||||||
|
bool fOutputEnabled; // true = mix thread should be started of it is not running
|
||||||
|
|
||||||
Resampler **fResampler; // array
|
Resampler **fResampler; // array
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,6 @@ 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);
|
SetMixBufferFormat(mixFrameRate, mixFrameCount);
|
||||||
UpdateChannelDesignations();
|
|
||||||
UpdateMixerChannels();
|
|
||||||
|
|
||||||
|
|
||||||
// XXX a test:
|
// XXX a test:
|
||||||
/*
|
/*
|
||||||
@@ -95,7 +92,10 @@ MixerInput::BufferReceived(BBuffer *buffer)
|
|||||||
size_t size;
|
size_t size;
|
||||||
bigtime_t start;
|
bigtime_t start;
|
||||||
|
|
||||||
ASSERT(fMixBuffer);
|
if (!fMixBuffer) {
|
||||||
|
printf("MixerInput::BufferReceived: dropped incoming buffer as we don't have a mix buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data = buffer->Data();
|
data = buffer->Data();
|
||||||
size = buffer->SizeUsed();
|
size = buffer->SizeUsed();
|
||||||
@@ -305,8 +305,6 @@ MixerInput::UpdateMixerChannels()
|
|||||||
mixer_chan_info *old_mixer_channel_info;
|
mixer_chan_info *old_mixer_channel_info;
|
||||||
uint32 old_mixer_channel_count;
|
uint32 old_mixer_channel_count;
|
||||||
|
|
||||||
ASSERT(fMixBuffer);
|
|
||||||
|
|
||||||
printf("UpdateMixerChannels: enter\n");
|
printf("UpdateMixerChannels: enter\n");
|
||||||
|
|
||||||
for (int i = 0; i < fInputChannelCount; i++)
|
for (int i = 0; i < fInputChannelCount; i++)
|
||||||
@@ -350,7 +348,7 @@ MixerInput::UpdateMixerChannels()
|
|||||||
int j;
|
int j;
|
||||||
for (j = 0; j < fInputChannelCount; j++) {
|
for (j = 0; j < fInputChannelCount; j++) {
|
||||||
if (fInputChannelInfo[j].designations & ChannelTypeToChannelMask(fMixerChannelInfo[i].type)) {
|
if (fInputChannelInfo[j].designations & ChannelTypeToChannelMask(fMixerChannelInfo[i].type)) {
|
||||||
fMixerChannelInfo[i].buffer_base = &fMixBuffer[j];
|
fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] : 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,7 +387,7 @@ MixerInput::GetMixerChannelCount()
|
|||||||
void
|
void
|
||||||
MixerInput::GetMixerChannelInfo(int channel, int64 framepos, 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(fMixBuffer); // this function should not be called if we don't have a mix buffer!
|
||||||
ASSERT(channel >= 0 && channel < fMixerChannelCount);
|
ASSERT(channel >= 0 && channel < fMixerChannelCount);
|
||||||
int32 offset = framepos % fMixBufferFrameCount;
|
int32 offset = framepos % fMixBufferFrameCount;
|
||||||
if (channel == 0) printf("GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + debugMixBufferFrames);
|
if (channel == 0) printf("GetMixerChannelInfo: frames %ld to %ld\n", offset, offset + debugMixBufferFrames);
|
||||||
@@ -420,10 +418,25 @@ MixerInput::GetMixerChannelGain(int channel)
|
|||||||
void
|
void
|
||||||
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
|
MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
|
||||||
{
|
{
|
||||||
|
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
|
||||||
|
|
||||||
fMixBufferFrameRate = framerate;
|
fMixBufferFrameRate = framerate;
|
||||||
debugMixBufferFrames = frames;
|
debugMixBufferFrames = frames;
|
||||||
|
|
||||||
printf("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", framerate, frames);
|
// frames and/or framerate can be 0 (if no output is connected)
|
||||||
|
if (framerate == 0 || frames == 0) {
|
||||||
|
if (fMixBuffer) {
|
||||||
|
rtm_free(fMixBuffer);
|
||||||
|
fMixBuffer = 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < fInputChannelCount; i++)
|
||||||
|
fInputChannelInfo[i].buffer_base = 0;
|
||||||
|
fMixBufferFrameCount = 0;
|
||||||
|
|
||||||
|
UpdateChannelDesignations();
|
||||||
|
UpdateMixerChannels();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -451,4 +464,7 @@ MixerInput::SetMixBufferFormat(int32 framerate, int32 frames)
|
|||||||
|
|
||||||
for (int i = 0; i < fInputChannelCount; i++)
|
for (int i = 0; i < fInputChannelCount; i++)
|
||||||
fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
|
fInputChannelInfo[i].buffer_base = &fMixBuffer[i];
|
||||||
|
|
||||||
|
UpdateChannelDesignations();
|
||||||
|
UpdateMixerChannels();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user