dungeon_crawler

view prototype/src/audio/stream.cc @ 55:4c427e28ca00

music playback bugfixing
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 19 Sep 2012 08:19:10 +0300
parents 995191474cc0
children f9b8bbebc9b3
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(enum PlayMode mode)
19 {
20 loop = (mode == PlayMode::loop);
21 done = false;
22 play_thread = std::thread(&AudioStream::poll_loop, this);
23 }
25 void AudioStream::stop()
26 {
27 std::lock_guard<std::mutex> lock(mutex);
29 if(alsrc) {
30 done = true;
31 alSourceStop(alsrc);
32 play_thread.join();
33 }
34 }
36 static ALenum alformat(AudioStreamBuffer *buf)
37 {
38 return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
39 }
41 // thread function
42 void AudioStream::poll_loop()
43 {
44 static const int num_buffers = 3;
45 unsigned int albuf[num_buffers];
47 mutex.lock();
49 alGenSources(1, &alsrc);
50 alGenBuffers(num_buffers, albuf);
52 AudioStreamBuffer *buf = new AudioStreamBuffer;
54 for(int i=0; i<num_buffers; i++) {
55 if(more_samples(buf)) {
56 int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples
57 printf("buffer data: %d samples, %d rate, %d channels\n", buf->num_samples, buf->sample_rate, buf->channels);
58 alBufferData(albuf[i], alformat(buf), buf->samples, bufsz, buf->sample_rate);
59 if(alGetError()) {
60 fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
61 }
63 alSourceQueueBuffers(alsrc, 1, albuf + i);
64 if(alGetError()) {
65 fprintf(stderr, "failed to start streaming audio buffers\n");
66 }
67 } else {
68 break;
69 }
70 }
71 // start playback
72 alSourcePlay(alsrc);
73 mutex.unlock();
75 while(!done) {
76 mutex.lock();
77 /* find out how many (if any) of the queued buffers are
78 * done, and free to be reused.
79 */
80 int num_buf_done;
81 alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done);
82 for(int i=0; i<num_buf_done; i++) {
83 // unqueue a buffer...
84 unsigned int buf_id;
85 alSourceUnqueueBuffers(alsrc, 1, &buf_id);
87 // if there are more data, fill it up and requeue it
88 if(more_samples(buf)) {
89 int bufsz = buf->num_samples * buf->channels * 2; // 2 is for 16bit samples
90 printf("buffer data: %d samples, %d rate, %d channels\n", buf->num_samples, buf->sample_rate, buf->channels);
91 alBufferData(buf_id, alformat(buf), buf->samples, bufsz, buf->sample_rate);
92 if(alGetError()) {
93 fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
94 }
96 alSourceQueueBuffers(alsrc, 1, albuf + i);
97 if(alGetError()) {
98 fprintf(stderr, "failed to start streaming audio buffers\n");
99 }
100 } else {
101 // no more data...
102 if(loop) {
103 rewind();
104 } else {
105 done = true;
106 }
107 }
108 }
110 if(num_buf_done) {
111 // make sure playback didn't stop
112 int state;
113 alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
114 if(state != AL_PLAYING) {
115 alSourcePlay(alsrc);
116 }
117 }
119 mutex.unlock();
121 std::chrono::milliseconds dur{poll_interval};
122 std::this_thread::sleep_for(dur);
123 }
125 mutex.lock();
127 // done with the data, wait for the source to stop playing before cleanup
128 int state;
129 while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
130 std::this_thread::yield();
131 }
133 alDeleteBuffers(num_buffers, albuf);
134 alDeleteSources(1, &alsrc);
135 alsrc = 0;
137 mutex.unlock();
138 }