Some documentation cleanups
[alure.git] / src / stream.cpp
blob2663858f4444e9838e72b3ab35cec12f1c4721d8
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (C) 2009 by Chris Robinson.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 /* Title: Streaming */
23 #include "config.h"
25 #include "main.h"
27 #include <string.h>
29 #include <memory>
31 static alureStream *InitStream(alureStream *instream, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
33 std::auto_ptr<alureStream> stream(instream);
34 ALenum format;
35 ALuint freq, blockAlign;
37 if(!stream->GetFormat(&format, &freq, &blockAlign))
39 SetError("Could not get stream format");
40 return NULL;
43 if(format == AL_NONE)
45 SetError("No valid format");
46 return NULL;
48 if(blockAlign == 0)
50 SetError("Invalid block size");
51 return NULL;
53 if(freq == 0)
55 SetError("Invalid sample rate");
56 return NULL;
59 chunkLength -= chunkLength%blockAlign;
60 if(chunkLength <= 0)
62 SetError("Chunk length too small");
63 return NULL;
66 stream->chunkLen = chunkLength;
67 stream->dataChunk = new ALubyte[stream->chunkLen];
69 alGenBuffers(numBufs, bufs);
70 if(alGetError() != AL_NO_ERROR)
72 SetError("Buffer creation failed");
73 return NULL;
76 ALsizei filled = alureBufferDataFromStream(stream.get(), numBufs, bufs);
77 if(filled < 0)
79 alDeleteBuffers(numBufs, bufs);
80 alGetError();
82 SetError("Buffering error");
83 return NULL;
86 while(filled < numBufs)
88 alBufferData(bufs[filled], format, stream->dataChunk, 0, freq);
89 if(alGetError() != AL_NO_ERROR)
91 SetError("Buffer load failed");
92 return NULL;
94 filled++;
97 return stream.release();
101 extern "C" {
103 /* Function: alureCreateStreamFromFile
105 * Opens a file and sets it up for streaming. The given chunkLength is the
106 * number of bytes each buffer will fill with. ALURE will optionally generate
107 * the specified number of buffer objects, fill them with the beginning of the
108 * data, then place the new IDs into the provided storage, before returning.
109 * Requires an active context.
111 * Returns:
112 * An opaque handle used to control the opened stream, or NULL on error.
114 * See Also:
115 * <alureCreateStreamFromMemory>, <alureCreateStreamFromStaticMemory>,
116 * <alureCreateStreamFromCallback>
118 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromFile(const ALchar *fname, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
120 if(alGetError() != AL_NO_ERROR)
122 SetError("Existing OpenAL error");
123 return NULL;
126 if(chunkLength < 0)
128 SetError("Invalid chunk length");
129 return NULL;
132 if(numBufs < 0)
134 SetError("Invalid buffer count");
135 return NULL;
138 alureStream *stream = create_stream(fname);
139 if(!stream->IsValid())
141 delete stream;
142 return NULL;
145 return InitStream(stream, chunkLength, numBufs, bufs);
148 /* Function: alureCreateStreamFromMemory
150 * Opens a file image from memory and sets it up for streaming, similar to
151 * alureCreateStreamFromFile. The given data buffer can be safely deleted after
152 * calling this function. Requires an active context.
154 * Returns:
155 * An opaque handle used to control the opened stream, or NULL on error.
157 * See Also:
158 * <alureCreateStreamFromFile>, <alureCreateStreamFromStaticMemory>,
159 * <alureCreateStreamFromCallback>
161 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromMemory(const ALubyte *fdata, ALuint length, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
163 if(alGetError() != AL_NO_ERROR)
165 SetError("Existing OpenAL error");
166 return NULL;
169 if(chunkLength < 0)
171 SetError("Invalid chunk length");
172 return NULL;
175 if(numBufs < 0)
177 SetError("Invalid buffer count");
178 return NULL;
181 if(length <= 0)
183 SetError("Invalid data length");
184 return NULL;
187 ALubyte *streamData = new ALubyte[length];
188 memcpy(streamData, fdata, length);
190 MemDataInfo memData;
191 memData.Data = streamData;
192 memData.Length = length;
193 memData.Pos = 0;
195 alureStream *stream = create_stream(memData);
196 stream->data = streamData;
197 if(!stream->IsValid())
199 delete stream;
200 return NULL;
203 return InitStream(stream, chunkLength, numBufs, bufs);
206 /* Function: alureCreateStreamFromStaticMemory
208 * Identical to alureCreateStreamFromMemory, except the given memory is used
209 * directly and not duplicated. As a consequence, the data buffer must remain
210 * valid while the stream is alive. Requires an active context.
212 * Returns:
213 * An opaque handle used to control the opened stream, or NULL on error.
215 * See Also:
216 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
217 * <alureCreateStreamFromCallback>
219 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromStaticMemory(const ALubyte *fdata, ALuint length, ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
221 if(alGetError() != AL_NO_ERROR)
223 SetError("Existing OpenAL error");
224 return NULL;
227 if(chunkLength < 0)
229 SetError("Invalid chunk length");
230 return NULL;
233 if(numBufs < 0)
235 SetError("Invalid buffer count");
236 return NULL;
239 if(length <= 0)
241 SetError("Invalid data length");
242 return NULL;
245 MemDataInfo memData;
246 memData.Data = fdata;
247 memData.Length = length;
248 memData.Pos = 0;
250 alureStream *stream = create_stream(memData);
251 if(!stream->IsValid())
253 delete stream;
254 return NULL;
257 return InitStream(stream, chunkLength, numBufs, bufs);
260 /* Function: alureCreateStreamFromCallback
262 * Creates a stream using the specified callback to retrieve data. Requires an
263 * active context.
265 * Parameters:
266 * callback - This is called when more data is needed from the stream. Up to
267 * the specified number of bytes should be written to the data
268 * pointer, and the number of bytes actually written should be
269 * returned. The number of bytes written must be block aligned for
270 * the format (eg. a multiple of 4 for AL_FORMAT_STEREO16), or an
271 * OpenAL error may occur during buffering.
272 * userdata - A handle passed through to the callback.
273 * format - The format of the data the callback will be giving. The format must
274 * be valid for the context.
275 * samplerate - The sample rate (frequency) of the stream
277 * Returns:
278 * An opaque handle used to control the opened stream, or NULL on error.
280 * See Also:
281 * <alureCreateStreamFromFile>, <alureCreateStreamFromMemory>,
282 * <alureCreateStreamFromStaticMemory>
284 ALURE_API alureStream* ALURE_APIENTRY alureCreateStreamFromCallback(
285 ALuint (*callback)(void *userdata, ALubyte *data, ALuint bytes),
286 void *userdata, ALenum format, ALuint samplerate,
287 ALsizei chunkLength, ALsizei numBufs, ALuint *bufs)
289 if(alGetError() != AL_NO_ERROR)
291 SetError("Existing OpenAL error");
292 return NULL;
295 if(callback == NULL)
297 SetError("Invalid callback");
298 return NULL;
301 if(chunkLength < 0)
303 SetError("Invalid chunk length");
304 return NULL;
307 if(numBufs < 0)
309 SetError("Invalid buffer count");
310 return NULL;
313 UserCallbacks newcb;
314 newcb.open_file = NULL;
315 newcb.open_mem = NULL;
316 newcb.get_fmt = NULL;
317 newcb.decode = callback;
318 newcb.rewind = NULL;
319 newcb.close = NULL;
321 customStream *stream = new customStream(userdata, format, samplerate, newcb);
322 return InitStream(stream, chunkLength, numBufs, bufs);
325 /* Function: alureGetStreamFormat
327 * Retrieves the format, frequency, and block-alignment used for the given
328 * stream. If a parameter is NULL, that value will not be returned.
330 * Returns:
331 * AL_FALSE on error.
333 ALURE_API ALboolean ALURE_APIENTRY alureGetStreamFormat(alureStream *stream,
334 ALenum *format, ALuint *frequency, ALuint *blockAlign)
336 ALenum _fmt;
337 ALuint _rate, _balign;
339 if(!alureStream::Verify(stream))
341 SetError("Invalid stream pointer");
342 return AL_FALSE;
345 if(!format) format = &_fmt;
346 if(!frequency) frequency = &_rate;
347 if(!blockAlign) blockAlign = &_balign;
349 if(!stream->GetFormat(format, frequency, blockAlign))
351 SetError("Could not get stream format");
352 return AL_FALSE;
355 return AL_TRUE;
358 /* Function: alureBufferDataFromStream
360 * Buffers the given buffer objects with the next chunks of data from the
361 * stream. The given buffer objects do not need to be ones given by the
362 * alureCreateStreamFrom* functions. Requires an active context.
364 * Returns:
365 * The number of buffers filled with new data, or -1 on error. If the value
366 * returned is less than the number requested, the end of the stream has been
367 * reached.
369 ALURE_API ALsizei ALURE_APIENTRY alureBufferDataFromStream(alureStream *stream, ALsizei numBufs, ALuint *bufs)
371 if(alGetError() != AL_NO_ERROR)
373 SetError("Existing OpenAL error");
374 return -1;
377 if(!alureStream::Verify(stream))
379 SetError("Invalid stream pointer");
380 return -1;
383 if(numBufs < 0)
385 SetError("Invalid buffer count");
386 return -1;
389 ALenum format;
390 ALuint freq, blockAlign;
392 if(!stream->GetFormat(&format, &freq, &blockAlign))
394 SetError("Could not get stream format");
395 return -1;
398 ALsizei filled;
399 for(filled = 0;filled < numBufs;filled++)
401 ALuint got = stream->GetData(stream->dataChunk, stream->chunkLen);
402 got -= got%blockAlign;
403 if(got == 0) break;
405 alBufferData(bufs[filled], format, stream->dataChunk, got, freq);
406 if(alGetError() != AL_NO_ERROR)
408 SetError("Buffer load failed");
409 return -1;
413 return filled;
416 /* Function: alureRewindStream
418 * Rewinds the stream so that the next alureBufferDataFromStream call will
419 * restart from the beginning of the audio file.
421 * Returns:
422 * AL_FALSE on error.
424 * See Also:
425 * <alureSetStreamOrder>
427 ALURE_API ALboolean ALURE_APIENTRY alureRewindStream(alureStream *stream)
429 if(!alureStream::Verify(stream))
431 SetError("Invalid stream pointer");
432 return AL_FALSE;
435 return stream->Rewind();
438 /* Function: alureSetStreamOrder
440 * Skips the module decoder to the specified order, so following buffering
441 * calls will decode from the specified order. For non-module formats, setting
442 * order 0 is identical to rewinding the stream (other orders will fail).
444 * Returns:
445 * AL_FALSE on error.
447 * See Also:
448 * <alureRewindStream>
450 ALURE_API ALboolean ALURE_APIENTRY alureSetStreamOrder(alureStream *stream, ALuint order)
452 if(!alureStream::Verify(stream))
454 SetError("Invalid stream pointer");
455 return AL_FALSE;
458 return stream->SetOrder(order);
461 /* Function: alureDestroyStream
463 * Closes an opened stream. For convenience, it will also delete the given
464 * buffer objects. The given buffer objects do not need to be ones given by the
465 * alureCreateStreamFrom* functions. Requires an active context.
467 * Returns:
468 * AL_FALSE on error.
470 ALURE_API ALboolean ALURE_APIENTRY alureDestroyStream(alureStream *stream, ALsizei numBufs, ALuint *bufs)
472 if(alGetError() != AL_NO_ERROR)
474 SetError("Existing OpenAL error");
475 return AL_FALSE;
478 if(numBufs < 0)
480 SetError("Invalid buffer count");
481 return AL_FALSE;
484 if(stream && !alureStream::Verify(stream))
486 SetError("Invalid stream pointer");
487 return AL_FALSE;
490 alDeleteBuffers(numBufs, bufs);
491 if(alGetError() != AL_NO_ERROR)
493 SetError("Buffer deletion failed");
494 return AL_FALSE;
497 if(stream)
499 StopStream(stream);
500 std::istream *f = stream->fstream;
501 delete stream; delete f;
503 return AL_TRUE;