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;
|
media_node_id id;
|
||||||
FindLatencyFor(fOutput.destination, &fLatency, &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
|
// Use a dry run to see how long it takes me to fill a buffer of data
|
||||||
|
|
||||||
// The first step to setup the buffer
|
// The first step to setup the buffer
|
||||||
bigtime_t start, produceLatency;
|
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];
|
float* data = new float[frames * 2];
|
||||||
|
|
||||||
// Second, fill the buffer
|
// 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
|
// Set up the buffer group for our connection, as long as nobody handed us a
|
||||||
// buffer group (via SetBufferGroup()) prior to this.
|
// buffer group (via SetBufferGroup()) prior to this.
|
||||||
if (!fBufferGroup) {
|
if (!fBufferGroup) {
|
||||||
size_t size = fOutput.format.u.raw_audio.buffer_size;
|
|
||||||
int32 count = int32(fLatency / BufferDuration() + 2);
|
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) {
|
if (newGroup != NULL) {
|
||||||
// we were given a valid group; just use that one from now on
|
// we were given a valid group; just use that one from now on
|
||||||
fBufferGroup = newGroup;
|
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 {
|
} else {
|
||||||
// we were passed a NULL group pointer; that means we construct
|
// we were passed a NULL group pointer; that means we construct
|
||||||
// our own buffer group to use from now on
|
// 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);
|
int32 count = int32(fLatency / BufferDuration() + 2);
|
||||||
fBufferGroup = new BBufferGroup(size, count);
|
fBufferGroup = new BBufferGroup(fBufferSize, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
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
|
// 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
|
// 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.
|
// 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;
|
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
|
// 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;
|
fFramesSent += nFrames;
|
||||||
|
|
||||||
// The buffer is on its way; now schedule the next one to go
|
// 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*
|
BBuffer*
|
||||||
GameProducer::FillNextBuffer(bigtime_t event_time)
|
GameProducer::FillNextBuffer(bigtime_t event_time)
|
||||||
{
|
{
|
||||||
// get a buffer from our buffer group
|
// 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
|
// 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
|
// 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;
|
return NULL;
|
||||||
|
|
||||||
// we need to discribe the buffer
|
// we need to discribe the buffer
|
||||||
int64 frames = int64(fOutput.format.u.raw_audio.buffer_size / fFrameSize);
|
int64 frames = int64(fBufferSize / fFrameSize);
|
||||||
memset(buf->Data(), 0, fOutput.format.u.raw_audio.buffer_size);
|
memset(buf->Data(), 0, fBufferSize);
|
||||||
|
|
||||||
// now fill the buffer with data, continuing where the last buffer left off
|
// now fill the buffer with data, continuing where the last buffer left off
|
||||||
fObject->Play(buf->Data(), frames);
|
fObject->Play(buf->Data(), frames);
|
||||||
@@ -498,7 +507,7 @@ GameProducer::FillNextBuffer(bigtime_t event_time)
|
|||||||
// fill in the buffer header
|
// fill in the buffer header
|
||||||
media_header* hdr = buf->Header();
|
media_header* hdr = buf->Header();
|
||||||
hdr->type = B_MEDIA_RAW_AUDIO;
|
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();
|
hdr->time_source = TimeSource()->ID();
|
||||||
|
|
||||||
bigtime_t stamp;
|
bigtime_t stamp;
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ private:
|
|||||||
size_t fFrameSize;
|
size_t fFrameSize;
|
||||||
int64 fFramesSent;
|
int64 fFramesSent;
|
||||||
GameSoundBuffer * fObject;
|
GameSoundBuffer * fObject;
|
||||||
|
size_t fBufferSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <MediaAddOn.h>
|
#include <MediaAddOn.h>
|
||||||
#include <MediaTheme.h>
|
#include <MediaTheme.h>
|
||||||
#include <TimeSource.h>
|
#include <TimeSource.h>
|
||||||
|
#include <BufferGroup.h>
|
||||||
|
|
||||||
#include "GameProducer.h"
|
#include "GameProducer.h"
|
||||||
#include "GameSoundBuffer.h"
|
#include "GameSoundBuffer.h"
|
||||||
@@ -271,7 +272,7 @@ GameSoundBuffer::Play(void * data, int64 frames)
|
|||||||
pan[1] = fPanLeft;
|
pan[1] = fPanLeft;
|
||||||
|
|
||||||
char * buffer = new char[fFrameSize * frames];
|
char * buffer = new char[fFrameSize * frames];
|
||||||
|
|
||||||
FillBuffer(buffer, frames);
|
FillBuffer(buffer, frames);
|
||||||
|
|
||||||
switch (fFormat.format) {
|
switch (fFormat.format) {
|
||||||
@@ -533,11 +534,17 @@ SimpleSoundBuffer::FillBuffer(void * data, int64 frames)
|
|||||||
|
|
||||||
// StreamingSoundBuffer ------------------------------------------------------
|
// StreamingSoundBuffer ------------------------------------------------------
|
||||||
StreamingSoundBuffer::StreamingSoundBuffer(const gs_audio_format * format,
|
StreamingSoundBuffer::StreamingSoundBuffer(const gs_audio_format * format,
|
||||||
const void * streamHook)
|
const void * streamHook, size_t inBufferFrameCount,
|
||||||
|
size_t inBufferCount)
|
||||||
:
|
:
|
||||||
GameSoundBuffer(format),
|
GameSoundBuffer(format),
|
||||||
fStreamHook(const_cast<void *>(streamHook))
|
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;
|
size_t bytes = fFrameSize * frames;
|
||||||
object->FillBuffer(buffer, bytes);
|
object->FillBuffer(buffer, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,10 +65,11 @@ protected:
|
|||||||
|
|
||||||
size_t fFrameSize;
|
size_t fFrameSize;
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Connection * fConnection;
|
Connection * fConnection;
|
||||||
GameProducer * fNode;
|
GameProducer * fNode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
bool fIsConnected;
|
bool fIsConnected;
|
||||||
bool fIsPlaying;
|
bool fIsPlaying;
|
||||||
|
|
||||||
@@ -103,7 +104,9 @@ private:
|
|||||||
class StreamingSoundBuffer : public GameSoundBuffer {
|
class StreamingSoundBuffer : public GameSoundBuffer {
|
||||||
public:
|
public:
|
||||||
StreamingSoundBuffer(const gs_audio_format * format,
|
StreamingSoundBuffer(const gs_audio_format * format,
|
||||||
const void * streamHook);
|
const void * streamHook,
|
||||||
|
size_t inBufferFrameCount,
|
||||||
|
size_t inBufferCount);
|
||||||
virtual ~StreamingSoundBuffer();
|
virtual ~StreamingSoundBuffer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ BGameSoundDevice::CreateBuffer(gs_id* sound, const gs_audio_format* format,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
|
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)
|
if (!object || !sound)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -172,7 +173,8 @@ BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
|
|||||||
if (position >= 0) {
|
if (position >= 0) {
|
||||||
media_node systemMixer;
|
media_node systemMixer;
|
||||||
BMediaRoster::Roster()->GetAudioMixer(&systemMixer);
|
BMediaRoster::Roster()->GetAudioMixer(&systemMixer);
|
||||||
fSounds[position] = new StreamingSoundBuffer(format, object);
|
fSounds[position] = new StreamingSoundBuffer(format, object,
|
||||||
|
inBufferFrameCount, inBufferCount);
|
||||||
err = fSounds[position]->Connect(&systemMixer);
|
err = fSounds[position]->Connect(&systemMixer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ public:
|
|||||||
int64 frames);
|
int64 frames);
|
||||||
virtual status_t CreateBuffer(gs_id * sound,
|
virtual status_t CreateBuffer(gs_id * sound,
|
||||||
const void * object,
|
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 void ReleaseBuffer(gs_id sound);
|
||||||
|
|
||||||
virtual status_t Buffer(gs_id sound,
|
virtual status_t Buffer(gs_id sound,
|
||||||
@@ -73,6 +75,7 @@ protected:
|
|||||||
void SetInitError(status_t error);
|
void SetInitError(status_t error);
|
||||||
|
|
||||||
gs_audio_format fFormat;
|
gs_audio_format fFormat;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32 AllocateSound();
|
int32 AllocateSound();
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,8 @@ BStreamingGameSound::SetParameters(size_t inBufferFrameCount,
|
|||||||
size_t inBufferCount)
|
size_t inBufferCount)
|
||||||
{
|
{
|
||||||
gs_id sound;
|
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;
|
if (error != B_OK) return error;
|
||||||
|
|
||||||
return BGameSound::Init(sound);
|
return BGameSound::Init(sound);
|
||||||
|
|||||||
Reference in New Issue
Block a user