xref: /haiku/src/kits/game/GameSoundDevice.cpp (revision 0cc215800b9e7662154b6c4ad281d42f56124281)
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