Skip to content

Commit 8810c2f

Browse files
wiiu/audio: Open device in new thread
AX initialization needs to be done on CPU1, otherwise interrupts won't be handled properly. Previously this was attmpted to be done using `OSSetThreadAffinity` to change the affinity of the current thread. Unfortunately `OSSetThreadAffinity` does not work when called for the currently running thread. This caused issues when an SDL audio device was opened from a thread not running on CPU1. This commit now creates a new thread running on CPU1 for AX initialization, and joins it before moving on.
1 parent 01e8cee commit 8810c2f

File tree

1 file changed

+63
-18
lines changed

1 file changed

+63
-18
lines changed

src/audio/wiiu/SDL_wiiuaudio.c

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@ static SDL_AudioDevice* cb_this;
6161
/* +1, but never goes above NUM_BUFFERS */
6262
#define next_id(id) (id + 1) % NUM_BUFFERS
6363

64-
static int WIIUAUDIO_OpenDevice(_THIS, const char* devname) {
65-
int ret = 0;
64+
static int _WIIUAUDIO_OpenDeviceFunction(_THIS) {
6665
AXVoiceOffsets offs;
6766
AXVoiceVeData vol = {
6867
.volume = 0x8000,
6968
};
70-
uint32_t old_affinity;
7169
float srcratio;
7270
Uint8* mixbuf = NULL;
7371
uint32_t mixbuf_allocation_count = 0;
@@ -80,10 +78,6 @@ static int WIIUAUDIO_OpenDevice(_THIS, const char* devname) {
8078

8179
SDL_zerop(this->hidden);
8280

83-
/* We *must not* change cores when setting stuff up */
84-
old_affinity = OSGetThreadAffinity(OSGetCurrentThread());
85-
OSSetThreadAffinity(OSGetCurrentThread(), AX_MAIN_AFFINITY);
86-
8781
/* Take a quick aside to init the wiiu audio */
8882
if (!AXIsInit()) {
8983
/* Init the AX audio engine */
@@ -147,8 +141,7 @@ static int WIIUAUDIO_OpenDevice(_THIS, const char* devname) {
147141

148142
if (!mixbuf) {
149143
printf("Couldn't allocate mix buffer\n");
150-
ret = SDL_OutOfMemory();
151-
goto end;
144+
return SDL_OutOfMemory();
152145
}
153146

154147
memset(mixbuf, 0, this->spec.size * NUM_BUFFERS);
@@ -163,8 +156,7 @@ static int WIIUAUDIO_OpenDevice(_THIS, const char* devname) {
163156
if (this->hidden->deintvbuf == NULL) {
164157
AXQuit();
165158
printf("DEBUG: Couldn't allocate deinterleave buffer");
166-
ret = SDL_SetError("Couldn't allocate deinterleave buffer");
167-
goto end;
159+
return SDL_SetError("Couldn't allocate deinterleave buffer");
168160
}
169161

170162

@@ -174,8 +166,7 @@ static int WIIUAUDIO_OpenDevice(_THIS, const char* devname) {
174166
if (!this->hidden->voice[i]) {
175167
AXQuit();
176168
printf("DEBUG: couldn't get voice\n");
177-
ret = SDL_OutOfMemory();
178-
goto end;
169+
return SDL_OutOfMemory();
179170
}
180171

181172
/* Start messing with it */
@@ -247,10 +238,64 @@ static int WIIUAUDIO_OpenDevice(_THIS, const char* devname) {
247238
cb_this = this; //wish there was a better way
248239
AXRegisterAppFrameCallback(_WIIUAUDIO_framecallback);
249240

250-
end: ;
251-
/* Put the thread affinity back to normal - we won't call any more AX funcs */
252-
OSSetThreadAffinity(OSGetCurrentThread(), old_affinity);
253-
return ret;
241+
return 0;
242+
}
243+
244+
static void _WIIUAUDIO_ThreadDeallocator(OSThread *thread, void *stack) {
245+
free(thread);
246+
free(stack);
247+
}
248+
249+
static void _WIIUAUDIO_ThreadCleanup(OSThread *thread, void *stack) {
250+
}
251+
252+
static int WIIUAUDIO_OpenDevice(_THIS, const char *devname) {
253+
int result;
254+
255+
/* AX functions need to run from the same core.
256+
Since we cannot easily change the affinity of the currently running thread, we create a new one if necessary.
257+
This thread only runs on CPU1 (AX_MAIN_AFFINITY) and will be joined after initialization is done. */
258+
if (OSGetThreadAffinity(OSGetCurrentThread()) != AX_MAIN_AFFINITY) {
259+
OSThread *thread;
260+
uint32_t stackSize = 32 * 1024;
261+
uint8_t *stack;
262+
int32_t priority = OSGetThreadPriority(OSGetCurrentThread());
263+
264+
thread = (OSThread *)memalign(16, sizeof(OSThread));
265+
if (!thread) {
266+
return SDL_OutOfMemory();
267+
}
268+
269+
stack = memalign(16, stackSize);
270+
if (!stack) {
271+
free(thread);
272+
return SDL_OutOfMemory();
273+
}
274+
275+
if (!OSCreateThread(thread,
276+
(OSThreadEntryPointFn)_WIIUAUDIO_OpenDeviceFunction,
277+
(int32_t)this,
278+
NULL,
279+
stack + stackSize,
280+
stackSize,
281+
priority,
282+
AX_MAIN_AFFINITY))
283+
{
284+
return SDL_SetError("OSCreateThread() failed");
285+
}
286+
287+
OSSetThreadDeallocator(thread, &_WIIUAUDIO_ThreadDeallocator);
288+
OSSetThreadCleanupCallback(thread, &_WIIUAUDIO_ThreadCleanup);
289+
OSResumeThread(thread);
290+
291+
if (!OSJoinThread(thread, &result)) {
292+
return SDL_SetError("OSJoinThread() failed");
293+
}
294+
} else {
295+
result = _WIIUAUDIO_OpenDeviceFunction(this);
296+
}
297+
298+
return result;
254299
}
255300

256301
/* Called every 3ms before a frame of audio is rendered. Keep it fast! */
@@ -405,7 +450,7 @@ static void WIIUAUDIO_ThreadInit(_THIS) {
405450
OSSetThreadPriority(currentThread, priority);
406451
}
407452

408-
static SDL_bool WIIUAUDIO_Init(SDL_AudioDriverImpl* impl) {
453+
static SDL_bool WIIUAUDIO_Init(SDL_AudioDriverImpl *impl) {
409454
impl->OpenDevice = WIIUAUDIO_OpenDevice;
410455
impl->PlayDevice = WIIUAUDIO_PlayDevice;
411456
impl->WaitDevice = WIIUAUDIO_WaitDevice;

0 commit comments

Comments
 (0)