1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #if defined(MACOSX) || defined(GP2X) || defined(CAANOO) || defined(GP2XWIZ)
24 
25 #include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
26 
DoubleBufferSDLMixerManager()27 DoubleBufferSDLMixerManager::DoubleBufferSDLMixerManager()
28 	:
29 	_soundMutex(0), _soundCond(0), _soundThread(0),
30 	_soundThreadIsRunning(false), _soundThreadShouldQuit(false) {
31 
32 }
33 
~DoubleBufferSDLMixerManager()34 DoubleBufferSDLMixerManager::~DoubleBufferSDLMixerManager() {
35 	deinitThreadedMixer();
36 }
37 
startAudio()38 void DoubleBufferSDLMixerManager::startAudio() {
39 	_soundThreadIsRunning = false;
40 	_soundThreadShouldQuit = false;
41 
42 	// Create mutex and condition variable
43 	_soundMutex = SDL_CreateMutex();
44 	_soundCond = SDL_CreateCond();
45 
46 	// Create two sound buffers
47 	_activeSoundBuf = 0;
48 	uint bufSize = _obtained.samples * 4;
49 	_soundBufSize = bufSize;
50 	_soundBuffers[0] = (byte *)calloc(1, bufSize);
51 	_soundBuffers[1] = (byte *)calloc(1, bufSize);
52 
53 	_soundThreadIsRunning = true;
54 
55 	// Finally start the thread
56 #if SDL_VERSION_ATLEAST(2, 0, 0)
57 	_soundThread = SDL_CreateThread(mixerProducerThreadEntry, "ResidualVM Double Buffer Mixer", this);
58 #else
59 	_soundThread = SDL_CreateThread(mixerProducerThreadEntry, this);
60 #endif
61 
62 	SdlMixerManager::startAudio();
63 }
64 
mixerProducerThread()65 void DoubleBufferSDLMixerManager::mixerProducerThread() {
66 	byte nextSoundBuffer;
67 
68 	SDL_LockMutex(_soundMutex);
69 	while (true) {
70 		// Wait till we are allowed to produce data
71 		SDL_CondWait(_soundCond, _soundMutex);
72 
73 		if (_soundThreadShouldQuit)
74 			break;
75 
76 		// Generate samples and put them into the next buffer
77 		nextSoundBuffer = _activeSoundBuf ^ 1;
78 		_mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize);
79 
80 		// Swap buffers
81 		_activeSoundBuf = nextSoundBuffer;
82 	}
83 	SDL_UnlockMutex(_soundMutex);
84 }
85 
mixerProducerThreadEntry(void * arg)86 int SDLCALL DoubleBufferSDLMixerManager::mixerProducerThreadEntry(void *arg) {
87 	DoubleBufferSDLMixerManager *mixer = (DoubleBufferSDLMixerManager *)arg;
88 	assert(mixer);
89 	mixer->mixerProducerThread();
90 	return 0;
91 }
92 
deinitThreadedMixer()93 void DoubleBufferSDLMixerManager::deinitThreadedMixer() {
94 	// Kill thread?? _soundThread
95 
96 	if (_soundThreadIsRunning) {
97 		// Signal the producer thread to end, and wait for it to actually finish.
98 		_soundThreadShouldQuit = true;
99 		SDL_CondBroadcast(_soundCond);
100 		SDL_WaitThread(_soundThread, NULL);
101 
102 		// Kill the mutex & cond variables.
103 		// Attention: AT this point, the mixer callback must not be running
104 		// anymore, else we will crash!
105 		SDL_DestroyMutex(_soundMutex);
106 		SDL_DestroyCond(_soundCond);
107 
108 		_soundThreadIsRunning = false;
109 
110 		free(_soundBuffers[0]);
111 		free(_soundBuffers[1]);
112 	}
113 }
114 
callbackHandler(byte * samples,int len)115 void DoubleBufferSDLMixerManager::callbackHandler(byte *samples, int len) {
116 	assert(_mixer);
117 	assert((int)_soundBufSize == len);
118 
119 	// Lock mutex, to ensure our data is not overwritten by the producer thread
120 	SDL_LockMutex(_soundMutex);
121 
122 	// Copy data from the current sound buffer
123 	memcpy(samples, _soundBuffers[_activeSoundBuf], len);
124 
125 	// Unlock mutex and wake up the produced thread
126 	SDL_UnlockMutex(_soundMutex);
127 	SDL_CondSignal(_soundCond);
128 }
129 
130 #endif
131