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:
@@ -38,8 +38,9 @@ struct media_timed_event {
|
|||||||
int32 data;
|
int32 data;
|
||||||
int64 bigdata;
|
int64 bigdata;
|
||||||
char user_data[64];
|
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
|
// Raw port based communication
|
||||||
enum {
|
enum {
|
||||||
|
GENERAL_PURPOSE_WAKEUP = 0, // when no action but wait termination needed
|
||||||
|
|
||||||
ADD_ON_SERVER_RESCAN_ADD_ON_FLAVORS = 0x50,
|
ADD_ON_SERVER_RESCAN_ADD_ON_FLAVORS = 0x50,
|
||||||
ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY,
|
ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY,
|
||||||
ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE,
|
ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002 David Shipman,
|
* Copyright 2002 David Shipman,
|
||||||
* Copyright 2003-2007 Marcus Overhagen
|
* 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -113,7 +113,8 @@ AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer)
|
|||||||
fDownstreamLatency(1),
|
fDownstreamLatency(1),
|
||||||
fInternalLatency(1),
|
fInternalLatency(1),
|
||||||
fDisableStop(false),
|
fDisableStop(false),
|
||||||
fLastLateNotification(0)
|
fLastLateNotification(0),
|
||||||
|
fLastLateness(0)
|
||||||
{
|
{
|
||||||
BMediaNode::AddNodeKind(B_SYSTEM_MIXER);
|
BMediaNode::AddNodeKind(B_SYSTEM_MIXER);
|
||||||
|
|
||||||
@@ -319,11 +320,11 @@ AudioMixer::BufferReceived(BBuffer *buffer)
|
|||||||
void
|
void
|
||||||
AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
|
AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
|
||||||
{
|
{
|
||||||
if (lateness > kMaxJitter) {
|
if (lateness > kMaxJitter && lateness > fLastLateness) {
|
||||||
debug_printf("Received buffer %Ld usec late\n", lateness);
|
debug_printf("AudioMixer: Dequeued input buffer %Ld usec late\n", lateness);
|
||||||
if (RunMode() == B_DROP_DATA || RunMode() == B_DECREASE_PRECISION
|
if (RunMode() == B_DROP_DATA || RunMode() == B_DECREASE_PRECISION
|
||||||
|| RunMode() == B_INCREASE_LATENCY) {
|
|| RunMode() == B_INCREASE_LATENCY) {
|
||||||
debug_printf("sending notify\n");
|
debug_printf("AudioMixer: sending notify\n");
|
||||||
|
|
||||||
// Build a media_source out of the header data
|
// Build a media_source out of the header data
|
||||||
media_source source = media_source::null;
|
media_source source = media_source::null;
|
||||||
@@ -333,13 +334,12 @@ AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness)
|
|||||||
NotifyLateProducer(source, lateness, TimeSource()->Now());
|
NotifyLateProducer(source, lateness, TimeSource()->Now());
|
||||||
|
|
||||||
if (RunMode() == B_DROP_DATA) {
|
if (RunMode() == B_DROP_DATA) {
|
||||||
debug_printf("dropping buffer\n");
|
debug_printf("AudioMixer: dropping buffer\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fLastLateness = lateness;
|
||||||
// printf("Received buffer with lateness %Ld\n", lateness);
|
|
||||||
|
|
||||||
fCore->Lock();
|
fCore->Lock();
|
||||||
fCore->BufferReceived(buffer, lateness);
|
fCore->BufferReceived(buffer, lateness);
|
||||||
@@ -1006,18 +1006,19 @@ AudioMixer::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
|
|||||||
|
|
||||||
if (what == fCore->Output()->MediaOutput().source
|
if (what == fCore->Output()->MediaOutput().source
|
||||||
&& RunMode() == B_INCREASE_LATENCY) {
|
&& RunMode() == B_INCREASE_LATENCY) {
|
||||||
// We need to ignore subsequent notices whose performance time
|
// We need to ignore subsequent notices whose arrival time here
|
||||||
// lies before the performance time of the last notification
|
// lies within the last lateness, because queued-up buffers will all be 'late'
|
||||||
if (performanceTime < fLastLateNotification)
|
if (performanceTime < fLastLateNotification)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fInternalLatency += howMuch;
|
fInternalLatency += howMuch;
|
||||||
|
|
||||||
// At some point a too large latency can get annoying
|
// 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)
|
if (fInternalLatency > kMaxLatency)
|
||||||
fInternalLatency = kMaxLatency;
|
fInternalLatency = kMaxLatency;
|
||||||
|
|
||||||
fLastLateNotification = TimeSource()->Now();
|
fLastLateNotification = TimeSource()->Now() + howMuch;
|
||||||
|
|
||||||
debug_printf("AudioMixer: increasing internal latency to %Ld usec\n", fInternalLatency);
|
debug_printf("AudioMixer: increasing internal latency to %Ld usec\n", fInternalLatency);
|
||||||
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
SetEventLatency(fDownstreamLatency + fInternalLatency);
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ private:
|
|||||||
bool fDisableStop;
|
bool fDisableStop;
|
||||||
media_format fDefaultFormat;
|
media_format fDefaultFormat;
|
||||||
bigtime_t fLastLateNotification;
|
bigtime_t fLastLateNotification;
|
||||||
|
bigtime_t fLastLateness;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <TimeSource.h>
|
#include <TimeSource.h>
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include <Buffer.h>
|
#include <Buffer.h>
|
||||||
|
#include <ServerInterface.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
@@ -210,6 +211,7 @@ BMediaEventLooper::ControlLoop()
|
|||||||
status_t err;
|
status_t err;
|
||||||
bigtime_t latency;
|
bigtime_t latency;
|
||||||
bigtime_t waituntil;
|
bigtime_t waituntil;
|
||||||
|
bigtime_t lateness;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// while there are no events or it is not time for the earliest event,
|
// while there are no events or it is not time for the earliest event,
|
||||||
// process messages using WaitForMessages. Whenever this funtion times out,
|
// process messages using WaitForMessages. Whenever this funtion times out,
|
||||||
@@ -222,31 +224,37 @@ BMediaEventLooper::ControlLoop()
|
|||||||
// only the scheduling latency).
|
// only the scheduling latency).
|
||||||
|
|
||||||
latency = fEventLatency + fSchedulingLatency;
|
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;
|
waituntil = B_INFINITE_TIMEOUT;
|
||||||
if (fEventQueue.HasEvents()) {
|
if (fEventQueue.HasEvents()) {
|
||||||
waituntil = TimeSource()->RealTimeFor(fEventQueue.FirstEventTime(), latency);
|
const media_timed_event *firstEvent = fEventQueue.FirstEvent();
|
||||||
// printf("node %02d waiting for %12Ld that will happen at %12Ld\n", ID(), fEventQueue.FirstEventTime(), waituntil);
|
waituntil = TimeSource()->RealTimeFor(firstEvent->event_time, latency);
|
||||||
is_realtime = false;
|
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()) {
|
if (fRealTimeQueue.HasEvents()) {
|
||||||
|
const media_timed_event *firstEvent = fRealTimeQueue.FirstEvent();
|
||||||
bigtime_t temp;
|
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) {
|
if (temp < waituntil) {
|
||||||
waituntil = temp;
|
waituntil = temp;
|
||||||
is_realtime = true;
|
is_realtime = true;
|
||||||
latency = fSchedulingLatency;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lateness = 0; // remove any extraneous value if we get this far
|
||||||
err = WaitForMessage(waituntil);
|
err = WaitForMessage(waituntil);
|
||||||
if (err == B_TIMED_OUT)
|
if (err == B_TIMED_OUT)
|
||||||
break;
|
break;
|
||||||
@@ -258,16 +266,9 @@ BMediaEventLooper::ControlLoop()
|
|||||||
else
|
else
|
||||||
err = fEventQueue.RemoveFirstEvent(&event);
|
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) {
|
if (err == B_OK) DispatchEvent(&event, lateness, is_realtime);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,6 +389,7 @@ BMediaEventLooper::SetEventLatency(bigtime_t latency)
|
|||||||
latency = 0;
|
latency = 0;
|
||||||
|
|
||||||
fEventLatency = latency;
|
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",
|
TRACE("BMediaNode::WaitForMessage request is: %#lx, node %ld, this %p\n",
|
||||||
message, fNodeID, this);
|
message, fNodeID, this);
|
||||||
|
|
||||||
|
if (message == GENERAL_PURPOSE_WAKEUP) return B_OK; // no action needed
|
||||||
|
|
||||||
if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
|
if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
|
||||||
TRACE("BMediaNode::WaitForMessage calling BMediaNode\n");
|
TRACE("BMediaNode::WaitForMessage calling BMediaNode\n");
|
||||||
if (B_OK == BMediaNode::HandleMessage(message, data, size))
|
if (B_OK == BMediaNode::HandleMessage(message, data, size))
|
||||||
|
|||||||
@@ -29,16 +29,19 @@
|
|||||||
|
|
||||||
/* Implements _event_queue_imp used by BTimedEventQueue, not thread save!
|
/* Implements _event_queue_imp used by BTimedEventQueue, not thread save!
|
||||||
*/
|
*/
|
||||||
#include <TimedEventQueue.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Buffer.h>
|
#include <Buffer.h>
|
||||||
#include <InterfaceDefs.h> //defines B_DELETE
|
#include <InterfaceDefs.h> //defines B_DELETE
|
||||||
|
#include <TimedEventQueue.h>
|
||||||
|
#include <TimeSource.h>
|
||||||
|
|
||||||
#include "TimedEventQueuePrivate.h"
|
#include "TimedEventQueuePrivate.h"
|
||||||
|
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
_event_queue_imp::_event_queue_imp() :
|
_event_queue_imp::_event_queue_imp() :
|
||||||
fLock(new BLocker("BTimedEventQueue locker")),
|
fLock(new BLocker("BTimedEventQueue locker")),
|
||||||
fEventCount(0),
|
fEventCount(0),
|
||||||
@@ -74,6 +77,8 @@ _event_queue_imp::AddEvent(const media_timed_event &event)
|
|||||||
if (event.type <= 0) {
|
if (event.type <= 0) {
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*(bigtime_t *)&event.queued_time = BTimeSource::RealTime();
|
||||||
|
|
||||||
//create a new queue
|
//create a new queue
|
||||||
if (fFirstEntry == NULL) {
|
if (fFirstEntry == NULL) {
|
||||||
|
|||||||
Reference in New Issue
Block a user