xref: /haiku/src/kits/game/GameSoundDevice.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, Haiku
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 ------------------------------------
50 const int32 kInitSoundCount = 32;
51 const int32 kGrowth = 16;
52 
53 static int32 sDeviceCount = 0;
54 static BGameSoundDevice* sDevice = NULL;
55 static BLocker sDeviceRefCountLock("GameSound device lock");
56 
57 
58 BGameSoundDevice*
59 GetDefaultDevice()
60 {
61 	BAutolock _(sDeviceRefCountLock);
62 
63 	if (!sDevice)
64 		sDevice = new BGameSoundDevice();
65 
66 	sDeviceCount++;
67 	return sDevice;
68 }
69 
70 
71 void
72 ReleaseDevice()
73 {
74 	BAutolock _(sDeviceRefCountLock);
75 
76 	sDeviceCount--;
77 
78 	if (sDeviceCount <= 0) {
79 		delete sDevice;
80 		sDevice = NULL;
81 	}
82 }
83 
84 
85 // BGameSoundDevice -------------------------------------------------------
86 BGameSoundDevice::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 
101 BGameSoundDevice::~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 
114 status_t
115 BGameSoundDevice::InitCheck() const
116 {
117 	return fInitError;
118 }
119 
120 
121 const gs_audio_format&
122 BGameSoundDevice::Format() const
123 {
124 	return fFormat;
125 }
126 
127 
128 const gs_audio_format&
129 BGameSoundDevice::Format(gs_id sound) const
130 {
131 	return fSounds[sound - 1]->Format();
132 }
133 
134 
135 void
136 BGameSoundDevice::SetInitError(status_t error)
137 {
138 	fInitError = error;
139 }
140 
141 
142 status_t
143 BGameSoundDevice::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 	// Make sure BMediaRoster is created before we AllocateSound()
150 	BMediaRoster* roster = BMediaRoster::Roster();
151 
152 	status_t err = B_MEDIA_TOO_MANY_BUFFERS;
153 	int32 position = AllocateSound();
154 
155 	if (position >= 0) {
156 		fSounds[position] = new SimpleSoundBuffer(format, data, frames);
157 
158 		media_node systemMixer;
159 		roster->GetAudioMixer(&systemMixer);
160 		err = fSounds[position]->Connect(&systemMixer);
161 	}
162 
163 	if (err == B_OK)
164 		*sound = gs_id(position + 1);
165 	return err;
166 }
167 
168 
169 status_t
170 BGameSoundDevice::CreateBuffer(gs_id* sound, const void* object,
171 	const gs_audio_format* format, size_t inBufferFrameCount,
172 	size_t inBufferCount)
173 {
174 	if (!object || !sound)
175 		return B_BAD_VALUE;
176 
177 	// Make sure BMediaRoster is created before we AllocateSound()
178 	BMediaRoster* roster = BMediaRoster::Roster();
179 
180 	status_t err = B_MEDIA_TOO_MANY_BUFFERS;
181 	int32 position = AllocateSound();
182 
183 	if (position >= 0) {
184 		fSounds[position] = new StreamingSoundBuffer(format, object,
185 			inBufferFrameCount, inBufferCount);
186 
187 		media_node systemMixer;
188 		roster->GetAudioMixer(&systemMixer);
189 		err = fSounds[position]->Connect(&systemMixer);
190 	}
191 
192 	if (err == B_OK)
193 		*sound = gs_id(position + 1);
194 	return err;
195 }
196 
197 
198 void
199 BGameSoundDevice::ReleaseBuffer(gs_id sound)
200 {
201 	if (sound <= 0)
202 		return;
203 
204 	if (fSounds[sound - 1]) {
205 		// We must stop playback befor destroying the sound or else
206 		// we may receive fatal errors.
207 		fSounds[sound - 1]->StopPlaying();
208 
209 		delete fSounds[sound - 1];
210 		fSounds[sound - 1] = NULL;
211 	}
212 }
213 
214 
215 status_t
216 BGameSoundDevice::Buffer(gs_id sound, gs_audio_format* format, void*& data)
217 {
218 	if (!format || sound <= 0)
219 		return B_BAD_VALUE;
220 
221 	memcpy(format, &fSounds[sound - 1]->Format(), sizeof(gs_audio_format));
222 	if (fSounds[sound - 1]->Data()) {
223 		data = malloc(format->buffer_size);
224 		memcpy(data, fSounds[sound - 1]->Data(), format->buffer_size);
225 	} else
226 		data = NULL;
227 
228 	return B_OK;
229 }
230 
231 
232 status_t
233 BGameSoundDevice::StartPlaying(gs_id sound)
234 {
235 	if (sound <= 0)
236 		return B_BAD_VALUE;
237 
238 	if (!fSounds[sound - 1]->IsPlaying()) {
239 		// tell the producer to start playing the sound
240 		return fSounds[sound - 1]->StartPlaying();
241 	}
242 
243 	fSounds[sound - 1]->Reset();
244 	return EALREADY;
245 }
246 
247 
248 status_t
249 BGameSoundDevice::StopPlaying(gs_id sound)
250 {
251 	if (sound <= 0)
252 		return B_BAD_VALUE;
253 
254 	if (fSounds[sound - 1]->IsPlaying()) {
255 		// Tell the producer to stop play this sound
256 		fSounds[sound - 1]->Reset();
257 		return fSounds[sound - 1]->StopPlaying();
258 	}
259 
260 	return EALREADY;
261 }
262 
263 
264 bool
265 BGameSoundDevice::IsPlaying(gs_id sound)
266 {
267 	if (sound <= 0)
268 		return false;
269 	return fSounds[sound - 1]->IsPlaying();
270 }
271 
272 
273 status_t
274 BGameSoundDevice::GetAttributes(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]->GetAttributes(attributes, attributeCount);
281 }
282 
283 
284 status_t
285 BGameSoundDevice::SetAttributes(gs_id sound, gs_attribute* attributes,
286 	size_t attributeCount)
287 {
288 	if (!fSounds[sound - 1])
289 		return B_ERROR;
290 
291 	return fSounds[sound - 1]->SetAttributes(attributes, attributeCount);
292 }
293 
294 
295 int32
296 BGameSoundDevice::AllocateSound()
297 {
298 	for (int32 i = 0; i < fSoundCount; i++)
299 		if (!fSounds[i])
300 			return i;
301 
302 	// we need to allocate new space for the sound
303 	GameSoundBuffer ** sounds = new GameSoundBuffer*[fSoundCount + kGrowth];
304 	for (int32 i = 0; i < fSoundCount; i++)
305 		sounds[i] = fSounds[i];
306 
307 	for (int32 i = fSoundCount; i < fSoundCount + kGrowth; i++)
308 		sounds[i] = NULL;
309 
310 	// replace the old list
311 	delete [] fSounds;
312 	fSounds = sounds;
313 	fSoundCount += kGrowth;
314 
315 	return fSoundCount - kGrowth;
316 }
317 
318