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