Refactor audio/camera/mic threads

This commit is contained in:
Nekotekina 2018-10-01 20:58:34 +03:00
parent 19a64e0e94
commit 1456678316
6 changed files with 88 additions and 126 deletions

View file

@ -8,8 +8,6 @@
#include "Emu/Audio/AudioThread.h"
#include "cellAudio.h"
#include <thread>
LOG_CHANNEL(cellAudio);
template <>
@ -40,22 +38,7 @@ void fmt_class_string<CellAudioError>::format(std::string& out, u64 arg)
});
}
void audio_config::on_init(const std::shared_ptr<void>& _this)
{
m_buffer.set(vm::alloc(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, vm::main));
m_indexes.set(vm::alloc(sizeof(u64) * AUDIO_PORT_COUNT, vm::main));
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
{
ports[i].number = i;
ports[i].addr = m_buffer + AUDIO_PORT_OFFSET * i;
ports[i].index = m_indexes + i;
}
old_thread::on_init(_this);
}
void audio_config::on_task()
std::pair<u32, u32> audio_thread::operator()()
{
thread_ctrl::set_native_priority(1);
@ -76,11 +59,11 @@ void audio_config::on_task()
const auto audio = Emu.GetCallbacks().get_audio();
audio->Open(buf8ch, buf_sz);
while (fxm::check<audio_config>() && !Emu.IsStopped())
while (fxm::check<audio_config>() == this && !Emu.IsStopped())
{
if (Emu.IsPaused())
{
std::this_thread::sleep_for(1ms); // hack
thread_ctrl::wait_for(1000); // hack
continue;
}
@ -94,7 +77,7 @@ void audio_config::on_task()
const u64 expected_time = m_counter * AUDIO_SAMPLES * 1000000 / 48000;
if (expected_time >= time_pos)
{
std::this_thread::sleep_for(1ms); // hack
thread_ctrl::wait_for(1000); // hack
continue;
}
@ -342,17 +325,24 @@ void audio_config::on_task()
cellAudio.trace("Audio perf: (access=%d, AddData=%d, events=%d, dump=%d)",
stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
}
return {m_buffer.addr(), m_indexes.addr()};
}
error_code cellAudioInit()
{
cellAudio.warning("cellAudioInit()");
const auto buf = vm::cast(vm::alloc(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, vm::main));
const auto ind = vm::cast(vm::alloc(sizeof(u64) * AUDIO_PORT_COUNT, vm::main));
// Start audio thread
const auto g_audio = fxm::make<audio_config>();
const auto g_audio = fxm::make<audio_config>("Audio Thread", buf, ind);
if (!g_audio)
{
vm::dealloc(buf);
vm::dealloc(ind);
return CELL_AUDIO_ERROR_ALREADY_INIT;
}
@ -371,6 +361,10 @@ error_code cellAudioQuit()
return CELL_AUDIO_ERROR_NOT_INIT;
}
// Join and dealloc
auto [buf, ind] = g_audio->operator()();
vm::dealloc(buf);
vm::dealloc(ind);
return CELL_OK;
}

View file

