1//------------------------------------------------------------------------------ 2// Copyright (c) 2001-2002, OpenBeOS 3// 4// Permission is hereby granted, free of charge, to any person obtaining a 5// copy of this software and associated documentation files (the "Software"), 6// to deal in the Software without restriction, including without limitation 7// the rights to use, copy, modify, merge, publish, distribute, sublicense, 8// and/or sell copies of the Software, and to permit persons to whom the 9// Software is furnished to do so, subject to the following conditions: 10// 11// The above copyright notice and this permission notice shall be included in 12// all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20// DEALINGS IN THE SOFTWARE. 21// 22// File Name: BGameSoundDevice.cpp 23// Author: Christopher ML Zumwalt May (zummy@users.sf.net) 24// Description: Manages the game producer. The class may change with out 25// notice and was only inteneded for use by the GameKit at 26// this time. Use at your own risk. 27//------------------------------------------------------------------------------ 28 29 30#include "GameSoundDevice.h" 31 32#include <stdlib.h> 33#include <stdio.h> 34#include <string.h> 35 36#include <Autolock.h> 37#include <List.h> 38#include <Locker.h> 39#include <MediaAddOn.h> 40#include <MediaRoster.h> 41#include <MediaTheme.h> 42#include <TimeSource.h> 43 44#include "GameSoundBuffer.h" 45#include "GameProducer.h" 46#include "GSUtility.h" 47 48 49// BGameSoundDevice definitions ------------------------------------ 50const int32 kInitSoundCount = 32; 51const int32 kGrowth = 16; 52 53static int32 sDeviceCount = 0; 54static BGameSoundDevice* sDevice = NULL; 55static BLocker sDeviceRefCountLock = BLocker("GameSound device lock"); 56 57 58BGameSoundDevice* 59GetDefaultDevice() 60{ 61 BAutolock _(sDeviceRefCountLock); 62 63 if (!sDevice) 64 sDevice = new BGameSoundDevice(); 65 66 sDeviceCount++; 67 return sDevice; 68} 69 70 71void 72ReleaseDevice() 73{ 74 BAutolock _(sDeviceRefCountLock); 75 76 sDeviceCount--; 77 78 if (sDeviceCount <= 0) { 79 delete sDevice; 80 sDevice = NULL; 81 } 82} 83 84 85// BGameSoundDevice ------------------------------------------------------- 86BGameSoundDevice::BGameSoundDevice() 87 : 88 fIsConnected(false), 89 fSoundCount(kInitSoundCount) 90{ 91 memset(&fFormat, 0, sizeof(gs_audio_format)); 92 93 fInitError = B_OK; 94 95 fSounds = new GameSoundBuffer*[kInitSoundCount]; 96 for (int32 i = 0; i < kInitSoundCount; i++) 97 fSounds[i] = NULL; 98} 99 100 101BGameSoundDevice::~BGameSoundDevice() 102{ 103 // We need to stop all the sounds before we stop the mixer 104 for (int32 i = 0; i < fSoundCount; i++) { 105 if (fSounds[i]) 106 fSounds[i]->StopPlaying(); 107 delete fSounds[i]; 108 } 109 110 delete[] fSounds; 111} 112 113 114status_t 115BGameSoundDevice::InitCheck() const 116{ 117 return fInitError; 118} 119 120 121const gs_audio_format& 122BGameSoundDevice::Format() const 123{ 124 return fFormat; 125} 126 127 128const gs_audio_format& 129BGameSoundDevice::Format(gs_id sound) const 130{ 131 return fSounds[sound - 1]->Format(); 132} 133 134 135void 136BGameSoundDevice::SetInitError(status_t error) 137{ 138 fInitError = error; 139} 140 141 142status_t 143BGameSoundDevice::CreateBuffer(gs_id* sound, const gs_audio_format* format, 144 const void* data, int64 frames) 145{ 146 if (frames <= 0 || !sound) 147 return B_BAD_VALUE; 148 149 status_t err = B_MEDIA_TOO_MANY_BUFFERS; 150 int32 position = AllocateSound(); 151 152 if (position >= 0) { 153 media_node systemMixer; 154 BMediaRoster::Roster()->GetAudioMixer(&systemMixer); 155 fSounds[position] = new SimpleSoundBuffer(format, data, frames); 156 err = fSounds[position]->Connect(&systemMixer); 157 } 158 159 if (err == B_OK) 160 *sound = gs_id(position + 1); 161 return err; 162} 163 164 165status_t 166BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object, 167 const gs_audio_format* format, size_t inBufferFrameCount, 168 size_t inBufferCount) 169{ 170 if (!object || !sound) 171 return B_BAD_VALUE; 172 173 status_t err = B_MEDIA_TOO_MANY_BUFFERS; 174 int32 position = AllocateSound(); 175 176 if (position >= 0) { 177 media_node systemMixer; 178 BMediaRoster::Roster()->GetAudioMixer(&systemMixer); 179 fSounds[position] = new StreamingSoundBuffer(format, object, 180 inBufferFrameCount, inBufferCount); 181 err = fSounds[position]->Connect(&systemMixer); 182 } 183 184 if (err == B_OK) 185 *sound = gs_id(position + 1); 186 return err; 187} 188 189 190void 191BGameSoundDevice::ReleaseBuffer(gs_id sound) 192{ 193 if (sound <= 0) 194 return; 195 196 if (fSounds[sound - 1]) { 197 // We must stop playback befor destroying the sound or else 198 // we may receive fatal errors. 199 fSounds[sound - 1]->StopPlaying(); 200 201 delete fSounds[sound - 1]; 202 fSounds[sound - 1] = NULL; 203 } 204} 205 206 207status_t 208BGameSoundDevice::Buffer(gs_id sound, gs_audio_format* format, void*& data) 209{ 210 if (!format || sound <= 0) 211 return B_BAD_VALUE; 212 213 memcpy(format, &fSounds[sound - 1]->Format(), sizeof(gs_audio_format)); 214 if (fSounds[sound - 1]->Data()) { 215 data = malloc(format->buffer_size); 216 memcpy(data, fSounds[sound - 1]->Data(), format->buffer_size); 217 } else 218 data = NULL; 219 220 return B_OK; 221} 222 223 224status_t 225BGameSoundDevice::StartPlaying(gs_id sound) 226{ 227 if (sound <= 0) 228 return B_BAD_VALUE; 229 230 if (!fSounds[sound - 1]->IsPlaying()) { 231 // tell the producer to start playing the sound 232 return fSounds[sound - 1]->StartPlaying(); 233 } 234 235 fSounds[sound - 1]->Reset(); 236 return EALREADY; 237} 238 239 240status_t 241BGameSoundDevice::StopPlaying(gs_id sound) 242{ 243 if (sound <= 0) 244 return B_BAD_VALUE; 245 246 if (fSounds[sound - 1]->IsPlaying()) { 247 // Tell the producer to stop play this sound 248 fSounds[sound - 1]->Reset(); 249 return fSounds[sound - 1]->StopPlaying(); 250 } 251 252 return EALREADY; 253} 254 255 256bool 257BGameSoundDevice::IsPlaying(gs_id sound) 258{ 259 if (sound <= 0) 260 return false; 261 return fSounds[sound - 1]->IsPlaying(); 262} 263 264 265status_t 266BGameSoundDevice::GetAttributes(gs_id sound, gs_attribute* attributes, 267 size_t attributeCount) 268{ 269 if (!fSounds[sound - 1]) 270 return B_ERROR; 271 272 return fSounds[sound - 1]->GetAttributes(attributes, attributeCount); 273} 274 275 276status_t 277BGameSoundDevice::SetAttributes(gs_id sound, gs_attribute* attributes, 278 size_t attributeCount) 279{ 280 if (!fSounds[sound - 1]) 281 return B_ERROR; 282 283 return fSounds[sound - 1]->SetAttributes(attributes, attributeCount); 284} 285 286 287int32 288BGameSoundDevice::AllocateSound() 289{ 290 for (int32 i = 0; i < fSoundCount; i++) 291 if (!fSounds[i]) 292 return i; 293 294 // we need to allocate new space for the sound 295 GameSoundBuffer ** sounds = new GameSoundBuffer*[fSoundCount + kGrowth]; 296 for (int32 i = 0; i < fSoundCount; i++) 297 sounds[i] = fSounds[i]; 298 299 for (int32 i = fSoundCount; i < fSoundCount + kGrowth; i++) 300 sounds[i] = NULL; 301 302 // replace the old list 303 delete [] fSounds; 304 fSounds = sounds; 305 fSoundCount += kGrowth; 306 307 return fSoundCount - kGrowth; 308} 309 310