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 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 33 #include <Autolock.h> 34 #include <List.h> 35 #include <Locker.h> 36 #include <MediaRoster.h> 37 #include <MediaAddOn.h> 38 #include <TimeSource.h> 39 #include <MediaTheme.h> 40 41 #include "GSUtility.h" 42 #include "GameSoundDevice.h" 43 #include "GameSoundBuffer.h" 44 #include "GameProducer.h" 45 46 // BGameSoundDevice definitions ------------------------------------ 47 const int32 kInitSoundCount = 32; 48 const int32 kGrowth = 16; 49 50 static int32 sDeviceCount = 0; 51 static BGameSoundDevice* sDevice = NULL; 52 static BLocker sDeviceRefCountLock = BLocker("GameSound device lock"); 53 54 55 BGameSoundDevice* 56 GetDefaultDevice() 57 { 58 BAutolock _(sDeviceRefCountLock); 59 60 if (!sDevice) 61 sDevice = new BGameSoundDevice(); 62 63 sDeviceCount++; 64 return sDevice; 65 } 66 67 68 void 69 ReleaseDevice() 70 { 71 BAutolock _(sDeviceRefCountLock); 72 73 sDeviceCount--; 74 75 if (sDeviceCount <= 0) { 76 delete sDevice; 77 sDevice = NULL; 78 } 79 } 80 81 82 // BGameSoundDevice ------------------------------------------------------- 83 BGameSoundDevice::BGameSoundDevice() 84 : 85 fIsConnected(false), 86 fSoundCount(kInitSoundCount) 87 { 88 memset(&fFormat, 0, sizeof(gs_audio_format)); 89 90 fInitError = B_OK; 91 92 fSounds = new GameSoundBuffer*[kInitSoundCount]; 93 for (int32 i = 0; i < kInitSoundCount; i++) 94 fSounds[i] = NULL; 95 } 96 97 98 BGameSoundDevice::~BGameSoundDevice() 99 { 100 // We need to stop all the sounds before we stop the mixer 101 for (int32 i = 0; i < fSoundCount; i++) { 102 if (fSounds[i]) 103 fSounds[i]->StopPlaying(); 104 delete fSounds[i]; 105 } 106 107 delete[] fSounds; 108 } 109 110 111 status_t 112 BGameSoundDevice::InitCheck() const 113 { 114 return fInitError; 115 } 116 117 118 const gs_audio_format& 119 BGameSoundDevice::Format() const 120 { 121 return fFormat; 122 } 123 124 125 const gs_audio_format& 126 BGameSoundDevice::Format(gs_id sound) const 127 { 128 return fSounds[sound - 1]->Format(); 129 } 130 131 132 void 133 BGameSoundDevice::SetInitError(status_t error) 134 { 135 fInitError = error; 136 } 137 138 139 status_t 140 BGameSoundDevice::CreateBuffer(gs_id* sound, const gs_audio_format* format, 141 const void* data, int64 frames) 142 { 143 if (frames <= 0 || !sound) 144 return B_BAD_VALUE; 145 146 status_t err = B_MEDIA_TOO_MANY_BUFFERS; 147 int32 position = AllocateSound(); 148 149 if (position >= 0) { 150 media_node systemMixer; 151 BMediaRoster::Roster()->GetAudioMixer(&systemMixer); 152 fSounds[position] = new SimpleSoundBuffer(format, data, frames); 153 err = fSounds[position]->Connect(&systemMixer); 154 } 155 156 if (err == B_OK) 157 *sound = gs_id(position + 1); 158 return err; 159 } 160 161 162 status_t 163 BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object, 164 const gs_audio_format* format, size_t inBufferFrameCount, 165 size_t inBufferCount) 166 { 167 if (!object || !sound) 168 return B_BAD_VALUE; 169 170 status_t err = B_MEDIA_TOO_MANY_BUFFERS; 171 int32 position = AllocateSound(); 172 173 if (position >= 0) { 174 media_node systemMixer; 175 BMediaRoster::Roster()->GetAudioMixer(&systemMixer); 176 fSounds[position] = new StreamingSoundBuffer(format, object, 177 inBufferFrameCount, inBufferCount); 178 err = fSounds[position]->Connect(&systemMixer); 179 } 180 181 if (err == B_OK) 182 *sound = gs_id(position+1); 183 return err; 184 } 185 186 187 void 188 BGameSoundDevice::ReleaseBuffer(gs_id sound) 189 { 190 if (sound <= 0) 191 return; 192 193 if (fSounds[sound - 1]) { 194 // We must stop playback befor destroying the sound or else 195 // we may recieve fatel errors. 196 fSounds[sound - 1]->StopPlaying(); 197 198 delete fSounds[sound - 1]; 199 fSounds[sound - 1] = NULL; 200 } 201 } 202 203 204 status_t 205 BGameSoundDevice::Buffer(gs_id sound, gs_audio_format* format, void*& data) 206 { 207 if (!format || sound <= 0) 208 return B_BAD_VALUE; 209 210 memcpy(format, &fSounds[sound-1]->Format(), sizeof(gs_audio_format)); 211 if (fSounds[sound-1]->Data()) { 212 data = malloc(format->buffer_size); 213 memcpy(data, fSounds[sound-1]->Data(), format->buffer_size); 214 } else 215 data = NULL; 216 217 return B_OK; 218 } 219 220 221 status_t 222 BGameSoundDevice::StartPlaying(gs_id sound) 223 { 224 if (sound <= 0) 225 return B_BAD_VALUE; 226 227 if (!fSounds[sound - 1]->IsPlaying()) { 228 // tell the producer to start playing the sound 229 return fSounds[sound - 1]->StartPlaying(); 230 } 231 232 fSounds[sound - 1]->Reset(); 233 return EALREADY; 234 } 235 236 237 status_t 238 BGameSoundDevice::StopPlaying(gs_id sound) 239 { 240 if (sound <= 0) 241 return B_BAD_VALUE; 242 243 if (fSounds[sound - 1]->IsPlaying()) { 244 // Tell the producer to stop play this sound 245 fSounds[sound - 1]->Reset(); 246 return fSounds[sound - 1]->StopPlaying(); 247 } 248 249 return EALREADY; 250 } 251 252 253 bool 254 BGameSoundDevice::IsPlaying(gs_id sound) 255 { 256 if (sound <= 0) 257 return false; 258 return fSounds[sound - 1]->IsPlaying(); 259 } 260 261 262 status_t 263 BGameSoundDevice::GetAttributes(gs_id sound, gs_attribute* attributes, 264 size_t attributeCount) 265 { 266 if (!fSounds[sound - 1]) 267 return B_ERROR; 268 269 return fSounds[sound - 1]->GetAttributes(attributes, attributeCount); 270 } 271 272 273 status_t 274 BGameSoundDevice::SetAttributes(gs_id sound, gs_attribute* attributes, 275 size_t attributeCount) 276 { 277 if (!fSounds[sound - 1]) 278 return B_ERROR; 279 280 return fSounds[sound - 1]->SetAttributes(attributes, attributeCount); 281 } 282 283 284 int32 285 BGameSoundDevice::AllocateSound() 286 { 287 for (int32 i = 0; i < fSoundCount; i++) 288 if (!fSounds[i]) 289 return i; 290 291 // we need to allocate new space for the sound 292 GameSoundBuffer ** sounds = new GameSoundBuffer*[fSoundCount + kGrowth]; 293 for (int32 i = 0; i < fSoundCount; i++) 294 sounds[i] = fSounds[i]; 295 296 for (int32 i = fSoundCount; i < fSoundCount + kGrowth; i++) 297 sounds[i] = NULL; 298 299 // replace the old list 300 delete [] fSounds; 301 fSounds = sounds; 302 fSoundCount += kGrowth; 303 304 return fSoundCount - kGrowth; 305 } 306 307