diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 3f1774ebfc..e847f8ff03 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -28,12 +28,15 @@ #include "ChunkFile.h" #include "FixedSizeQueue.h" #include "Common/Thread.h" +#include "Common/Atomics.h" +#include "../../native/base/mutex.h" // Should be used to lock anything related to the outAudioQueue. -recursive_mutex section; +//atomic locks are used on the lock. TODO: make this lock-free +atomic_flag audioQueueLock(NATIVE_ATOMIC_FLAG_INIT); int eventAudioUpdate = -1; -int eventHostAudioUpdate = -1; +int eventHostAudioUpdate = -1; int mixFrequency = 44100; const int hwSampleRate = 44100; @@ -55,6 +58,9 @@ static int chanQueueMinSizeFactor; // is bad mojo. FixedSizeQueue outAudioQueue; +bool __gainAudioQueueLock(); +void __releaseAcquiredLock(); + static inline s16 clamp_s16(int i) { if (i > 32767) return 32767; @@ -108,6 +114,8 @@ void __AudioInit() { mixBuffer = new s32[hwBlockSize * 2]; memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32)); + + } void __AudioDoState(PointerWrap &p) { @@ -122,9 +130,18 @@ void __AudioDoState(PointerWrap &p) { p.Do(mixFrequency); - { - lock_guard guard(section); + { + //block until a lock is achieved. Not a good idea at all, but + //can't think of a better one... + while(!__gainAudioQueueLock()){ + continue; + } + outAudioQueue.DoState(p); + + //release the atomic lock + __releaseAcquiredLock(); + } int chanCount = ARRAY_SIZE(chans); @@ -322,11 +339,18 @@ void __AudioUpdate() { } if (g_Config.bEnableSound) { - lock_guard guard(section); + + //looks like the heavy lifting is done here. + //we have to optimize this some more. + if(!__gainAudioQueueLock()){ + return; + } + if (outAudioQueue.room() >= hwBlockSize * 2) { s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; outAudioQueue.pushPointers(hwBlockSize * 2, &buf1, &sz1, &buf2, &sz2); + for (size_t s = 0; s < sz1; s++) buf1[s] = clamp_s16(mixBuffer[s]); if (buf2) { @@ -337,6 +361,9 @@ void __AudioUpdate() { // This happens quite a lot. There's still something slightly off // about the amount of audio we produce. } + + //release the atomic lock + __releaseAcquiredLock(); } } @@ -352,12 +379,21 @@ int __AudioMix(short *outstereo, int numFrames) const s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; { - lock_guard guard(section); + + if(!__gainAudioQueueLock()){ + return numFrames; + } + + outAudioQueue.popPointers(numFrames * 2, &buf1, &sz1, &buf2, &sz2); + memcpy(outstereo, buf1, sz1 * sizeof(s16)); if (buf2) { memcpy(outstereo + sz1, buf2, sz2 * sizeof(s16)); } + + //release the atomic lock + __releaseAcquiredLock(); } int remains = (int)(numFrames * 2 - sz1 - sz2); @@ -370,3 +406,21 @@ int __AudioMix(short *outstereo, int numFrames) } return underrun >= 0 ? underrun : numFrames; } + + +/*returns whether the lock was successfully gained or not. +i.e - whether the lock belongs to you +*/ +inline bool __gainAudioQueueLock(){ + /*if the previous state was 0, that means the lock was "unlocked". So, + we return !0, which is true thanks to C's int to bool conversion + + One the other hand, if it was locked, then the lock would return 1. + so, !1 = 0 = false. + */ + return !audioQueueLock.test_and_set(); +}; + +inline void __releaseAcquiredLock(){ + audioQueueLock.clear(); +} diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index 403c2f961f..e338557683 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -16,9 +16,9 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #pragma once - #include "sceAudio.h" + // Easy interface for sceAudio to write to, to keep the complexity in check. void __AudioInit();