dungeon_crawler

view prototype/src/audio/stream.cc @ 54:995191474cc0

writting the stream audio player
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 19 Sep 2012 05:22:43 +0300
parents 1ea56011c1ff
children 4c427e28ca00
line source
1 #include <stdio.h>
2 #include "stream.h"
3 #include "openal.h"
5 AudioStream::AudioStream()
6 {
7 alsrc = 0;
8 poll_interval = 250;
9 done = true;
10 loop = false;
11 }
13 AudioStream::~AudioStream()
14 {
15 stop();
16 }
18 void AudioStream::play(bool loop)
19 {
20 this->loop = loop;
21 done = false;
22 play_thread = std::thread(&AudioStream::poll_loop, this);
23 }
25 void AudioStream::stop()
26 {
27 if(alsrc) {
28 done = true;
29 alSourceStop(alsrc);
30 play_thread.join();
31 }
32 }
34 static ALenum alformat(AudioStreamBuffer *buf)
35 {
36 return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
37 }
39 // thread function
40 void AudioStream::poll_loop()
41 {
42 static const int num_buffers = 3;
43 AudioStreamBuffer buf;
44 unsigned int albuf[num_buffers];
46 alGenSources(1, &alsrc);
47 alGenBuffers(num_buffers, albuf);
49 for(int i=0; i<num_buffers; i++) {
50 if(more_samples(&buf)) {
51 alSourceQueueBuffers(alsrc, 1, albuf + i);
52 } else {
53 break;
54 }
55 }
57 while(!done) {
58 /* find out how many (if any) of the queued buffers are
59 * done, and free to be reused.
60 */
61 int num_buf_done;
62 alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done);
63 for(int i=0; i<num_buf_done; i++) {
64 // unqueue a buffer...
65 unsigned int buf_id;
66 alSourceUnqueueBuffers(alsrc, 1, &buf_id);
68 // if there are more data, fill it up and requeue it
69 if(more_samples(&buf)) {
70 int bufsz = buf.num_samples * buf.channels * 2; // 2 is for 16bit samples
71 alBufferData(buf_id, alformat(&buf), buf.samples, bufsz, buf.sample_rate);
72 if(alGetError()) {
73 fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
74 }
75 } else {
76 // no more data...
77 if(loop) {
78 rewind();
79 } else {
80 done = true;
81 }
82 }
83 }
85 if(num_buf_done) {
86 // make sure playback didn't stop
87 int state;
88 alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
89 if(state != AL_PLAYING) {
90 alSourcePlay(alsrc);
91 }
92 }
94 std::chrono::milliseconds dur{poll_interval};
95 std::this_thread::sleep_for(dur);
96 }
98 // done with the data, wait for the source to stop playing before cleanup
99 int state;
100 while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
101 std::this_thread::yield();
102 }
104 alDeleteBuffers(num_buffers, albuf);
105 alDeleteSources(1, &alsrc);
106 alsrc = 0;
107 }