static THREAD_ENTRY _audioThread(void* context) { struct mPSP2AudioContext* audio = (struct mPSP2AudioContext*) context; uint32_t zeroBuffer[PSP2_SAMPLES] = {0}; void* buffer = zeroBuffer; int audioPort = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO); while (audio->running) { MutexLock(&audio->mutex); if (buffer != zeroBuffer) { // Can only happen in successive iterations audio->samples -= PSP2_SAMPLES; ConditionWake(&audio->cond); } if (audio->samples >= PSP2_SAMPLES) { buffer = &audio->buffer[audio->readOffset]; audio->readOffset += PSP2_SAMPLES; if (audio->readOffset >= PSP2_AUDIO_BUFFER_SIZE) { audio->readOffset = 0; } // Don't mark samples as read until the next loop iteration to prevent // writing to the buffer while being read (see above) } else { buffer = zeroBuffer; } MutexUnlock(&audio->mutex); sceAudioOutOutput(audioPort, buffer); } sceAudioOutReleasePort(audioPort); return 0; }
void GBASyncConsumeAudio(struct GBASync* sync) { if (!sync) { return; } ConditionWake(&sync->audioRequiredCond); MutexUnlock(&sync->audioBufferMutex); }
bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) { struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; MutexLock(&node->p->mutex); --node->p->loaded; ConditionWake(&node->p->barrier); MutexUnlock(&node->p->mutex); return true; }
static void _changeVideoSync(struct GBASync* sync, bool frameOn) { // Make sure the video thread can process events while the GBA thread is paused MutexLock(&sync->videoFrameMutex); if (frameOn != sync->videoFrameOn) { sync->videoFrameOn = frameOn; ConditionWake(&sync->videoFrameAvailableCond); } MutexUnlock(&sync->videoFrameMutex); }
void GBASyncForceFrame(struct GBASync* sync) { if (!sync) { return; } MutexLock(&sync->videoFrameMutex); ConditionWake(&sync->videoFrameAvailableCond); MutexUnlock(&sync->videoFrameMutex); }
void GBASyncPostFrame(struct GBASync* sync) { if (!sync) { return; } MutexLock(&sync->videoFrameMutex); ++sync->videoFramePending; --sync->videoFrameSkip; if (sync->videoFrameSkip < 0) { do { ConditionWake(&sync->videoFrameAvailableCond); if (sync->videoFrameWait) { ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex); } } while (sync->videoFrameWait && sync->videoFramePending); } MutexUnlock(&sync->videoFrameMutex); }
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) { if (!sync) { return true; } MutexLock(&sync->videoFrameMutex); ConditionWake(&sync->videoFrameRequiredCond); if (!sync->videoFrameOn && !sync->videoFramePending) { return false; } if (sync->videoFrameOn) { if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) { return false; } } sync->videoFramePending = 0; sync->videoFrameSkip = frameskip; return true; }