zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
alstream.c
Go to the documentation of this file.
1 /*
2  * OpenAL Audio Stream Example
3  *
4  * Copyright (c) 2011 by Chris Robinson <chris.kcat@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 /* This file contains a relatively simple streaming audio player. */
26 
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <signal.h>
31 #include <assert.h>
32 
33 #include "AL/al.h"
34 #include "AL/alc.h"
35 #include "AL/alext.h"
36 
37 #include "common/alhelpers.h"
38 #include "common/alffmpeg.h"
39 
40 
43 
44 
45 /* Define the number of buffers and buffer size (in samples) to use. 4 buffers
46  * with 8192 samples each gives a nice per-chunk size, and lets the queue last
47  * for almost 3/4ths of a second for a 44.1khz stream. */
48 #define NUM_BUFFERS 4
49 #define BUFFER_SIZE 8192
50 
51 typedef struct StreamPlayer {
52  /* These are the buffers and source to play out through OpenAL with */
54  ALuint source;
55 
56  /* Handles for the audio stream */
57  FilePtr file;
59 
60  /* A temporary data buffer for readAVAudioData to write to and pass to
61  * OpenAL with */
62  ALbyte *data;
63  ALsizei datasize;
64 
65  /* The format of the output stream */
66  ALenum format;
67  ALenum channels;
68  ALenum type;
69  ALuint rate;
70 } StreamPlayer;
71 
72 static StreamPlayer *NewPlayer(void);
73 static void DeletePlayer(StreamPlayer *player);
74 static int OpenPlayerFile(StreamPlayer *player, const char *filename);
75 static void ClosePlayerFile(StreamPlayer *player);
76 static int StartPlayer(StreamPlayer *player);
77 static int UpdatePlayer(StreamPlayer *player);
78 
79 /* Creates a new player object, and allocates the needed OpenAL source and
80  * buffer objects. Error checking is simplified for the purposes of this
81  * example, and will cause an abort if needed. */
82 static StreamPlayer *NewPlayer(void)
83 {
84  StreamPlayer *player;
85 
86  player = malloc(sizeof(*player));
87  assert(player != NULL);
88 
89  memset(player, 0, sizeof(*player));
90 
91  /* Generate the buffers and source */
92  alGenBuffers(NUM_BUFFERS, player->buffers);
93  assert(alGetError() == AL_NO_ERROR && "Could not create buffers");
94 
95  alGenSources(1, &player->source);
96  assert(alGetError() == AL_NO_ERROR && "Could not create source");
97 
98  /* Set parameters so mono sources play out the front-center speaker and
99  * won't distance attenuate. */
100  alSource3i(player->source, AL_POSITION, 0, 0, -1);
101  alSourcei(player->source, AL_SOURCE_RELATIVE, AL_TRUE);
102  alSourcei(player->source, AL_ROLLOFF_FACTOR, 0);
103  assert(alGetError() == AL_NO_ERROR && "Could not set source parameters");
104 
105  return player;
106 }
107 
108 /* Destroys a player object, deleting the source and buffers. No error handling
109  * since these calls shouldn't fail with a properly-made player object. */
110 static void DeletePlayer(StreamPlayer *player)
111 {
112  ClosePlayerFile(player);
113 
114  alDeleteSources(1, &player->source);
115  alDeleteBuffers(NUM_BUFFERS, player->buffers);
116  if(alGetError() != AL_NO_ERROR)
117  fprintf(stderr, "Failed to delete object IDs\n");
118 
119  memset(player, 0, sizeof(*player));
120  free(player);
121 }
122 
123 
124 /* Opens the first audio stream of the named file. If a file is already open,
125  * it will be closed first. */
126 static int OpenPlayerFile(StreamPlayer *player, const char *filename)
127 {
128  ClosePlayerFile(player);
129 
130  /* Open the file and get the first stream from it */
131  player->file = openAVFile(filename);
132  player->stream = getAVAudioStream(player->file, 0);
133  if(!player->stream)
134  {
135  fprintf(stderr, "Could not open audio in %s\n", filename);
136  goto error;
137  }
138 
139  /* Get the stream format, and figure out the OpenAL format */
140  if(getAVAudioInfo(player->stream, &player->rate, &player->channels,
141  &player->type) != 0)
142  {
143  fprintf(stderr, "Error getting audio info for %s\n", filename);
144  goto error;
145  }
146 
147  player->format = GetFormat(player->channels, player->type, alIsBufferFormatSupportedSOFT);
148  if(player->format == 0)
149  {
150  fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
151  ChannelsName(player->channels), TypeName(player->type),
152  filename);
153  goto error;
154  }
155 
156  /* Allocate enough space for the temp buffer, given the format */
157  player->datasize = FramesToBytes(BUFFER_SIZE, player->channels,
158  player->type);
159  player->data = malloc(player->datasize);
160  if(player->data == NULL)
161  {
162  fprintf(stderr, "Error allocating %d bytes\n", player->datasize);
163  goto error;
164  }
165 
166  return 1;
167 
168 error:
169  closeAVFile(player->file);
170  player->file = NULL;
171  player->stream = NULL;
172  player->datasize = 0;
173 
174  return 0;
175 }
176 
177 /* Closes the audio file stream */
178 static void ClosePlayerFile(StreamPlayer *player)
179 {
180  closeAVFile(player->file);
181  player->file = NULL;
182  player->stream = NULL;
183 
184  free(player->data);
185  player->data = NULL;
186  player->datasize = 0;
187 }
188 
189 
190 /* Prebuffers some audio from the file, and starts playing the source */
191 static int StartPlayer(StreamPlayer *player)
192 {
193  size_t i, got;
194 
195  /* Rewind the source position and clear the buffer queue */
196  alSourceRewind(player->source);
197  alSourcei(player->source, AL_BUFFER, 0);
198 
199  /* Fill the buffer queue */
200  for(i = 0;i < NUM_BUFFERS;i++)
201  {
202  /* Get some data to give it to the buffer */
203  got = readAVAudioData(player->stream, player->data, player->datasize);
204  if(got == 0) break;
205 
206  alBufferSamplesSOFT(player->buffers[i], player->rate, player->format,
207  BytesToFrames(got, player->channels, player->type),
208  player->channels, player->type, player->data);
209  }
210  if(alGetError() != AL_NO_ERROR)
211  {
212  fprintf(stderr, "Error buffering for playback\n");
213  return 0;
214  }
215 
216  /* Now queue and start playback! */
217  alSourceQueueBuffers(player->source, i, player->buffers);
218  alSourcePlay(player->source);
219  if(alGetError() != AL_NO_ERROR)
220  {
221  fprintf(stderr, "Error starting playback\n");
222  return 0;
223  }
224 
225  return 1;
226 }
227 
228 static int UpdatePlayer(StreamPlayer *player)
229 {
230  ALint processed, state;
231 
232  /* Get relevant source info */
233  alGetSourcei(player->source, AL_SOURCE_STATE, &state);
234  alGetSourcei(player->source, AL_BUFFERS_PROCESSED, &processed);
235  if(alGetError() != AL_NO_ERROR)
236  {
237  fprintf(stderr, "Error checking source state\n");
238  return 0;
239  }
240 
241  /* Unqueue and handle each processed buffer */
242  while(processed > 0)
243  {
244  ALuint bufid;
245  size_t got;
246 
247  alSourceUnqueueBuffers(player->source, 1, &bufid);
248  processed--;
249 
250  /* Read the next chunk of data, refill the buffer, and queue it
251  * back on the source */
252  got = readAVAudioData(player->stream, player->data, player->datasize);
253  if(got > 0)
254  {
255  alBufferSamplesSOFT(bufid, player->rate, player->format,
256  BytesToFrames(got, player->channels, player->type),
257  player->channels, player->type, player->data);
258  alSourceQueueBuffers(player->source, 1, &bufid);
259  }
260  if(alGetError() != AL_NO_ERROR)
261  {
262  fprintf(stderr, "Error buffering data\n");
263  return 0;
264  }
265  }
266 
267  /* Make sure the source hasn't underrun */
268  if(state != AL_PLAYING && state != AL_PAUSED)
269  {
270  ALint queued;
271 
272  /* If no buffers are queued, playback is finished */
273  alGetSourcei(player->source, AL_BUFFERS_QUEUED, &queued);
274  if(queued == 0)
275  return 0;
276 
277  alSourcePlay(player->source);
278  if(alGetError() != AL_NO_ERROR)
279  {
280  fprintf(stderr, "Error restarting playback\n");
281  return 0;
282  }
283  }
284 
285  return 1;
286 }
287 
288 
289 int main(int argc, char **argv)
290 {
291  StreamPlayer *player;
292  int i;
293 
294  /* Print out usage if no file was specified */
295  if(argc < 2)
296  {
297  fprintf(stderr, "Usage: %s <filenames...>\n", argv[0]);
298  return 1;
299  }
300 
301  if(InitAL() != 0)
302  return 1;
303 
304  if(alIsExtensionPresent("AL_SOFT_buffer_samples"))
305  {
306  printf("AL_SOFT_buffer_samples supported!\n");
307  alBufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
308  alIsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
309  }
310  else
311  printf("AL_SOFT_buffer_samples not supported\n");
312 
313  player = NewPlayer();
314 
315  /* Play each file listed on the command line */
316  for(i = 1;i < argc;i++)
317  {
318  if(!OpenPlayerFile(player, argv[i]))
319  continue;
320 
321  printf("Playing %s (%s, %s, %dhz)\n", argv[i],
322  TypeName(player->type), ChannelsName(player->channels),
323  player->rate);
324  fflush(stdout);
325 
326  if(!StartPlayer(player))
327  {
328  ClosePlayerFile(player);
329  continue;
330  }
331 
332  while(UpdatePlayer(player))
333  Sleep(10);
334 
335  /* All done with this file. Close it and go to the next */
336  ClosePlayerFile(player);
337  }
338  printf("Done.\n");
339 
340  /* All files done. Delete the player, and close OpenAL */
341  DeletePlayer(player);
342  player = NULL;
343 
344  CloseAL();
345 
346  return 0;
347 }
AL_API void AL_APIENTRY alSourcePlay(ALuint source)
Definition: alSource.c:1894
AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3)
Definition: alSource.c:1499
LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT
Definition: allatency.c:45
struct MyFile * FilePtr
Definition: alffmpeg.h:13
AL_API void *AL_APIENTRY alGetProcAddress(const ALchar *fname)
Definition: alExtension.c:88
#define NUM_BUFFERS
Definition: alstream.c:48
static int StartPlayer(StreamPlayer *player)
Definition: alstream.c:191
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
int main(int argc, char **argv)
Definition: bootstrap.cpp:102
FilePtr openAVFile(const char *fname)
Definition: alffmpeg.c:161
#define AL_TRUE
Definition: al.h:86
#define NULL
Definition: ftobjs.h:61
void CloseAL(void)
Definition: alhelpers.c:71
GLuint GLuint stream
Definition: glew.h:6573
static StreamPlayer * NewPlayer(void)
Definition: alstream.c:82
AL_API ALenum AL_APIENTRY alGetError(void)
Definition: alError.c:46
int ALsizei
Definition: al.h:62
SDL_EventEntry * free
Definition: SDL_events.c:80
AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value)
Definition: alSource.c:1754
int ALint
Definition: al.h:56
#define memset
Definition: SDL_malloc.c:633
FILE * file
Definition: visualinfo.c:88
static void ClosePlayerFile(StreamPlayer *player)
Definition: alstream.c:178
#define AL_SOURCE_STATE
Definition: al.h:235
struct StreamPlayer StreamPlayer
void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data)
Definition: alhelpers.c:253
#define BUFFER_SIZE
Definition: alstream.c:49
#define assert(x)
Definition: SDL_malloc.c:1234
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type)
Definition: alhelpers.c:296
#define AL_PAUSED
Definition: al.h:240
AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources)
Definition: alSource.c:1216
signed char ALbyte
Definition: al.h:44
size_t readAVAudioData(StreamPtr stream, void *data, size_t length)
Definition: alffmpeg.c:567
#define AL_POSITION
Definition: al.h:144
StreamPtr getAVAudioStream(FilePtr file, int streamnum)
Definition: alffmpeg.c:318
#define Sleep(x)
Definition: allatency.c:34
ALboolean(AL_APIENTRY * LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum)
Definition: alext.h:261
const GLuint * buffers
Definition: glew.h:1669
const char * TypeName(ALenum type)
Definition: alhelpers.c:279
void(AL_APIENTRY * LPALBUFFERSAMPLESSOFT)(ALuint, ALuint, ALenum, ALsizei, ALenum, ALenum, const ALvoid *)
Definition: alext.h:258
#define AL_PLAYING
Definition: al.h:239
#define AL_ROLLOFF_FACTOR
Definition: al.h:286
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
FT_Error error
Definition: cffdrivr.c:407
AL_API void AL_APIENTRY alSourceRewind(ALuint source)
Definition: alSource.c:2021
struct MyStream * StreamPtr
Definition: alffmpeg.h:14
static void DeletePlayer(StreamPlayer *player)
Definition: alstream.c:110
int ALenum
Definition: al.h:65
#define AL_BUFFERS_PROCESSED
Definition: al.h:262
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl2ext.h:845
unsigned int ALuint
Definition: al.h:59
AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
Definition: alBuffer.c:183
#define AL_BUFFER
Definition: al.h:182
ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type)
Definition: alhelpers.c:324
#define AL_SOURCE_RELATIVE
Definition: al.h:97
static int UpdatePlayer(StreamPlayer *player)
Definition: alstream.c:228
ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT)
Definition: alhelpers.c:93
static int OpenPlayerFile(StreamPlayer *player, const char *filename)
Definition: alstream.c:126
#define malloc
Definition: SDL_malloc.c:635
const char * ChannelsName(ALenum chans)
Definition: alhelpers.c:264
AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname)
Definition: alExtension.c:49
AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers)
Definition: alSource.c:2058
int InitAL(void)
Definition: alhelpers.c:42
AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers)
Definition: alSource.c:2194
AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
Definition: alBuffer.c:229
void closeAVFile(FilePtr file)
Definition: alffmpeg.c:271
int i
Definition: pngrutil.c:1377
AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value)
Definition: alSource.c:1481
int getAVAudioInfo(StreamPtr stream, ALuint *rate, ALenum *channels, ALenum *type)
Definition: alffmpeg.c:392
GLsizei GLsizei GLchar * source
Definition: gl2ext.h:994
#define AL_BUFFERS_QUEUED
Definition: al.h:250
#define AL_NO_ERROR
Definition: al.h:364
LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT
Definition: allatency.c:46
AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
Definition: alSource.c:1262