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:
@@ -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;
|
||||
|
||||
@@ -146,6 +146,7 @@ private:
|
||||
size_t fFrameSize;
|
||||
int64 fFramesSent;
|
||||
GameSoundBuffer * fObject;
|
||||
size_t fBufferSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user