Patch from bkmx.

Fixes crashes in the game sound code when using small buffers.

Closes #5093, but there are other issues left.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@43128 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues
2011-11-02 20:05:31 +00:00
parent d3fdcc312a
commit 0cc215800b
7 changed files with 47 additions and 22 deletions
+21 -12
View File
@@ -214,11 +214,15 @@ GameProducer::Connect(status_t error, const media_source& source, const media_de
media_node_id id;
FindLatencyFor(fOutput.destination, &fLatency, &id);
if (!fBufferGroup)
fBufferSize = fOutput.format.u.raw_audio.buffer_size;
// Have to set it before latency calculating
// Use a dry run to see how long it takes me to fill a buffer of data
// The first step to setup the buffer
bigtime_t start, produceLatency;
int32 frames = int32(fOutput.format.u.raw_audio.buffer_size / fFrameSize);
int32 frames = int32(fBufferSize / fFrameSize);
float* data = new float[frames * 2];
// Second, fill the buffer
@@ -243,9 +247,8 @@ GameProducer::Connect(status_t error, const media_source& source, const media_de
// Set up the buffer group for our connection, as long as nobody handed us a
// buffer group (via SetBufferGroup()) prior to this.
if (!fBufferGroup) {
size_t size = fOutput.format.u.raw_audio.buffer_size;
int32 count = int32(fLatency / BufferDuration() + 2);
fBufferGroup = new BBufferGroup(size, count);
fBufferGroup = new BBufferGroup(fBufferSize, count);
}
}
@@ -292,12 +295,18 @@ GameProducer::SetBufferGroup(const media_source& for_source, BBufferGroup* newGr
if (newGroup != NULL) {
// we were given a valid group; just use that one from now on
fBufferGroup = newGroup;
// get buffer length from the first buffer
BBuffer *buffers[1];
if (newGroup->GetBufferList(1, buffers) != B_OK)
return B_BAD_VALUE;
fBufferSize = buffers[0]->SizeAvailable();
} else {
// we were passed a NULL group pointer; that means we construct
// our own buffer group to use from now on
size_t size = fOutput.format.u.raw_audio.buffer_size;
fBufferSize = fOutput.format.u.raw_audio.buffer_size;
int32 count = int32(fLatency / BufferDuration() + 2);
fBufferGroup = new BBufferGroup(size, count);
fBufferGroup = new BBufferGroup(fBufferSize, count);
}
return B_OK;
@@ -336,7 +345,7 @@ GameProducer::LateNoticeReceived(const media_source& what, bigtime_t how_much, b
// The other run modes dictate various strategies for sacrificing data quality
// in the interests of timely data delivery. The way *we* do this is to skip
// a buffer, which catches us up in time by one buffer duration.
size_t nSamples = fOutput.format.u.raw_audio.buffer_size / fFrameSize;
size_t nSamples = fBufferSize / fFrameSize;
fFramesSent += nSamples;
}
}
@@ -460,7 +469,7 @@ GameProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, bo
}
// track how much media we've delivered so far
size_t nFrames = fOutput.format.u.raw_audio.buffer_size / fFrameSize;
size_t nFrames = fBufferSize / fFrameSize;
fFramesSent += nFrames;
// The buffer is on its way; now schedule the next one to go
@@ -479,9 +488,9 @@ GameProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, bo
BBuffer*
GameProducer::FillNextBuffer(bigtime_t event_time)
{
{
// get a buffer from our buffer group
BBuffer* buf = fBufferGroup->RequestBuffer(fOutput.format.u.raw_audio.buffer_size, BufferDuration());
BBuffer* buf = fBufferGroup->RequestBuffer(fBufferSize, BufferDuration());
// if we fail to get a buffer (for example, if the request times out), we skip this
// buffer and go on to the next, to avoid locking up the control thread
@@ -489,8 +498,8 @@ GameProducer::FillNextBuffer(bigtime_t event_time)
return NULL;
// we need to discribe the buffer
int64 frames = int64(fOutput.format.u.raw_audio.buffer_size / fFrameSize);
memset(buf->Data(), 0, fOutput.format.u.raw_audio.buffer_size);
int64 frames = int64(fBufferSize / fFrameSize);
memset(buf->Data(), 0, fBufferSize);
// now fill the buffer with data, continuing where the last buffer left off
fObject->Play(buf->Data(), frames);
@@ -498,7 +507,7 @@ GameProducer::FillNextBuffer(bigtime_t event_time)
// fill in the buffer header
media_header* hdr = buf->Header();
hdr->type = B_MEDIA_RAW_AUDIO;
hdr->size_used = fOutput.format.u.raw_audio.buffer_size;
hdr->size_used = fBufferSize;
hdr->time_source = TimeSource()->ID();
bigtime_t stamp;
+1
View File
@@ -146,6 +146,7 @@ private:
size_t fFrameSize;
int64 fFramesSent;
GameSoundBuffer * fObject;
size_t fBufferSize;
};
#endif
+9 -3
View File
@@ -32,6 +32,7 @@
#include <MediaAddOn.h>
#include <MediaTheme.h>
#include <TimeSource.h>
#include <BufferGroup.h>
#include "GameProducer.h"
#include "GameSoundBuffer.h"
@@ -271,7 +272,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
pan[1] = fPanLeft;
char * buffer = new char[fFrameSize * frames];
FillBuffer(buffer, frames);
switch (fFormat.format) {
@@ -533,11 +534,17 @@ SimpleSoundBuffer::FillBuffer(void * data, int64 frames)
// StreamingSoundBuffer ------------------------------------------------------
StreamingSoundBuffer::StreamingSoundBuffer(const gs_audio_format * format,
const void * streamHook)
const void * streamHook, size_t inBufferFrameCount,
size_t inBufferCount)
:
GameSoundBuffer(format),
fStreamHook(const_cast<void *>(streamHook))
{
if (inBufferFrameCount != 0 && inBufferCount != 0) {
BBufferGroup *bufferGroup = new BBufferGroup(inBufferFrameCount
* fFrameSize, inBufferCount);
fNode->SetBufferGroup(fConnection->source, bufferGroup);
}
}
@@ -554,4 +561,3 @@ StreamingSoundBuffer::FillBuffer(void * buffer, int64 frames)
size_t bytes = fFrameSize * frames;
object->FillBuffer(buffer, bytes);
}
+6 -3
View File
@@ -65,10 +65,11 @@ protected:
size_t fFrameSize;
private:
Connection * fConnection;
GameProducer * fNode;
private:
bool fIsConnected;
bool fIsPlaying;
@@ -103,7 +104,9 @@ private:
class StreamingSoundBuffer : public GameSoundBuffer {
public:
StreamingSoundBuffer(const gs_audio_format * format,
const void * streamHook);
const void * streamHook,
size_t inBufferFrameCount,
size_t inBufferCount);
virtual ~StreamingSoundBuffer();
protected:
+4 -2
View File
@@ -161,7 +161,8 @@ BGameSoundDevice::CreateBuffer(gs_id* sound, const gs_audio_format* format,
status_t
BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
const gs_audio_format* format)
const gs_audio_format* format, size_t inBufferFrameCount,
size_t inBufferCount)
{
if (!object || !sound)
return B_BAD_VALUE;
@@ -172,7 +173,8 @@ BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
if (position >= 0) {
media_node systemMixer;
BMediaRoster::Roster()->GetAudioMixer(&systemMixer);
fSounds[position] = new StreamingSoundBuffer(format, object);
fSounds[position] = new StreamingSoundBuffer(format, object,
inBufferFrameCount, inBufferCount);
err = fSounds[position]->Connect(&systemMixer);
}
+4 -1
View File
@@ -51,7 +51,9 @@ public:
int64 frames);
virtual status_t CreateBuffer(gs_id * sound,
const void * object,
const gs_audio_format * format);
const gs_audio_format * format,
size_t inBufferFrameCount = 0,
size_t inBufferCount = 0);
virtual void ReleaseBuffer(gs_id sound);
virtual status_t Buffer(gs_id sound,
@@ -73,6 +75,7 @@ protected:
void SetInitError(status_t error);
gs_audio_format fFormat;
private:
int32 AllocateSound();
+2 -1
View File
@@ -106,7 +106,8 @@ BStreamingGameSound::SetParameters(size_t inBufferFrameCount,
size_t inBufferCount)
{
gs_id sound;
status_t error = Device()->CreateBuffer(&sound, this, format);
status_t error = Device()->CreateBuffer(&sound, this, format,
inBufferFrameCount, inBufferCount);
if (error != B_OK) return error;
return BGameSound::Init(sound);