summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authorTharo <17233964+Thar0@users.noreply.github.com>2023-11-30 21:22:30 +0000
committerGitHub <noreply@github.com>2023-11-30 16:22:30 -0500
commit5ce4670fd19db356a9a31756a57428aab2978e0e (patch)
tree37b132f1e66173430d3cddf54959a63aac5e86ef /src/code
parentf2c06ce441a38a032202b9024fdfa57bb36a67c2 (diff)
Documentation for audio_thread_manager.c (#1562)
* Documentation for audio_thread_manager.c * Fixes * Move AudioTask back to z64audio.h and include in audiomgr.h, adjust bug comment * Adjust AudioMgrDebugLevel enum
Diffstat (limited to 'src/code')
-rw-r--r--src/code/audio_thread_manager.c90
-rw-r--r--src/code/main.c2
2 files changed, 76 insertions, 16 deletions
diff --git a/src/code/audio_thread_manager.c b/src/code/audio_thread_manager.c
index 01bf54397..159341153 100644
--- a/src/code/audio_thread_manager.c
+++ b/src/code/audio_thread_manager.c
@@ -1,82 +1,134 @@
+/**
+ * @file audio_thread_manager.c
+ *
+ * This file implements basic thread features for the audio driver. It manages updating the driver on vertical retrace
+ * and sending the audio rsp tasks generated by the driver to the task scheduler.
+ */
+
#include "global.h"
-void func_800C3C80(AudioMgr* audioMgr) {
+void AudioMgr_NotifyTaskDone(AudioMgr* audioMgr) {
AudioTask* task = audioMgr->rspTask;
+ // If the audio rsp task has a message queue to receive task done notifications, post a message to it.
if (audioMgr->rspTask->msgQueue != NULL) {
osSendMesg(task->msgQueue, NULL, OS_MESG_BLOCK);
}
}
+/**
+ * Handle retrace event.
+ * Update the audio driver and schedule audio rsp tasks.
+ */
void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
AudioTask* rspTask;
- if (SREG(20) > 0) {
+ if (R_AUDIOMGR_DEBUG_LEVEL > AUDIOMGR_DEBUG_LEVEL_NONE) {
+ // Inhibit audio rsp task processing
audioMgr->rspTask = NULL;
}
+
if (audioMgr->rspTask != NULL) {
+ // Got an rsp task to process, build the OSScTask and forward it to the scheduler to run
+
audioMgr->audioTask.next = NULL;
audioMgr->audioTask.flags = OS_SC_NEEDS_RSP;
audioMgr->audioTask.framebuffer = NULL;
audioMgr->audioTask.list = audioMgr->rspTask->task;
- audioMgr->audioTask.msgQueue = &audioMgr->taskQueue;
+ audioMgr->audioTask.msgQueue = &audioMgr->taskDoneQueue;
audioMgr->audioTask.msg = NULL;
osSendMesg(&audioMgr->sched->cmdQueue, (OSMesg)&audioMgr->audioTask, OS_MESG_BLOCK);
Sched_Notify(audioMgr->sched);
}
+ // Update the audio driver
+
gAudioThreadUpdateTimeStart = osGetTime();
- if (SREG(20) >= 2) {
+
+ if (R_AUDIOMGR_DEBUG_LEVEL >= AUDIOMGR_DEBUG_LEVEL_NO_UPDATE) {
+ // Skip update, no rsp task produced
rspTask = NULL;
} else {
rspTask = func_800E4FE0();
}
+
gAudioThreadUpdateTimeAcc += osGetTime() - gAudioThreadUpdateTimeStart;
gAudioThreadUpdateTimeStart = 0;
if (audioMgr->rspTask != NULL) {
- osRecvMesg(&audioMgr->taskQueue, NULL, OS_MESG_BLOCK);
- func_800C3C80(audioMgr);
+ // Wait for the audio rsp task scheduled on the previous retrace to complete. This looks like it should wait
+ // for the task scheduled on the current retrace, earlier in this function, but since the queue is initially
+ // filled in AudioMgr_Init this osRecvMesg call doesn't wait for the task scheduler to post a message for the
+ // most recent task as there is already a message waiting.
+ osRecvMesg(&audioMgr->taskDoneQueue, NULL, OS_MESG_BLOCK);
+ // Report task done
+ //! @bug As the above osRecvMesg is waiting for the previous task to complete rather than the current task,
+ //! the task done notification is sent to the task done queue for the current task as soon as the previous task
+ //! is completed, without waiting for the current task.
+ //! In practice, task done notifications are not used by the audio driver so this is inconsequential.
+ AudioMgr_NotifyTaskDone(audioMgr);
}
+ // Update rsp task to be scheduled on next retrace
audioMgr->rspTask = rspTask;
}
+/**
+ * Handle Pre-NMI event.
+ * Implemented by the audio driver.
+ *
+ * @see Audio_PreNMI
+ */
void AudioMgr_HandlePreNMI(AudioMgr* audioMgr) {
// "Audio manager received OS_SC_PRE_NMI_MSG"
osSyncPrintf("オーディオマネージャが OS_SC_PRE_NMI_MSG を受け取りました\n");
Audio_PreNMI();
}
-void AudioMgr_ThreadEntry(void* arg0) {
- AudioMgr* audioMgr = (AudioMgr*)arg0;
+void AudioMgr_ThreadEntry(void* arg) {
+ AudioMgr* audioMgr = (AudioMgr*)arg;
IrqMgrClient irqClient;
s16* msg = NULL;
- osSyncPrintf("オーディオマネージャスレッド実行開始\n"); // "Start running audio manager thread"
+ // "Start running audio manager thread"
+ osSyncPrintf("オーディオマネージャスレッド実行開始\n");
+
+ // Initialize audio driver
Audio_Init();
AudioLoad_SetDmaHandler(DmaMgr_AudioDmaHandler);
Audio_InitSound();
- osSendMesg(&audioMgr->lockQueue, NULL, OS_MESG_BLOCK);
+
+ // Fill init queue to signal that the audio driver is initialized
+ osSendMesg(&audioMgr->initQueue, NULL, OS_MESG_BLOCK);
+
IrqMgr_AddClient(audioMgr->irqMgr, &irqClient, &audioMgr->interruptQueue);
+ // Spin waiting for events
while (true) {
osRecvMesg(&audioMgr->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
+
switch (*msg) {
case OS_SC_RETRACE_MSG:
AudioMgr_HandleRetrace(audioMgr);
+
+ // Empty the interrupt queue
while (!MQ_IS_EMPTY(&audioMgr->interruptQueue)) {
osRecvMesg(&audioMgr->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
+
switch (*msg) {
case OS_SC_RETRACE_MSG:
+ // Don't process a retrace more than once in quick succession
break;
+
case OS_SC_PRE_NMI_MSG:
+ // Always handle Pre-NMI
AudioMgr_HandlePreNMI(audioMgr);
break;
}
}
break;
+
case OS_SC_PRE_NMI_MSG:
AudioMgr_HandlePreNMI(audioMgr);
break;
@@ -84,8 +136,15 @@ void AudioMgr_ThreadEntry(void* arg0) {
}
}
-void AudioMgr_Unlock(AudioMgr* audioMgr) {
- osRecvMesg(&audioMgr->lockQueue, NULL, OS_MESG_BLOCK);
+/**
+ * Stalls the current thread until the audio thread is sufficiently initialized.
+ *
+ * Note this function only works once. After the first call the message that the audio thread posted to the init queue
+ * will have been removed, subsequent calls to this function will block indefinitely as the audio thread does not refill
+ * the queue.
+ */
+void AudioMgr_WaitForInit(AudioMgr* audioMgr) {
+ osRecvMesg(&audioMgr->initQueue, NULL, OS_MESG_BLOCK);
}
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Scheduler* sched, IrqMgr* irqMgr) {
@@ -95,11 +154,12 @@ void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Schedule
audioMgr->irqMgr = irqMgr;
audioMgr->rspTask = NULL;
- osCreateMesgQueue(&audioMgr->taskQueue, audioMgr->taskMsgBuf, ARRAY_COUNT(audioMgr->taskMsgBuf));
+ osCreateMesgQueue(&audioMgr->taskDoneQueue, &audioMgr->taskDoneMsg, 1);
osCreateMesgQueue(&audioMgr->interruptQueue, audioMgr->interruptMsgBuf, ARRAY_COUNT(audioMgr->interruptMsgBuf));
- osCreateMesgQueue(&audioMgr->lockQueue, audioMgr->lockMsgBuf, ARRAY_COUNT(audioMgr->lockMsgBuf));
+ osCreateMesgQueue(&audioMgr->initQueue, &audioMgr->initMsg, 1);
- osSendMesg(&audioMgr->taskQueue, NULL, OS_MESG_BLOCK);
+ // Send a message to the task done queue so it is initially full
+ osSendMesg(&audioMgr->taskDoneQueue, NULL, OS_MESG_BLOCK);
osCreateThread(&audioMgr->thread, id, AudioMgr_ThreadEntry, audioMgr, stack, pri);
osStartThread(&audioMgr->thread);
diff --git a/src/code/main.c b/src/code/main.c
index a1fe35ef3..4e633fd34 100644
--- a/src/code/main.c
+++ b/src/code/main.c
@@ -90,7 +90,7 @@ void Main(void* arg) {
StackCheck_Init(&sPadMgrStackInfo, sPadMgrStack, STACK_TOP(sPadMgrStack), 0, 0x100, "padmgr");
PadMgr_Init(&gPadMgr, &sSerialEventQueue, &gIrqMgr, THREAD_ID_PADMGR, THREAD_PRI_PADMGR, STACK_TOP(sPadMgrStack));
- AudioMgr_Unlock(&gAudioMgr);
+ AudioMgr_WaitForInit(&gAudioMgr);
StackCheck_Init(&sGraphStackInfo, sGraphStack, STACK_TOP(sGraphStack), 0, 0x100, "graph");
osCreateThread(&sGraphThread, THREAD_ID_GRAPH, Graph_ThreadEntry, arg, STACK_TOP(sGraphStack), THREAD_PRI_GRAPH);