dungeon_crawler

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