@ -2,8 +2,6 @@
#include "Utilities/Thread.h"
// Error codes
enum CellAudioError : u32
{
@ -85,8 +83,6 @@ enum : u32
AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES,
};
extern u64 get_system_time();
enum class audio_port_state : u32
{
closed,
@ -96,7 +92,7 @@ enum class audio_port_state : u32
struct audio_port
{
atomic_t<audio_port_state> state{ audio_port_state::closed };
atomic_t<audio_port_state> state = audio_port_state::closed;
u32 number;
vm::ptr<char> addr{};
@ -119,36 +115,36 @@ struct audio_port
atomic_t<level_set_t> level_set;
};
class audio_config final : public old_thread
class audio_thread
{
void on_task() override;
std::string get_name() const override { return "Audio Thread"; }
vm::ptr<char> m_buffer = vm::null;
vm::ptr<u64> m_indexes = vm::null;
vm::ptr<char> m_buffer;
vm::ptr<u64> m_indexes;
u64 m_counter{};
public:
void on_init(const std::shared_ptr<void>&) override;
const u64 start_time = get_system_time();
std::array<audio_port, AUDIO_PORT_COUNT> ports;
std::vector<u64> keys;
semaphore<> mutex;
shared_mutex mutex;
audio_config() = default;
~audio_config()
audio_thread(vm::ptr<char> buf, vm::ptr<u64> ind)
: m_buffer(buf)
, m_indexes(ind)
{
vm::dealloc_verbose_nothrow(m_buffer.addr());
vm::dealloc_verbose_nothrow(m_indexes.addr());
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
{
ports[i].number = i;
ports[i].addr = m_buffer + AUDIO_PORT_OFFSET * i;
ports[i].index = m_indexes + i;
}
}
std::pair<u32, u32> operator()();
audio_port* open_port()
{
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
@ -162,3 +158,5 @@ public:
return nullptr;
}
};
using audio_config = named_thread<audio_thread>;

View file

@ -7,8 +7,6 @@
#include "Emu/Io/PadHandler.h"
#include "Emu/System.h"
#include <thread>
LOG_CHANNEL(cellCamera);
// **************
@ -284,7 +282,7 @@ s32 cellCameraInit()
}
// Start camera thread
const auto g_camera = fxm::make<camera_thread>();
const auto g_camera = fxm::make<camera_thread>("Camera Thread");
if (!g_camera)
{
@ -356,6 +354,13 @@ s32 cellCameraEnd()
return CELL_OK;
}
const auto g_camera = fxm::withdraw<camera_thread>();
if (!g_camera)
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
// TODO: My tests hinted to this behavior, but I'm not sure, so I'll leave this commented
//s32 res = cellCameraClose(0);
//if (res != CELL_OK)
@ -363,11 +368,8 @@ s32 cellCameraEnd()
// return res;
//}
if (!fxm::remove<camera_thread>())
{
return CELL_CAMERA_ERROR_NOT_INIT;
}
// Join thread
g_camera->operator()();
return CELL_OK;
}
@ -1154,19 +1156,19 @@ DECLARE(ppu_module_manager::cellCamera)("cellCamera", []()
// camera_thread members
void camera_thread::on_task()
void camera_context::operator()()
{
while (fxm::check<camera_thread>() && !Emu.IsStopped())
while (fxm::check<camera_thread>() == this && !Emu.IsStopped())
{
std::chrono::steady_clock::time_point frame_start = std::chrono::steady_clock::now();
const u64 frame_start = get_system_time();
if (Emu.IsPaused())
{
std::this_thread::sleep_for(1ms); // hack
thread_ctrl::wait_for(1000); // hack
continue;
}
std::lock_guard lock(mutex_notify_data_map);
std::unique_lock lock(mutex_notify_data_map);
for (auto const& notify_data_entry : notify_data_map)
{
@ -1180,8 +1182,8 @@ void camera_thread::on_task()
{
if (auto queue = lv2_event_queue::find(key))
{
u64 data2{ 0 };
u64 data3{ 0 };
u64 data2 = 0;
u64 data3 = 0;
if (read_mode.load() == CELL_CAMERA_READ_DIRECT)
{
@ -1205,29 +1207,22 @@ void camera_thread::on_task()
}
}
}
}
const std::chrono::microseconds frame_target_time{ static_cast<u32>(1000000.0 / info.framerate) };
lock.unlock();
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
std::chrono::microseconds frame_processing_time = std::chrono::duration_cast<std::chrono::microseconds>(now - frame_start);
if (frame_processing_time < frame_target_time)
for (const u64 frame_target_time = 1000000u / info.framerate;;)
{
std::chrono::microseconds frame_idle_time = frame_target_time - frame_processing_time;
std::this_thread::sleep_for(frame_idle_time);
const u64 time_passed = get_system_time() - frame_start;
if (time_passed >= frame_target_time)
break;
thread_ctrl::wait_for(frame_target_time - time_passed);
}
}
}
void camera_thread::on_init(const std::shared_ptr<void>& _this)
{
old_thread::on_init(_this);
}
void camera_thread::send_attach_state(bool attached)
void camera_context::send_attach_state(bool attached)
{
std::lock_guard lock(mutex_notify_data_map);
@ -1255,7 +1250,7 @@ void camera_thread::send_attach_state(bool attached)
}
}
void camera_thread::set_attr(s32 attrib, u32 arg1, u32 arg2)
void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2)
{
if (attrib == CELL_CAMERA_READMODE)
{
@ -1271,7 +1266,7 @@ void camera_thread::set_attr(s32 attrib, u32 arg1, u32 arg2)
attr[attrib] = {arg1, arg2};
}
void camera_thread::add_queue(u64 key, u64 source, u64 flag)
void camera_context::add_queue(u64 key, u64 source, u64 flag)
{
std::lock_guard lock(mutex);
{
@ -1284,7 +1279,7 @@ void camera_thread::add_queue(u64 key, u64 source, u64 flag)
send_attach_state(true);
}
void camera_thread::remove_queue(u64 key)
void camera_context::remove_queue(u64 key)
{
std::lock_guard lock(mutex);
{

View file

@ -351,21 +351,16 @@ struct CellCameraReadEx
vm::bptr<u8> pbuf;
};
class camera_thread final : public old_thread
class camera_context
{
private:
struct notify_event_data
{
u64 source;
u64 flag;
};
void on_task() override;
std::string get_name() const override { return "Camera Thread"; }
public:
void on_init(const std::shared_ptr<void>&) override;
void operator()();
void send_attach_state(bool attached);
void set_attr(s32 attrib, u32 arg1, u32 arg2);
@ -385,11 +380,11 @@ public:
std::map<u64, notify_event_data> notify_data_map;
semaphore<> mutex;
semaphore<> mutex_notify_data_map;
shared_mutex mutex;
shared_mutex mutex_notify_data_map;
Timer timer;
atomic_t<u8> read_mode{0};
atomic_t<u8> read_mode{CELL_CAMERA_READ_FUNCCALL};
atomic_t<bool> is_streaming{false};
atomic_t<bool> is_attached{false};
atomic_t<bool> is_open{false};
@ -404,11 +399,10 @@ public:
lv2_memory_container container;
atomic_t<u32> frame_num;
camera_thread() : read_mode(CELL_CAMERA_READ_FUNCCALL) {}
~camera_thread() = default;
};
using camera_thread = named_thread<camera_context>;
/// Shared data between cellGem and cellCamera
struct gem_camera_shared
{

View file

@ -5,38 +5,24 @@
#include "cellMic.h"
#include <Emu/IdManager.h>
#include <Emu/Cell/lv2/sys_event.h>
#include <thread>
LOG_CHANNEL(cellMic);
void mic_thread::on_init(const std::shared_ptr<void>& _this)
void mic_context::operator()()
{
old_thread::on_init(_this);
}
void mic_thread::on_task()
{
while (micInited && !Emu.IsStopped())
while (fxm::check<mic_thread>() == this && !Emu.IsStopped())
{
thread_ctrl::wait_for(1000);
if (Emu.IsPaused())
{
std::this_thread::sleep_for(1ms); // hack from cellAudio
continue;
}
if (!micOpened || !micStarted)
continue;
// If event queue is not set, then we can't send any events
if (eventQueueKey == 0)
continue;
std::this_thread::sleep_for(1s);
// Make sure the mic thread wasn't stopped while we were sleeping
if (!micInited)
break;
auto micQueue = lv2_event_queue::find(eventQueueKey);
if (!micQueue)
continue;
micQueue->send(0, CELL_MIC_DATA, 0, 0);
}
@ -47,8 +33,8 @@ void mic_thread::on_task()
s32 cellMicInit()
{
cellMic.notice("cellMicInit()");
const auto micThread = fxm::make<mic_thread>();
micInited = true;
const auto micThread = fxm::make<mic_thread>("Mic Thread");
if (!micThread)
return CELL_MIC_ERROR_ALREADY_INIT;
@ -58,11 +44,13 @@ s32 cellMicInit()
s32 cellMicEnd()
{
cellMic.notice("cellMicEnd()");
micInited = false;
const auto micThread = fxm::withdraw<mic_thread>();
if (!micThread)
return CELL_MIC_ERROR_NOT_INIT;
// Join
micThread->operator()();
return CELL_OK;
}
@ -479,8 +467,8 @@ s32 cellMicGetDeviceIdentifier()
return CELL_OK;
}
DECLARE(ppu_module_manager::cellMic)
("cellMic", []() {
DECLARE(ppu_module_manager::cellMic)("cellMic", []()
{
REG_FUNC(cellMic, cellMicInit);
REG_FUNC(cellMic, cellMicEnd);
REG_FUNC(cellMic, cellMicOpen);

View file

@ -52,15 +52,11 @@ enum CellMicCommand
// TODO: generate this from input from an actual microphone
const u32 bufferSize = 1;
bool micInited = false;
class mic_thread final : public old_thread
class mic_context
{
private:
void on_task() override;
std::string get_name() const override { return "Mic Thread"; }
public:
void on_init(const std::shared_ptr<void>&) override;
void operator()();
// Default value of 48000 for no particular reason
u32 DspFrequency = 48000; // DSP is the default type
u32 rawFrequency = 48000;
@ -76,9 +72,6 @@ public:
f32 signalStateGainControl;
f32 signalStateMicSignalLevel; // value is in decibels
f32 signalStateSpeakerSignalLevel; // value is in decibels
mic_thread() = default;
~mic_thread()
{
micInited = false;
}
};
using mic_thread = named_thread<mic_context>;