dungeon_crawler

annotate 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
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@54 18 void AudioStream::play(bool loop)
nuclear@53 19 {
nuclear@54 20 this->loop = 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@54 27 if(alsrc) {
nuclear@54 28 done = true;
nuclear@54 29 alSourceStop(alsrc);
nuclear@54 30 play_thread.join();
nuclear@54 31 }
nuclear@53 32 }
nuclear@54 33
nuclear@54 34 static ALenum alformat(AudioStreamBuffer *buf)
nuclear@54 35 {
nuclear@54 36 return buf->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
nuclear@54 37 }
nuclear@54 38
nuclear@54 39 // thread function
nuclear@54 40 void AudioStream::poll_loop()
nuclear@54 41 {
nuclear@54 42 static const int num_buffers = 3;
nuclear@54 43 AudioStreamBuffer buf;
nuclear@54 44 unsigned int albuf[num_buffers];
nuclear@54 45
nuclear@54 46 alGenSources(1, &alsrc);
nuclear@54 47 alGenBuffers(num_buffers, albuf);
nuclear@54 48
nuclear@54 49 for(int i=0; i<num_buffers; i++) {
nuclear@54 50 if(more_samples(&buf)) {
nuclear@54 51 alSourceQueueBuffers(alsrc, 1, albuf + i);
nuclear@54 52 } else {
nuclear@54 53 break;
nuclear@54 54 }
nuclear@54 55 }
nuclear@54 56
nuclear@54 57 while(!done) {
nuclear@54 58 /* find out how many (if any) of the queued buffers are
nuclear@54 59 * done, and free to be reused.
nuclear@54 60 */
nuclear@54 61 int num_buf_done;
nuclear@54 62 alGetSourcei(alsrc, AL_BUFFERS_PROCESSED, &num_buf_done);
nuclear@54 63 for(int i=0; i<num_buf_done; i++) {
nuclear@54 64 // unqueue a buffer...
nuclear@54 65 unsigned int buf_id;
nuclear@54 66 alSourceUnqueueBuffers(alsrc, 1, &buf_id);
nuclear@54 67
nuclear@54 68 // if there are more data, fill it up and requeue it
nuclear@54 69 if(more_samples(&buf)) {
nuclear@54 70 int bufsz = buf.num_samples * buf.channels * 2; // 2 is for 16bit samples
nuclear@54 71 alBufferData(buf_id, alformat(&buf), buf.samples, bufsz, buf.sample_rate);
nuclear@54 72 if(alGetError()) {
nuclear@54 73 fprintf(stderr, "failed to load sample data into OpenAL buffer\n");
nuclear@54 74 }
nuclear@54 75 } else {
nuclear@54 76 // no more data...
nuclear@54 77 if(loop) {
nuclear@54 78 rewind();
nuclear@54 79 } else {
nuclear@54 80 done = true;
nuclear@54 81 }
nuclear@54 82 }
nuclear@54 83 }
nuclear@54 84
nuclear@54 85 if(num_buf_done) {
nuclear@54 86 // make sure playback didn't stop
nuclear@54 87 int state;
nuclear@54 88 alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
nuclear@54 89 if(state != AL_PLAYING) {
nuclear@54 90 alSourcePlay(alsrc);
nuclear@54 91 }
nuclear@54 92 }
nuclear@54 93
nuclear@54 94 std::chrono::milliseconds dur{poll_interval};
nuclear@54 95 std::this_thread::sleep_for(dur);
nuclear@54 96 }
nuclear@54 97
nuclear@54 98 // done with the data, wait for the source to stop playing before cleanup
nuclear@54 99 int state;
nuclear@54 100 while(alGetSourcei(alsrc, AL_SOURCE_STATE, &state), state == AL_PLAYING) {
nuclear@54 101 std::this_thread::yield();
nuclear@54 102 }
nuclear@54 103
nuclear@54 104 alDeleteBuffers(num_buffers, albuf);
nuclear@54 105 alDeleteSources(1, &alsrc);
nuclear@54 106 alsrc = 0;
nuclear@54 107 }