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:
parent
530590d3b9
commit
ba5e652d79
|
@ -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];
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -136,6 +136,7 @@ private:
|
|||
bool fDisableStop;
|
||||
media_format fDefaultFormat;
|
||||
bigtime_t fLastLateNotification;
|
||||
bigtime_t fLastLateness;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue