#include "GameSoundDevice.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Autolock.h>
#include <List.h>
#include <Locker.h>
#include <MediaAddOn.h>
#include <MediaRoster.h>
#include <MediaTheme.h>
#include <TimeSource.h>
#include "GameSoundBuffer.h"
#include "GameProducer.h"
#include "GSUtility.h"
const int32 kInitSoundCount = 32;
const int32 kGrowth = 16;
static int32 sDeviceCount = 0;
static BGameSoundDevice* sDevice = NULL;
static BLocker sDeviceRefCountLock("GameSound device lock");
BGameSoundDevice*
GetDefaultDevice()
{
BAutolock _(sDeviceRefCountLock);
if (!sDevice)
sDevice = new BGameSoundDevice();
sDeviceCount++;
return sDevice;
}
void
ReleaseDevice()
{
BAutolock _(sDeviceRefCountLock);
sDeviceCount--;
if (sDeviceCount <= 0) {
delete sDevice;
sDevice = NULL;
}
}
BGameSoundDevice::BGameSoundDevice()
:
fIsConnected(false),
fSoundCount(kInitSoundCount)
{
memset(&fFormat, 0, sizeof(gs_audio_format));
fInitError = B_OK;
fSounds = new GameSoundBuffer*[kInitSoundCount];
for (int32 i = 0; i < kInitSoundCount; i++)
fSounds[i] = NULL;
}
BGameSoundDevice::~BGameSoundDevice()
{
for (int32 i = 0; i < fSoundCount; i++) {
if (fSounds[i])
fSounds[i]->StopPlaying();
delete fSounds[i];
}
delete[] fSounds;
}
status_t
BGameSoundDevice::InitCheck() const
{
return fInitError;
}
const gs_audio_format&
BGameSoundDevice::Format() const
{
return fFormat;
}
const gs_audio_format&
BGameSoundDevice::Format(gs_id sound) const
{
return fSounds[sound - 1]->Format();
}
void
BGameSoundDevice::SetInitError(status_t error)
{
fInitError = error;
}
status_t
BGameSoundDevice::CreateBuffer(gs_id* sound, const gs_audio_format* format,
const void* data, int64 frames)
{
if (frames <= 0 || !sound)
return B_BAD_VALUE;
BMediaRoster* roster = BMediaRoster::Roster();
status_t err = B_MEDIA_TOO_MANY_BUFFERS;
int32 position = AllocateSound();
if (position >= 0) {
fSounds[position] = new SimpleSoundBuffer(format, data, frames);
media_node systemMixer;
roster->GetAudioMixer(&systemMixer);
err = fSounds[position]->Connect(&systemMixer);
}
if (err == B_OK)
*sound = gs_id(position + 1);
return err;
}
status_t
BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
const gs_audio_format* format, size_t inBufferFrameCount,
size_t inBufferCount)
{
if (!object || !sound)
return B_BAD_VALUE;
BMediaRoster* roster = BMediaRoster::Roster();
status_t err = B_MEDIA_TOO_MANY_BUFFERS;
int32 position = AllocateSound();
if (position >= 0) {
fSounds[position] = new StreamingSoundBuffer(format, object,
inBufferFrameCount, inBufferCount);
media_node systemMixer;
roster->GetAudioMixer(&systemMixer);
err = fSounds[position]->Connect(&systemMixer);
}
if (err == B_OK)
*sound = gs_id(position + 1);
return err;
}
void
BGameSoundDevice::ReleaseBuffer(gs_id sound)
{
if (sound <= 0)
return;
if (fSounds[sound - 1]) {
fSounds[sound - 1]->StopPlaying();
delete fSounds[sound - 1];
fSounds[sound - 1] = NULL;
}
}
status_t
BGameSoundDevice::Buffer(gs_id sound, gs_audio_format* format, void*& data)
{
if (!format || sound <= 0)
return B_BAD_VALUE;
memcpy(format, &fSounds[sound - 1]->Format(), sizeof(gs_audio_format));
if (fSounds[sound - 1]->Data()) {
data = malloc(format->buffer_size);
memcpy(data, fSounds[sound - 1]->Data(), format->buffer_size);
} else
data = NULL;
return B_OK;
}
status_t
BGameSoundDevice::StartPlaying(gs_id sound)
{
if (sound <= 0)
return B_BAD_VALUE;
if (!fSounds[sound - 1]->IsPlaying()) {
return fSounds[sound - 1]->StartPlaying();
}
fSounds[sound - 1]->Reset();
return EALREADY;
}
status_t
BGameSoundDevice::StopPlaying(gs_id sound)
{
if (sound <= 0)
return B_BAD_VALUE;
if (fSounds[sound - 1]->IsPlaying()) {
fSounds[sound - 1]->Reset();
return fSounds[sound - 1]->StopPlaying();
}
return EALREADY;
}
bool
BGameSoundDevice::IsPlaying(gs_id sound)
{
if (sound <= 0)
return false;
return fSounds[sound - 1]->IsPlaying();
}
status_t
BGameSoundDevice::GetAttributes(gs_id sound, gs_attribute* attributes,
size_t attributeCount)
{
if (!fSounds[sound - 1])
return B_ERROR;
return fSounds[sound - 1]->GetAttributes(attributes, attributeCount);
}
status_t
BGameSoundDevice::SetAttributes(gs_id sound, gs_attribute* attributes,
size_t attributeCount)
{
if (!fSounds[sound - 1])
return B_ERROR;
return fSounds[sound - 1]->SetAttributes(attributes, attributeCount);
}
int32
BGameSoundDevice::AllocateSound()
{
for (int32 i = 0; i < fSoundCount; i++)
if (!fSounds[i])
return i;
GameSoundBuffer ** sounds = new GameSoundBuffer*[fSoundCount + kGrowth];
for (int32 i = 0; i < fSoundCount; i++)
sounds[i] = fSounds[i];
for (int32 i = fSoundCount; i < fSoundCount + kGrowth; i++)
sounds[i] = NULL;
delete [] fSounds;
fSounds = sounds;
fSoundCount += kGrowth;
return fSoundCount - kGrowth;
}