* Cache the silence buffer instead of allocating a new one each time and
writing zeros into it in a real time thread. * Use a different method to calculate the drift. The old method would generate a stable drift value after some time, but somehow the drift gave problems after a while. For example on Haiku, the MediaPlayer would stop playing stuff after several hours of uptime. The new method calculates the drift for just the last written buffer, like the Multi-Audio node does, but averages the result over the last 64 drift values in order to smooth out sudden changes. Seems to work well on Haiku, on BeOS, the sound quality seems to be a bit worse (the BeOS mixer actually resamples each buffer according to current drift). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26125 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -104,7 +104,7 @@ status_t OpenSoundDeviceEngine::Open(int mode)
|
||||
// HD Audio hardware, it is too short. However, I seem to remember the
|
||||
// HD Audio supports 32 bit sample width (while C-Media supports "only"
|
||||
// 16). If OSS uses the same 2048 bytes even for 32 bit/sample, then I
|
||||
// could see how that would be asking too much, since that would
|
||||
// could see how that would be asking for too much, since that would
|
||||
// effectively half the latency.
|
||||
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
|
||||
v = 5;
|
||||
|
||||
@@ -100,45 +100,20 @@ public:
|
||||
RecycleAllBuffers();
|
||||
}
|
||||
|
||||
status_t FillBuffer(BBuffer* buffer)
|
||||
status_t Write(void* data, size_t size)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
ssize_t written = fRealEngine->Write(
|
||||
buffer->Data(), buffer->SizeUsed());
|
||||
ssize_t written = fRealEngine->Write(data, size);
|
||||
|
||||
if (written < 0)
|
||||
return (status_t)written;
|
||||
if (written < (ssize_t)buffer->SizeUsed())
|
||||
if (written < (ssize_t)size)
|
||||
return B_IO_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void WriteSilence(size_t bytes)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
// TODO: A silenceBuffer could be cached!
|
||||
uint8 formatSilence = 0;
|
||||
if (fInput.format.u.raw_audio.format
|
||||
== media_raw_audio_format::B_AUDIO_UCHAR)
|
||||
formatSilence = 128;
|
||||
|
||||
size_t bufferSize = 2048;
|
||||
char buffer[bufferSize];
|
||||
|
||||
memset(buffer, formatSilence, bufferSize);
|
||||
|
||||
while (bytes) {
|
||||
size_t chunk = MIN(bytes, bufferSize);
|
||||
ssize_t written = fRealEngine->Write(buffer, chunk);
|
||||
if (written < 0)
|
||||
return;
|
||||
bytes -= written;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteTestTone(size_t bytes)
|
||||
{
|
||||
// phase of the sine wave
|
||||
@@ -1630,7 +1605,9 @@ OpenSoundNode::TimeSourceOp(const time_source_op_info& op, void* _reserved)
|
||||
}
|
||||
break;
|
||||
case B_TIMESOURCE_SEEK:
|
||||
TRACE("TimeSourceOp op B_TIMESOURCE_SEEK\n");
|
||||
// TRACE("TimeSourceOp op B_TIMESOURCE_SEEK\n");
|
||||
printf("TimeSourceOp op B_TIMESOURCE_SEEK, real %lld, "
|
||||
"perf %lld\n", op.real_time, op.performance_time);
|
||||
BroadcastTimeWarp(op.real_time, op.performance_time);
|
||||
break;
|
||||
default:
|
||||
@@ -2245,13 +2222,29 @@ OpenSoundNode::_PlayThread(NodeInput* input)
|
||||
"size: %ld", driverBufferSize, bufferSize);
|
||||
}
|
||||
|
||||
// cache a silence buffer
|
||||
uint8 silenceBuffer[bufferSize];
|
||||
uint8 formatSilence = 0;
|
||||
if (input->fInput.format.u.raw_audio.format
|
||||
== media_raw_audio_format::B_AUDIO_UCHAR)
|
||||
formatSilence = 128;
|
||||
|
||||
memset(silenceBuffer, formatSilence, bufferSize);
|
||||
|
||||
// start by writing the OSS driver buffer size of silence
|
||||
// so that the first call to write() already blocks for (almost) the
|
||||
// buffer duration
|
||||
input->WriteSilence(driverBufferSize);
|
||||
input->Write(silenceBuffer, bufferSize);
|
||||
|
||||
int64 bytesWritten = 0;
|
||||
bigtime_t realTimeStart = RealTime();
|
||||
bigtime_t lastRealTime = RealTime();
|
||||
bigtime_t lastPerformanceTime = 0;
|
||||
|
||||
const int32 driftValueCount = 64;
|
||||
int32 currentDriftValueIndex = 0;
|
||||
float driftValues[driftValueCount];
|
||||
for (int32 i = 0; i < driftValueCount; i++)
|
||||
driftValues[i] = 1.0;
|
||||
|
||||
do {
|
||||
if (!fDevice->Locker()->Lock())
|
||||
@@ -2275,47 +2268,45 @@ OpenSoundNode::_PlayThread(NodeInput* input)
|
||||
// buffer->Recycle();
|
||||
//continue;
|
||||
|
||||
int32 additionalBytesWritten = 0;
|
||||
if (buffer != NULL) {
|
||||
input->FillBuffer(buffer);
|
||||
bytesWritten += buffer->SizeUsed();
|
||||
if (input->Write(buffer->Data(), buffer->SizeUsed()) == B_OK)
|
||||
additionalBytesWritten = buffer->SizeUsed();
|
||||
buffer->Recycle();
|
||||
} else {
|
||||
if (input->fInput.source != media_source::null) {
|
||||
//printf("no buffer - silence\n");
|
||||
input->WriteSilence(bufferSize);
|
||||
bytesWritten += bufferSize;
|
||||
} else {
|
||||
//printf("no buffer - snooze\n");
|
||||
snooze(3000);
|
||||
// NOTE - stippi: I think this is what needs to happen
|
||||
// anyways, or the "drift" will be totally screwed:
|
||||
realTimeStart = RealTime();
|
||||
bytesWritten = 0;
|
||||
}
|
||||
input->Write(silenceBuffer, bufferSize);
|
||||
additionalBytesWritten = bufferSize;
|
||||
}
|
||||
|
||||
// TODO: do not assume channel 0 will always be running!
|
||||
// update the timesource
|
||||
if (input->fEngineIndex == 0 && input->fThread >= 0) {
|
||||
|
||||
bigtime_t now = RealTime();
|
||||
// NOTE stippi: I am unsure which realtime start time to use here,
|
||||
// "fTimeSourceStartTime" is the time at which the Timesource start op
|
||||
// was received, realTimeStart should be more precise though for calculating
|
||||
// the "drift":
|
||||
bigtime_t realPlaybackDuration = now - realTimeStart;
|
||||
//bigtime_t realPlaybackDuration = now - fTimeSourceStartTime;
|
||||
bigtime_t estimatedPlaybackDuration
|
||||
bigtime_t realTime = RealTime();
|
||||
bigtime_t realPlaybackDuration = realTime - lastRealTime;
|
||||
bigtime_t performanceTime
|
||||
= time_for_buffer(bytesWritten, input->fInput.format);
|
||||
float drift = (double)estimatedPlaybackDuration
|
||||
/ realPlaybackDuration;
|
||||
float drift = (double)(performanceTime
|
||||
- lastPerformanceTime) / realPlaybackDuration;
|
||||
|
||||
lastPerformanceTime = performanceTime;
|
||||
lastRealTime = realTime;
|
||||
|
||||
driftValues[currentDriftValueIndex++] = drift;
|
||||
if (currentDriftValueIndex == driftValueCount)
|
||||
currentDriftValueIndex = 0;
|
||||
drift = 0.0;
|
||||
for (int32 i = 0; i < driftValueCount; i++)
|
||||
drift += driftValues[i];
|
||||
drift /= driftValueCount;
|
||||
|
||||
if (fDevice->Locker()->Lock()) {
|
||||
if (input->fThread >= 0)
|
||||
_UpdateTimeSource(estimatedPlaybackDuration, now, drift);
|
||||
_UpdateTimeSource(performanceTime, realTime, drift);
|
||||
fDevice->Locker()->Unlock();
|
||||
}
|
||||
}
|
||||
bytesWritten += additionalBytesWritten;
|
||||
|
||||
} while (input->fThread > -1);
|
||||
|
||||
@@ -2507,8 +2498,8 @@ OpenSoundNode::_UpdateTimeSource(bigtime_t performanceTime,
|
||||
|
||||
PublishTime(performanceTime, realTime, drift);
|
||||
|
||||
// TRACE("_UpdateTimeSource() perfTime : %lli, realTime : %lli,
|
||||
// drift : %f\n", perfTime, realTime, drift);
|
||||
// TRACE("_UpdateTimeSource() perfTime : %lli, realTime : %lli, "
|
||||
// "drift : %f\n", perfTime, realTime, drift);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user