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