Set of patches by Pete Goodeve to imrpove the handling of audio latency.

Closes #7285.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@43164 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues 2011-11-03 14:26:03 +00:00
parent 530590d3b9
commit ba5e652d79
7 changed files with 52 additions and 38 deletions

View File

@ -38,8 +38,9 @@ struct media_timed_event {
int32 data;
int64 bigdata;
char user_data[64];
bigtime_t queued_time; // Real time when put in queue
uint32 _reserved_media_timed_event_[8];
uint32 _reserved_media_timed_event_[6];
};

View File

@ -37,6 +37,8 @@ enum {
// Raw port based communication
enum {
GENERAL_PURPOSE_WAKEUP = 0, // when no action but wait termination needed
ADD_ON_SERVER_RESCAN_ADD_ON_FLAVORS = 0x50,
ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY,
ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE,

View File

@ -1,7 +1,7 @@
/*
* Copyright 2002 David Shipman,
* Copyright 2003-2007 Marcus Overhagen
* Copyright 2007-2010 Haiku Inc. All rights reserved.
* Copyright 2007-2011 Haiku Inc. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
@ -113,7 +113,8 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
fDownstreamLatency(1),
fInternalLatency(1),
fDisableStop(false),
fLastLateNotification(0)
fLastLateNotification(0),
fLastLateness(0)
{
BMediaNode::AddNodeKind(B_SYSTEM_MIXER);
@ -319,11 +320,11 @@ AudioMixer::BufferReceived(BBuffer *buffer)
void
AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
{
if (lateness > kMaxJitter) {
debug_printf("Received buffer %Ld usec late\n", lateness);
if (lateness > kMaxJitter && lateness > fLastLateness) {
debug_printf("AudioMixer: Dequeued input buffer %Ld usec late\n", lateness);
if (RunMode() == B_DROP_DATA || RunMode() == B_DECREASE_PRECISION
|| RunMode() == B_INCREASE_LATENCY) {
debug_printf("sending notify\n");
debug_printf("AudioMixer: sending notify\n");
// Build a media_source out of the header data
media_source source = media_source::null;
@ -333,13 +334,12 @@ AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
NotifyLateProducer(source, lateness, TimeSource()->Now());
if (RunMode() == B_DROP_DATA) {
debug_printf("dropping buffer\n");
debug_printf("AudioMixer: dropping buffer\n");
return;
}
}
}
// printf("Received buffer with lateness %Ld\n", lateness);
fLastLateness = lateness;
fCore->Lock();
fCore->BufferReceived(buffer, lateness);
@ -1006,18 +1006,19 @@ AudioMixer::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
if (what == fCore->Output()->MediaOutput().source
&& RunMode() == B_INCREASE_LATENCY) {
// We need to ignore subsequent notices whose performance time
// lies before the performance time of the last notification
// We need to ignore subsequent notices whose arrival time here
// lies within the last lateness, because queued-up buffers will all be 'late'
if (performanceTime < fLastLateNotification)
return;
fInternalLatency += howMuch;
// At some point a too large latency can get annoying
// (actually more than annoying, as there won't be enough buffers long before this!)
if (fInternalLatency > kMaxLatency)
fInternalLatency = kMaxLatency;
fLastLateNotification = TimeSource()->Now();
fLastLateNotification = TimeSource()->Now() + howMuch;
debug_printf("AudioMixer: increasing internal latency to %Ld usec\n", fInternalLatency);
SetEventLatency(fDownstreamLatency + fInternalLatency);

View File

@ -136,6 +136,7 @@ private:
bool fDisableStop;
media_format fDefaultFormat;
bigtime_t fLastLateNotification;
bigtime_t fLastLateness;
};

View File

@ -31,6 +31,7 @@
#include <TimeSource.h>
#include <scheduler.h>
#include <Buffer.h>
#include <ServerInterface.h>
#include "debug.h"
/*************************************************************
@ -210,6 +211,7 @@ BMediaEventLooper::ControlLoop()
status_t err;
bigtime_t latency;
bigtime_t waituntil;
bigtime_t lateness;
for (;;) {
// while there are no events or it is not time for the earliest event,
// process messages using WaitForMessages. Whenever this funtion times out,
@ -222,31 +224,37 @@ BMediaEventLooper::ControlLoop()
// only the scheduling latency).
latency = fEventLatency + fSchedulingLatency;
if (fEventQueue.HasEvents() && (TimeSource()->Now() - latency) >= fEventQueue.FirstEventTime()) {
// printf("node %02d waiting for %12Ld that has already happened, now %12Ld\n", ID(), fEventQueue.FirstEventTime(), system_time());
is_realtime = false;
break;
}
if (fRealTimeQueue.HasEvents() && (TimeSource()->RealTime() - fSchedulingLatency) >= fRealTimeQueue.FirstEventTime()) {
latency = fSchedulingLatency;
is_realtime = true;
break;
}
waituntil = B_INFINITE_TIMEOUT;
if (fEventQueue.HasEvents()) {
waituntil = TimeSource()->RealTimeFor(fEventQueue.FirstEventTime(), latency);
// printf("node %02d waiting for %12Ld that will happen at %12Ld\n", ID(), fEventQueue.FirstEventTime(), waituntil);
const media_timed_event *firstEvent = fEventQueue.FirstEvent();
waituntil = TimeSource()->RealTimeFor(firstEvent->event_time, latency);
is_realtime = false;
lateness = firstEvent->queued_time - waituntil;
if (lateness > 0) {
// if (lateness > 1000)
// printf("node %02ld handling %12Ld at %12Ld -- %Ld late, queued at %Ld now %12Ld \n",
// ID(), fEventQueue.FirstEventTime(), TimeSource()->Now(), lateness,
// firstEvent->queued_time, TimeSource()->RealTime());
is_realtime = false;
break;
}
// printf("node %02ld waiting for %12Ld that will happen at %12Ld\n", ID(), fEventQueue.FirstEventTime(), waituntil);
}
if (fRealTimeQueue.HasEvents()) {
const media_timed_event *firstEvent = fRealTimeQueue.FirstEvent();
bigtime_t temp;
temp = fRealTimeQueue.FirstEventTime() - fSchedulingLatency;
temp = firstEvent->event_time - fSchedulingLatency;
lateness = firstEvent->queued_time - temp;
if (lateness > 0) {
is_realtime = true;
break;
}
if (temp < waituntil) {
waituntil = temp;
is_realtime = true;
latency = fSchedulingLatency;
}
}
lateness = 0; // remove any extraneous value if we get this far
err = WaitForMessage(waituntil);
if (err == B_TIMED_OUT)
break;
@ -258,16 +266,9 @@ BMediaEventLooper::ControlLoop()
else
err = fEventQueue.RemoveFirstEvent(&event);
// printf("node %02d handling %12Ld at %12Ld\n", ID(), event.event_time, system_time());
// printf("node %02ld handling %12Ld at %12Ld\n", ID(), event.event_time, TimeSource()->Now());
if (err == B_OK) {
bigtime_t lateness;
if (is_realtime)
lateness = TimeSource()->RealTime() - event.event_time;
else
lateness = TimeSource()->RealTime() - TimeSource()->RealTimeFor(event.event_time, 0) + fEventLatency;
DispatchEvent(&event, lateness, is_realtime);
}
if (err == B_OK) DispatchEvent(&event, lateness, is_realtime);
}
}
@ -388,6 +389,7 @@ BMediaEventLooper::SetEventLatency(bigtime_t latency)
latency = 0;
fEventLatency = latency;
write_port_etc(ControlPort(), GENERAL_PURPOSE_WAKEUP, 0, 0, B_TIMEOUT, 0);
}

View File

@ -377,6 +377,8 @@ BMediaNode::WaitForMessage(bigtime_t waitUntil,
TRACE("BMediaNode::WaitForMessage request is: %#lx, node %ld, this %p\n",
message, fNodeID, this);
if (message == GENERAL_PURPOSE_WAKEUP) return B_OK; // no action needed
if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
TRACE("BMediaNode::WaitForMessage calling BMediaNode\n");
if (B_OK == BMediaNode::HandleMessage(message, data, size))

View File

@ -29,16 +29,19 @@
/* Implements _event_queue_imp used by BTimedEventQueue, not thread save!
*/
#include <TimedEventQueue.h>
#include <string.h>
#include <Autolock.h>
#include <Buffer.h>
#include <InterfaceDefs.h> //defines B_DELETE
#include <TimedEventQueue.h>
#include <TimeSource.h>
#include "TimedEventQueuePrivate.h"
#include "Debug.h"
#include "debug.h"
#include <string.h>
_event_queue_imp::_event_queue_imp() :
fLock(new BLocker("BTimedEventQueue locker")),
fEventCount(0),
@ -74,6 +77,8 @@ _event_queue_imp::AddEvent(const media_timed_event &event)
if (event.type <= 0) {
return B_BAD_VALUE;
}
*(bigtime_t *)&event.queued_time = BTimeSource::RealTime();
//create a new queue
if (fFirstEntry == NULL) {