1 /***************************************************************************
2
3 file : OpenAlMusicPlayer.cpp
4 created : Fri Dec 23 17:35:18 CET 2011
5 copyright : (C) 2011 Bernhard Wymann
6 email : berniw@bluewin.ch
7 version : $Id: OpenALMusicPlayer.cpp,v 1.1.2.3 2014/02/05 09:54:43 berniw Exp $
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20 #include <stdio.h>
21 #include <tgf.h>
22 #include "OpenALMusicPlayer.h"
23
24 const int OpenALMusicPlayer::BUFFERSIZE = 4096*64;
25
OpenALMusicPlayer(SoundStream * soundStream)26 OpenALMusicPlayer::OpenALMusicPlayer(SoundStream* soundStream):
27 device(NULL),
28 context(NULL),
29 source(0),
30 stream(soundStream),
31 ready(false)
32 {
33 buffers[0] = 0;
34 buffers[1] = 0;
35 }
36
37
38
39
~OpenALMusicPlayer()40 OpenALMusicPlayer::~OpenALMusicPlayer()
41 {
42 if (ready) {
43 stop();
44 }
45 }
46
47
48
49
stop()50 void OpenALMusicPlayer::stop()
51 {
52 if (!ready) {
53 return;
54 }
55
56 alSourceStop(source);
57
58 int queued;
59
60 alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
61 while (queued--) {
62 ALuint buffer;
63 alSourceUnqueueBuffers(source, 1, &buffer);
64 check();
65 }
66
67 alDeleteSources(1, &source);
68 check();
69 alDeleteBuffers(2, buffers);
70 check();
71
72 alcMakeContextCurrent(NULL);
73 alcDestroyContext(context);
74 alcCloseDevice(device);
75
76 ready = false;
77 }
78
79
80
81
initContext()82 bool OpenALMusicPlayer::initContext()
83 {
84 device = alcOpenDevice(NULL);
85 if( device == NULL ) {
86 GfError("OpenALMusicPlayer: OpenAL could not open device\n");
87 return false;
88 }
89
90 context = alcCreateContext(device, NULL);
91 if(context == NULL) {
92 alcCloseDevice(device);
93 GfError("OpenALMusicPlayer: OpenAL could not create contect for device\n");
94 return false;
95 }
96
97 alcMakeContextCurrent(context);
98 alcGetError(device);
99
100 return check();
101 }
102
103
104
105
initBuffers()106 bool OpenALMusicPlayer::initBuffers()
107 {
108 alGenBuffers(2, buffers);
109 return check();
110 }
111
112
113
114
initSource()115 bool OpenALMusicPlayer::initSource()
116 {
117 alGenSources(1, &source);
118 if (!check()) {
119 GfError("OpenALMusicPlayer: initSource failed to get sound source.\n");
120 return false;
121 };
122
123 alSource3f(source, AL_POSITION, 0.0, 0.0, 0.0);
124 alSource3f(source, AL_VELOCITY, 0.0, 0.0, 0.0);
125 alSource3f(source, AL_DIRECTION, 0.0, 0.0, 0.0);
126 alSourcef (source, AL_ROLLOFF_FACTOR, 0.0 );
127 alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE );
128
129 return true;
130 }
131
132
133
134
check()135 bool OpenALMusicPlayer::check()
136 {
137 int error = alGetError();
138
139 if(error != AL_NO_ERROR) {
140 GfError("OpenALMusicPlayer: OpenAL error was raised: %d\n", error);
141 return false;
142 }
143
144 return true;
145 }
146
147
148
149
isPlaying()150 bool OpenALMusicPlayer::isPlaying()
151 {
152 ALenum state;
153
154 alGetSourcei(source, AL_SOURCE_STATE, &state);
155 return (state == AL_PLAYING);
156 }
157
158
159
streamBuffer(ALuint buffer)160 bool OpenALMusicPlayer::streamBuffer(ALuint buffer)
161 {
162 char pcm[BUFFERSIZE];
163 int size = 0;
164 const char* error = nullptr;
165
166 if (!stream->read(pcm, BUFFERSIZE, &size, &error)) {
167 GfError("OpenALMusicPlayer: Stream read error: %s\n", error);
168 return false;
169 } else {
170 int format;
171 switch (stream->getSoundFormat()) {
172 case SoundStream::FORMAT_MONO16:
173 format = AL_FORMAT_MONO16;
174 break;
175 case SoundStream::FORMAT_STEREO16:
176 format = AL_FORMAT_STEREO16;
177 break;
178 default:
179 GfError("OpenALMusicPlayer: Format error: \n");
180 return false;
181 }
182
183 alBufferData(buffer, format, pcm, size, stream->getRateInHz());
184 return check();
185 }
186 }
187
188
189
190
start()191 void OpenALMusicPlayer::start()
192 {
193 if (!ready) {
194 if (stream->getSoundFormat() == SoundStream::FORMAT_INVALID) {
195 GfError("OpenALMusicPlayer: Sound stream has invalid format\n");
196 return;
197 }
198
199 if (initContext() && initBuffers() && initSource()) {
200 ready = true;
201 startPlayback();
202 }
203
204 return;
205 }
206 }
207
208
209
210
rewind()211 void OpenALMusicPlayer::rewind()
212 {
213 stream->rewind();
214 }
215
216
217
218
playAndManageBuffer()219 bool OpenALMusicPlayer::playAndManageBuffer()
220 {
221 if (!ready) {
222 return false;
223 }
224
225 int processed;
226 bool active = true;
227
228 alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
229
230 while(processed--) {
231 ALuint buffer;
232
233 alSourceUnqueueBuffers(source, 1, &buffer);
234 check();
235 active = streamBuffer(buffer);
236 alSourceQueueBuffers(source, 1, &buffer);
237 check();
238 }
239
240 if (!active && !isPlaying()) {
241 // Try to reanimate playback
242 if(!startPlayback()) {
243 GfError("OpenALMusicPlayer: Cannot play stream.\n");
244 }
245 }
246
247 return true;
248 }
249
250
251
252
startPlayback()253 bool OpenALMusicPlayer::startPlayback()
254 {
255 if(isPlaying()) {
256 return true;
257 }
258
259 if(!streamBuffer(buffers[0])) {
260 return false;
261 }
262
263 if(!streamBuffer(buffers[1])) {
264 return false;
265 }
266
267 alSourceQueueBuffers(source, 2, buffers);
268 alSourcePlay(source);
269
270 return true;
271 }
272