Audio system overhaul for support of multiple audio drivers.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <xenia/apu/audio_system.h>
|
||||
#include <xenia/apu/audio_driver.h>
|
||||
|
||||
#include <xenia/emulator.h>
|
||||
#include <xenia/cpu/processor.h>
|
||||
@@ -21,12 +22,19 @@ using namespace xe::cpu;
|
||||
|
||||
AudioSystem::AudioSystem(Emulator* emulator) :
|
||||
emulator_(emulator), memory_(emulator->memory()),
|
||||
thread_(0), running_(false),
|
||||
client_({ 0 }) {
|
||||
thread_(0), running_(false) {
|
||||
lock_ = xe_mutex_alloc();
|
||||
memset(clients_, 0, sizeof(clients_));
|
||||
for (size_t i = 0; i < maximum_client_count_; ++i) {
|
||||
client_wait_handles_[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
unused_clients_.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
AudioSystem::~AudioSystem() {
|
||||
for (size_t i = 0; i < maximum_client_count_; ++i) {
|
||||
CloseHandle(client_wait_handles_[i]);
|
||||
}
|
||||
xe_mutex_free(lock_);
|
||||
}
|
||||
|
||||
@@ -70,27 +78,34 @@ void AudioSystem::ThreadStart() {
|
||||
|
||||
// Main run loop.
|
||||
while (running_) {
|
||||
// Pump worker.
|
||||
// This may block.
|
||||
Pump();
|
||||
|
||||
xe_mutex_lock(lock_);
|
||||
uint32_t client_callback = client_.callback;
|
||||
uint32_t client_callback_arg = client_.wrapped_callback_arg;
|
||||
xe_mutex_unlock(lock_);
|
||||
if (client_callback) {
|
||||
processor->Execute(
|
||||
thread_state_, client_callback, client_callback_arg, 0);
|
||||
} else {
|
||||
Sleep(500);
|
||||
auto result = WaitForMultipleObjectsEx(maximum_client_count_, client_wait_handles_, FALSE, INFINITE, FALSE);
|
||||
if (result == WAIT_FAILED) {
|
||||
DWORD err = GetLastError();
|
||||
XEASSERTALWAYS();
|
||||
}
|
||||
size_t pumped = 0;
|
||||
if (result >= WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + (maximum_client_count_ - 1)) {
|
||||
size_t index = result - WAIT_OBJECT_0;
|
||||
do {
|
||||
xe_mutex_lock(lock_);
|
||||
uint32_t client_callback = clients_[index].callback;
|
||||
uint32_t client_callback_arg = clients_[index].wrapped_callback_arg;
|
||||
xe_mutex_unlock(lock_);
|
||||
if (client_callback) {
|
||||
processor->Execute(thread_state_, client_callback, client_callback_arg, 0);
|
||||
}
|
||||
pumped++;
|
||||
index++;
|
||||
} while (index < maximum_client_count_ && WaitForSingleObject(client_wait_handles_[index], 0) == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
if (!running_) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Pump audio system.
|
||||
Pump();
|
||||
if (!pumped) {
|
||||
Sleep(500);
|
||||
}
|
||||
}
|
||||
running_ = false;
|
||||
|
||||
@@ -109,23 +124,53 @@ void AudioSystem::Shutdown() {
|
||||
memory()->HeapFree(thread_block_, 0);
|
||||
}
|
||||
|
||||
void AudioSystem::RegisterClient(
|
||||
uint32_t callback, uint32_t callback_arg) {
|
||||
// Only support one client for now.
|
||||
XEASSERTZERO(client_.callback);
|
||||
X_STATUS AudioSystem::RegisterClient(
|
||||
uint32_t callback, uint32_t callback_arg, size_t* out_index) {
|
||||
XEASSERTTRUE(unused_clients_.size());
|
||||
xe_mutex_lock(lock_);
|
||||
|
||||
auto index = unused_clients_.front();
|
||||
|
||||
auto wait_handle = client_wait_handles_[index];
|
||||
ResetEvent(wait_handle);
|
||||
AudioDriver* driver;
|
||||
auto result = CreateDriver(index, wait_handle, &driver);
|
||||
if (XFAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
XEASSERTNOTNULL(driver != NULL);
|
||||
|
||||
unused_clients_.pop();
|
||||
|
||||
uint32_t ptr = (uint32_t)memory()->HeapAlloc(0, 0x4, 0);
|
||||
auto mem = memory()->membase();
|
||||
XESETUINT32BE(mem + ptr, callback_arg);
|
||||
|
||||
clients_[index] = { driver, callback, callback_arg, ptr };
|
||||
|
||||
if (out_index) {
|
||||
*out_index = index;
|
||||
}
|
||||
|
||||
xe_mutex_unlock(lock_);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void AudioSystem::SubmitFrame(size_t index, uint32_t samples_ptr) {
|
||||
xe_mutex_lock(lock_);
|
||||
client_ = { callback, callback_arg, ptr };
|
||||
XEASSERTTRUE(index < maximum_client_count_);
|
||||
XEASSERTTRUE(clients_[index].driver != NULL);
|
||||
(clients_[index].driver)->SubmitFrame(samples_ptr);
|
||||
ResetEvent(client_wait_handles_[index]);
|
||||
xe_mutex_unlock(lock_);
|
||||
}
|
||||
|
||||
void AudioSystem::UnregisterClient() {
|
||||
void AudioSystem::UnregisterClient(size_t index) {
|
||||
xe_mutex_lock(lock_);
|
||||
client_ = { 0 };
|
||||
XEASSERTTRUE(index < maximum_client_count_);
|
||||
DestroyDriver(clients_[index].driver);
|
||||
clients_[index] = { 0 };
|
||||
unused_clients_.push(index);
|
||||
xe_mutex_unlock(lock_);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user