Skip to content

Commit 85add52

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 63173cd commit 85add52

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

src/audio/wiiu/SDL_wiiuaudio.c

Lines changed: 47 additions & 17 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 open_device_thread(_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,49 @@ 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 thread_deallocator(OSThread* thread, void* stack) {
245+
free(thread);
246+
free(stack);
247+
}
248+
249+
static void thread_cleanup(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
257+
we simply create a new one which only runs on CPU1 (AX_MAIN_AFFINITY), then join it */
258+
OSThread *thread = (OSThread *)memalign(16, sizeof(OSThread));
259+
uint32_t stackSize = 32 * 1024;
260+
uint8_t *stack = memalign(16, stackSize);
261+
int32_t priority = OSGetThreadPriority(OSGetCurrentThread());
262+
263+
if (!OSCreateThread(thread,
264+
(OSThreadEntryPointFn)open_device_thread,
265+
(int32_t)this,
266+
NULL,
267+
stack + stackSize,
268+
stackSize,
269+
priority,
270+
AX_MAIN_AFFINITY))
271+
{
272+
return SDL_SetError("OSCreateThread() failed");
273+
}
274+
275+
OSSetThreadDeallocator(thread, &thread_deallocator);
276+
OSSetThreadCleanupCallback(thread, &thread_cleanup);
277+
OSResumeThread(thread);
278+
279+
if (!OSJoinThread(thread, &result)) {
280+
return SDL_SetError("OSJoinThread() failed");
281+
}
282+
283+
return result;
254284
}
255285

256286
/* Called every 3ms before a frame of audio is rendered. Keep it fast! */

0 commit comments

Comments
 (0)