Switching audio system to platform-agnostic primitives.
This commit is contained in:
@@ -73,19 +73,14 @@ AudioSystem::AudioSystem(Emulator* emulator)
|
||||
}
|
||||
for (size_t i = 0; i < kMaximumClientCount; ++i) {
|
||||
client_semaphores_[i] =
|
||||
CreateSemaphore(NULL, 0, kMaximumQueuedFrames, NULL);
|
||||
wait_handles_[i] = client_semaphores_[i];
|
||||
xe::threading::Semaphore::Create(0, kMaximumQueuedFrames);
|
||||
wait_handles_[i] = client_semaphores_[i].get();
|
||||
}
|
||||
shutdown_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
wait_handles_[kMaximumClientCount] = shutdown_event_;
|
||||
shutdown_event_ = xe::threading::Event::CreateManualResetEvent(false);
|
||||
wait_handles_[kMaximumClientCount] = shutdown_event_.get();
|
||||
}
|
||||
|
||||
AudioSystem::~AudioSystem() {
|
||||
for (size_t i = 0; i < kMaximumClientCount; ++i) {
|
||||
CloseHandle(client_semaphores_[i]);
|
||||
}
|
||||
CloseHandle(shutdown_event_);
|
||||
}
|
||||
AudioSystem::~AudioSystem() = default;
|
||||
|
||||
X_STATUS AudioSystem::Setup() {
|
||||
processor_ = emulator_->processor();
|
||||
@@ -111,18 +106,17 @@ void AudioSystem::WorkerThreadMain() {
|
||||
|
||||
// Main run loop.
|
||||
while (worker_running_) {
|
||||
auto result =
|
||||
WaitForMultipleObjectsEx(DWORD(xe::countof(wait_handles_)),
|
||||
wait_handles_, FALSE, INFINITE, FALSE);
|
||||
if (result == WAIT_FAILED ||
|
||||
result == WAIT_OBJECT_0 + kMaximumClientCount) {
|
||||
auto result = xe::threading::WaitAny(
|
||||
wait_handles_, DWORD(xe::countof(wait_handles_)), true);
|
||||
if (result.first == xe::threading::WaitResult::kFailed ||
|
||||
(result.first == xe::threading::WaitResult::kSuccess &&
|
||||
result.second == kMaximumClientCount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t pumped = 0;
|
||||
if (result >= WAIT_OBJECT_0 &&
|
||||
result <= WAIT_OBJECT_0 + (kMaximumClientCount - 1)) {
|
||||
size_t index = result - WAIT_OBJECT_0;
|
||||
if (result.first == xe::threading::WaitResult::kSuccess) {
|
||||
size_t index = result.second;
|
||||
do {
|
||||
lock_.lock();
|
||||
uint32_t client_callback = clients_[index].callback;
|
||||
@@ -138,8 +132,9 @@ void AudioSystem::WorkerThreadMain() {
|
||||
pumped++;
|
||||
index++;
|
||||
} while (index < kMaximumClientCount &&
|
||||
WaitForSingleObject(client_semaphores_[index], 0) ==
|
||||
WAIT_OBJECT_0);
|
||||
xe::threading::Wait(client_semaphores_[index].get(), false,
|
||||
std::chrono::milliseconds(0)) ==
|
||||
xe::threading::WaitResult::kSuccess);
|
||||
}
|
||||
|
||||
if (!worker_running_) {
|
||||
@@ -160,7 +155,7 @@ void AudioSystem::Initialize() {}
|
||||
|
||||
void AudioSystem::Shutdown() {
|
||||
worker_running_ = false;
|
||||
SetEvent(shutdown_event_);
|
||||
shutdown_event_->Set();
|
||||
worker_thread_->Wait(0, 0, 0, nullptr);
|
||||
worker_thread_.reset();
|
||||
}
|
||||
@@ -172,9 +167,9 @@ X_STATUS AudioSystem::RegisterClient(uint32_t callback, uint32_t callback_arg,
|
||||
|
||||
auto index = unused_clients_.front();
|
||||
|
||||
auto client_semaphore = client_semaphores_[index];
|
||||
BOOL ret = ReleaseSemaphore(client_semaphore, kMaximumQueuedFrames, NULL);
|
||||
assert_true(ret == TRUE);
|
||||
auto client_semaphore = client_semaphores_[index].get();
|
||||
auto ret = client_semaphore->Release(kMaximumQueuedFrames, nullptr);
|
||||
assert_true(ret);
|
||||
|
||||
AudioDriver* driver;
|
||||
auto result = CreateDriver(index, client_semaphore, &driver);
|
||||
@@ -215,13 +210,14 @@ void AudioSystem::UnregisterClient(size_t index) {
|
||||
clients_[index] = {0};
|
||||
unused_clients_.push(index);
|
||||
|
||||
// drain the semaphore of its count
|
||||
auto client_semaphore = client_semaphores_[index];
|
||||
DWORD wait_result;
|
||||
// Drain the semaphore of its count.
|
||||
auto client_semaphore = client_semaphores_[index].get();
|
||||
xe::threading::WaitResult wait_result;
|
||||
do {
|
||||
wait_result = WaitForSingleObject(client_semaphore, 0);
|
||||
} while (wait_result == WAIT_OBJECT_0);
|
||||
assert_true(wait_result == WAIT_TIMEOUT);
|
||||
wait_result = xe::threading::Wait(client_semaphore, false,
|
||||
std::chrono::milliseconds(0));
|
||||
} while (wait_result == xe::threading::WaitResult::kSuccess);
|
||||
assert_true(wait_result == xe::threading::WaitResult::kTimeout);
|
||||
}
|
||||
|
||||
} // namespace apu
|
||||
|
||||
@@ -14,11 +14,10 @@
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
typedef void* HANDLE;
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
class XHostThread;
|
||||
@@ -48,7 +47,15 @@ class AudioSystem {
|
||||
void UnregisterClient(size_t index);
|
||||
void SubmitFrame(size_t index, uint32_t samples_ptr);
|
||||
|
||||
virtual X_STATUS CreateDriver(size_t index, HANDLE semaphore,
|
||||
protected:
|
||||
AudioSystem(Emulator* emulator);
|
||||
|
||||
virtual void Initialize();
|
||||
|
||||
void WorkerThreadMain();
|
||||
|
||||
virtual X_STATUS CreateDriver(size_t index,
|
||||
xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) = 0;
|
||||
virtual void DestroyDriver(AudioDriver* driver) = 0;
|
||||
|
||||
@@ -56,15 +63,6 @@ class AudioSystem {
|
||||
// XAUDIO2_MAX_QUEUED_BUFFERS))
|
||||
static const size_t kMaximumQueuedFrames = 64;
|
||||
|
||||
protected:
|
||||
virtual void Initialize();
|
||||
|
||||
private:
|
||||
void WorkerThreadMain();
|
||||
|
||||
protected:
|
||||
AudioSystem(Emulator* emulator);
|
||||
|
||||
Emulator* emulator_;
|
||||
Memory* memory_;
|
||||
cpu::Processor* processor_;
|
||||
@@ -83,9 +81,11 @@ class AudioSystem {
|
||||
uint32_t wrapped_callback_arg;
|
||||
} clients_[kMaximumClientCount];
|
||||
|
||||
HANDLE client_semaphores_[kMaximumClientCount];
|
||||
HANDLE shutdown_event_; // Event is always there in case we have no clients.
|
||||
HANDLE wait_handles_[kMaximumClientCount + 1];
|
||||
std::unique_ptr<xe::threading::Semaphore>
|
||||
client_semaphores_[kMaximumClientCount];
|
||||
// Event is always there in case we have no clients.
|
||||
std::unique_ptr<xe::threading::Event> shutdown_event_;
|
||||
xe::threading::WaitHandle* wait_handles_[kMaximumClientCount + 1];
|
||||
std::queue<size_t> unused_clients_;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ NopAudioSystem::NopAudioSystem(Emulator* emulator) : AudioSystem(emulator) {}
|
||||
|
||||
NopAudioSystem::~NopAudioSystem() = default;
|
||||
|
||||
X_STATUS NopAudioSystem::CreateDriver(size_t index, HANDLE wait_handle,
|
||||
X_STATUS NopAudioSystem::CreateDriver(size_t index,
|
||||
xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) {
|
||||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class NopAudioSystem : public AudioSystem {
|
||||
|
||||
static std::unique_ptr<AudioSystem> Create(Emulator* emulator);
|
||||
|
||||
X_STATUS CreateDriver(size_t index, HANDLE wait_handle,
|
||||
X_STATUS CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) override;
|
||||
void DestroyDriver(AudioDriver* driver) override;
|
||||
};
|
||||
|
||||
@@ -24,32 +24,27 @@ namespace xaudio2 {
|
||||
|
||||
class XAudio2AudioDriver::VoiceCallback : public IXAudio2VoiceCallback {
|
||||
public:
|
||||
VoiceCallback(HANDLE semaphore) : semaphore_(semaphore) {}
|
||||
VoiceCallback(xe::threading::Semaphore* semaphore) : semaphore_(semaphore) {}
|
||||
~VoiceCallback() {}
|
||||
|
||||
void OnStreamEnd() {}
|
||||
void OnVoiceProcessingPassEnd() {}
|
||||
void OnVoiceProcessingPassStart(uint32_t samples_required) {}
|
||||
void OnBufferEnd(void* context) {
|
||||
BOOL ret = ReleaseSemaphore(semaphore_, 1, NULL);
|
||||
assert_true(ret == TRUE);
|
||||
auto ret = semaphore_->Release(1, nullptr);
|
||||
assert_true(ret);
|
||||
}
|
||||
void OnBufferStart(void* context) {}
|
||||
void OnLoopEnd(void* context) {}
|
||||
void OnVoiceError(void* context, HRESULT result) {}
|
||||
|
||||
private:
|
||||
HANDLE semaphore_;
|
||||
xe::threading::Semaphore* semaphore_ = nullptr;
|
||||
};
|
||||
|
||||
XAudio2AudioDriver::XAudio2AudioDriver(Emulator* emulator, HANDLE semaphore)
|
||||
: AudioDriver(emulator),
|
||||
audio_(nullptr),
|
||||
mastering_voice_(nullptr),
|
||||
pcm_voice_(nullptr),
|
||||
semaphore_(semaphore),
|
||||
voice_callback_(nullptr),
|
||||
current_frame_(0) {
|
||||
XAudio2AudioDriver::XAudio2AudioDriver(Emulator* emulator,
|
||||
xe::threading::Semaphore* semaphore)
|
||||
: AudioDriver(emulator), semaphore_(semaphore) {
|
||||
static_assert(frame_count_ == XAUDIO2_MAX_QUEUED_BUFFERS,
|
||||
"xaudio header differs");
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace xaudio2 {
|
||||
|
||||
class XAudio2AudioDriver : public AudioDriver {
|
||||
public:
|
||||
XAudio2AudioDriver(Emulator* emulator, HANDLE semaphore);
|
||||
XAudio2AudioDriver(Emulator* emulator, xe::threading::Semaphore* semaphore);
|
||||
~XAudio2AudioDriver() override;
|
||||
|
||||
void Initialize();
|
||||
@@ -30,13 +30,13 @@ class XAudio2AudioDriver : public AudioDriver {
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
IXAudio2* audio_;
|
||||
IXAudio2MasteringVoice* mastering_voice_;
|
||||
IXAudio2SourceVoice* pcm_voice_;
|
||||
HANDLE semaphore_;
|
||||
IXAudio2* audio_ = nullptr;
|
||||
IXAudio2MasteringVoice* mastering_voice_ = nullptr;
|
||||
IXAudio2SourceVoice* pcm_voice_ = nullptr;
|
||||
xe::threading::Semaphore* semaphore_ = nullptr;
|
||||
|
||||
class VoiceCallback;
|
||||
VoiceCallback* voice_callback_;
|
||||
VoiceCallback* voice_callback_ = nullptr;
|
||||
|
||||
static const uint32_t frame_count_ = 64;
|
||||
static const uint32_t frame_channels_ = 6;
|
||||
@@ -44,7 +44,7 @@ class XAudio2AudioDriver : public AudioDriver {
|
||||
static const uint32_t frame_samples_ = frame_channels_ * channel_samples_;
|
||||
static const uint32_t frame_size_ = sizeof(float) * frame_samples_;
|
||||
float frames_[frame_count_][frame_samples_];
|
||||
uint32_t current_frame_;
|
||||
uint32_t current_frame_ = 0;
|
||||
};
|
||||
|
||||
} // namespace xaudio2
|
||||
|
||||
@@ -30,7 +30,8 @@ XAudio2AudioSystem::~XAudio2AudioSystem() {}
|
||||
|
||||
void XAudio2AudioSystem::Initialize() { AudioSystem::Initialize(); }
|
||||
|
||||
X_STATUS XAudio2AudioSystem::CreateDriver(size_t index, HANDLE semaphore,
|
||||
X_STATUS XAudio2AudioSystem::CreateDriver(size_t index,
|
||||
xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) {
|
||||
assert_not_null(out_driver);
|
||||
auto driver = new XAudio2AudioDriver(emulator_, semaphore);
|
||||
|
||||
@@ -23,7 +23,7 @@ class XAudio2AudioSystem : public AudioSystem {
|
||||
|
||||
static std::unique_ptr<AudioSystem> Create(Emulator* emulator);
|
||||
|
||||
X_RESULT CreateDriver(size_t index, HANDLE semaphore,
|
||||
X_RESULT CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) override;
|
||||
void DestroyDriver(AudioDriver* driver) override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user