mirror of https://github.com/RPCS3/rpcs3.git
cellMic: wait for registration of multiple input devices
This commit is contained in:
parent
0bcd45c1d4
commit
c2527c9e1b
|
@ -5,10 +5,13 @@
|
|||
#include "Emu/RSX/rsx_utils.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include "cellMic.h"
|
||||
#include "cellAudioIn.h"
|
||||
#include "cellAudioOut.h"
|
||||
#include "cellVideoOut.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
LOG_CHANNEL(cellAvconfExt);
|
||||
|
||||
template<>
|
||||
|
@ -34,9 +37,12 @@ void fmt_class_string<CellAudioInError>::format(std::string& out, u64 arg)
|
|||
|
||||
struct avconf_manager
|
||||
{
|
||||
shared_mutex mutex;
|
||||
std::vector<CellAudioInDeviceInfo> devices;
|
||||
CellAudioInDeviceMode inDeviceMode = CELL_AUDIO_IN_SINGLE_DEVICE_MODE; // TODO: use somewhere
|
||||
|
||||
void copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info);
|
||||
void copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info) const;
|
||||
std::optional<CellAudioInDeviceInfo> get_device_info(vm::cptr<char> name) const;
|
||||
|
||||
avconf_manager();
|
||||
|
||||
|
@ -49,7 +55,8 @@ avconf_manager::avconf_manager()
|
|||
{
|
||||
u32 curindex = 0;
|
||||
|
||||
auto mic_list = fmt::split(g_cfg.audio.microphone_devices.to_string(), {"@@@"});
|
||||
const std::vector<std::string> mic_list = fmt::split(g_cfg.audio.microphone_devices.to_string(), {"@@@"});
|
||||
|
||||
if (!mic_list.empty())
|
||||
{
|
||||
switch (g_cfg.audio.microphone_type)
|
||||
|
@ -131,20 +138,24 @@ avconf_manager::avconf_manager()
|
|||
}
|
||||
}
|
||||
|
||||
void avconf_manager::copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info)
|
||||
void avconf_manager::copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info) const
|
||||
{
|
||||
memset(info.get_ptr(), 0, sizeof(CellAudioInDeviceInfo));
|
||||
ensure(num < devices.size());
|
||||
*info = devices[num];
|
||||
}
|
||||
|
||||
info->portType = devices[num].portType;
|
||||
info->availableModeCount = devices[num].availableModeCount;
|
||||
info->state = devices[num].state;
|
||||
info->deviceId = devices[num].deviceId;
|
||||
info->type = devices[num].type;
|
||||
info->availableModes[0].type = devices[num].availableModes[0].type;
|
||||
info->availableModes[0].channel = devices[num].availableModes[0].channel;
|
||||
info->availableModes[0].fs = devices[num].availableModes[0].fs;
|
||||
info->deviceNumber = devices[num].deviceNumber;
|
||||
strcpy_trunc(info->name, devices[num].name);
|
||||
std::optional<CellAudioInDeviceInfo> avconf_manager::get_device_info(vm::cptr<char> name) const
|
||||
{
|
||||
for (const CellAudioInDeviceInfo& device : devices)
|
||||
{
|
||||
if (strncmp(device.name, name.get_ptr(), 64) == 0)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
error_code cellAudioOutUnregisterDevice(u32 deviceNumber)
|
||||
|
@ -199,6 +210,7 @@ error_code cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<C
|
|||
}
|
||||
|
||||
auto& av_manager = g_fxo->get<avconf_manager>();
|
||||
std::lock_guard lock(av_manager.mutex);
|
||||
|
||||
if (deviceNumber >= av_manager.devices.size())
|
||||
return CELL_AUDIO_OUT_ERROR_DEVICE_NOT_FOUND;
|
||||
|
@ -273,6 +285,7 @@ error_code cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDevic
|
|||
}
|
||||
|
||||
auto& av_manager = g_fxo->get<avconf_manager>();
|
||||
std::lock_guard lock(av_manager.mutex);
|
||||
|
||||
u32 num_devices_returned = std::min<u32>(count, ::size32(av_manager.devices));
|
||||
|
||||
|
@ -281,6 +294,15 @@ error_code cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDevic
|
|||
av_manager.copy_device_info(index, device_info + index);
|
||||
}
|
||||
|
||||
CellAudioInDeviceInfo disconnected_device{};
|
||||
disconnected_device.state = CELL_AUDIO_OUT_DEVICE_STATE_UNAVAILABLE;
|
||||
disconnected_device.deviceNumber = 0xff;
|
||||
|
||||
for (u32 index = num_devices_returned; index < count; index++)
|
||||
{
|
||||
device_info[index] = disconnected_device;
|
||||
}
|
||||
|
||||
return not_an_error(num_devices_returned);
|
||||
}
|
||||
|
||||
|
@ -355,6 +377,11 @@ error_code cellAudioInSetDeviceMode(u32 deviceMode)
|
|||
return CELL_AUDIO_IN_ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
auto& av_manager = g_fxo->get<avconf_manager>();
|
||||
std::lock_guard lock(av_manager.mutex);
|
||||
|
||||
av_manager.inDeviceMode = static_cast<CellAudioInDeviceMode>(deviceMode);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -368,12 +395,31 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
|
|||
return CELL_AUDIO_IN_ERROR_ILLEGAL_PARAMETER;
|
||||
}
|
||||
|
||||
return not_an_error(0); // device number
|
||||
auto& av_manager = g_fxo->get<avconf_manager>();
|
||||
const std::lock_guard lock(av_manager.mutex);
|
||||
|
||||
std::optional<CellAudioInDeviceInfo> info = av_manager.get_device_info(name);
|
||||
if (!info || !memchr(info->name, '\0', 64))
|
||||
{
|
||||
// TODO
|
||||
return CELL_AUDIO_IN_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
auto& mic_thr = g_fxo->get<mic_thread>();
|
||||
const std::lock_guard mic_lock(mic_thr.mutex);
|
||||
const u32 device_number = mic_thr.register_device(info->name);
|
||||
|
||||
return not_an_error(device_number);
|
||||
}
|
||||
|
||||
error_code cellAudioInUnregisterDevice(u32 deviceNumber)
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInUnregisterDevice(deviceNumber=0x%x)", deviceNumber);
|
||||
|
||||
auto& mic_thr = g_fxo->get<mic_thread>();
|
||||
const std::lock_guard lock(mic_thr.mutex);
|
||||
mic_thr.unregister_device(deviceNumber);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -103,8 +103,7 @@ void mic_context::operator()()
|
|||
|
||||
for (auto& mic_entry : mic_list)
|
||||
{
|
||||
auto& mic = mic_entry.second;
|
||||
mic.update_audio();
|
||||
mic_entry.update_audio();
|
||||
}
|
||||
|
||||
auto mic_queue = lv2_event_queue::find(event_queue_key);
|
||||
|
@ -113,9 +112,9 @@ void mic_context::operator()()
|
|||
return true;
|
||||
}
|
||||
|
||||
for (const auto& [dev_num, mic] : mic_list)
|
||||
for (usz dev_num = 0; dev_num < mic_list.size(); dev_num)
|
||||
{
|
||||
if (mic.has_data())
|
||||
if (mic_list[dev_num].has_data())
|
||||
{
|
||||
mic_queue->send(event_queue_source, CELLMIC_DATA, dev_num, 0);
|
||||
}
|
||||
|
@ -134,45 +133,77 @@ void mic_context::operator()()
|
|||
// Cleanup
|
||||
for (auto& mic_entry : mic_list)
|
||||
{
|
||||
mic_entry.second.close_microphone();
|
||||
mic_entry.close_microphone();
|
||||
}
|
||||
}
|
||||
|
||||
void mic_context::load_config_and_init()
|
||||
{
|
||||
auto device_list = fmt::split(g_cfg.audio.microphone_devices.to_string(), {"@@@"});
|
||||
const std::vector<std::string> device_list = fmt::split(g_cfg.audio.microphone_devices.to_string(), {"@@@"});
|
||||
|
||||
if (!device_list.empty() && mic_list.empty())
|
||||
{
|
||||
switch (g_cfg.audio.microphone_type)
|
||||
// We only register the first device. The rest is registered with cellAudioInRegisterDevice.
|
||||
if (g_cfg.audio.microphone_type == microphone_handler::singstar)
|
||||
{
|
||||
case microphone_handler::standard:
|
||||
{
|
||||
for (s32 index = 0; index < static_cast<s32>(device_list.size()); index++)
|
||||
{
|
||||
mic_list.emplace(std::piecewise_construct, std::forward_as_tuple(index), std::forward_as_tuple(microphone_handler::standard));
|
||||
::at32(mic_list, index).add_device(device_list[index]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case microphone_handler::singstar:
|
||||
{
|
||||
mic_list.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(microphone_handler::singstar));
|
||||
mic_list.emplace_back(microphone_handler::singstar);
|
||||
::at32(mic_list, 0).add_device(device_list[0]);
|
||||
|
||||
// Singstar uses the same device for 2 players
|
||||
if (device_list.size() >= 2)
|
||||
{
|
||||
::at32(mic_list, 0).add_device(device_list[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case microphone_handler::real_singstar:
|
||||
case microphone_handler::rocksmith:
|
||||
else
|
||||
{
|
||||
mic_list.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple(g_cfg.audio.microphone_type));
|
||||
::at32(mic_list, 0).add_device(device_list[0]);
|
||||
break;
|
||||
[[maybe_unused]] const u32 index = register_device(device_list[0]);
|
||||
}
|
||||
case microphone_handler::null:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 mic_context::register_device(const std::string& device_name, const std::string& name_2_for_singstar)
|
||||
{
|
||||
const usz index = mic_list.size();
|
||||
|
||||
switch (g_cfg.audio.microphone_type)
|
||||
{
|
||||
case microphone_handler::standard:
|
||||
case microphone_handler::real_singstar:
|
||||
case microphone_handler::rocksmith:
|
||||
{
|
||||
mic_list.emplace_back(g_cfg.audio.microphone_type.get());
|
||||
::at32(mic_list, index).add_device(device_name);
|
||||
|
||||
if (auto mic_queue = lv2_event_queue::find(event_queue_key))
|
||||
{
|
||||
mic_queue->send(event_queue_source, CELLMIC_ATTACH, index, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case microphone_handler::singstar:
|
||||
case microphone_handler::null:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ::narrow<u32>(index);
|
||||
}
|
||||
|
||||
void mic_context::unregister_device(u32 dev_num)
|
||||
{
|
||||
// Don't allow to unregister the first device for now.
|
||||
if (dev_num == 0 || dev_num >= mic_list.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mic_list.erase(mic_list.begin() + dev_num);
|
||||
|
||||
if (auto mic_queue = lv2_event_queue::find(event_queue_key))
|
||||
{
|
||||
mic_queue->send(event_queue_source, CELLMIC_DETACH, dev_num, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,7 +594,7 @@ error_code cellMicOpenEx(s32 dev_num, s32 rawSampleRate, s32 rawChannel, s32 DSP
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -599,7 +630,7 @@ u8 cellMicIsOpen(s32 dev_num)
|
|||
if (!mic_thr.init)
|
||||
return false;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return false;
|
||||
|
||||
return ::at32(mic_thr.mic_list, dev_num).is_opened();
|
||||
|
@ -620,7 +651,7 @@ error_code cellMicClose(s32 dev_num)
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -645,7 +676,7 @@ error_code cellMicStartEx(s32 dev_num, u32 iflags)
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -675,7 +706,7 @@ error_code cellMicStop(s32 dev_num)
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -705,7 +736,7 @@ error_code cellMicGetDeviceAttr(s32 dev_num, CellMicDeviceAttr deviceAttributes,
|
|||
if (dev_num < 0)
|
||||
return CELL_MICIN_ERROR_PARAM;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -741,7 +772,7 @@ error_code cellMicSetDeviceAttr(s32 dev_num, CellMicDeviceAttr deviceAttributes,
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -777,7 +808,7 @@ error_code cellMicGetSignalAttr(s32 dev_num, CellMicSignalAttr sig_attrib, vm::p
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& mic = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -801,7 +832,7 @@ error_code cellMicSetSignalAttr(s32 dev_num, CellMicSignalAttr sig_attrib, vm::p
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& mic = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -825,7 +856,7 @@ error_code cellMicGetSignalState(s32 dev_num, CellMicSignalState sig_state, vm::
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& mic = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -876,7 +907,7 @@ error_code cellMicGetFormatEx(s32 dev_num, vm::ptr<CellMicInputFormatI> format,
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& device = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -937,9 +968,9 @@ error_code cellMicSetNotifyEventQueue(u64 key)
|
|||
mic_thr.event_queue_key = key;
|
||||
|
||||
// TODO: Properly generate/handle mic events
|
||||
for (const auto& mic_entry : mic_thr.mic_list)
|
||||
for (usz i = 0; i < mic_thr.mic_list.size(); i)
|
||||
{
|
||||
mic_queue->send(0, CELLMIC_ATTACH, mic_entry.first, 0);
|
||||
mic_queue->send(0, CELLMIC_ATTACH, i, 0);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
@ -963,9 +994,9 @@ error_code cellMicSetNotifyEventQueue2(u64 key, u64 source, u64 flag)
|
|||
mic_thr.event_queue_source = source;
|
||||
|
||||
// TODO: Properly generate/handle mic events
|
||||
for (const auto& mic_entry : mic_thr.mic_list)
|
||||
for (usz i = 0; i < mic_thr.mic_list.size(); i)
|
||||
{
|
||||
mic_queue->send(source, CELLMIC_ATTACH, mic_entry.first, 0);
|
||||
mic_queue->send(source, CELLMIC_ATTACH, i, 0);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
@ -997,7 +1028,7 @@ error_code cell_mic_read(s32 dev_num, vm::ptr<void> data, s32 max_bytes, /*CellM
|
|||
if (!mic_thr.init)
|
||||
return CELL_MICIN_ERROR_NOT_INIT;
|
||||
|
||||
if (!mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num >= static_cast<s32>(mic_thr.mic_list.size()))
|
||||
return CELL_MICIN_ERROR_DEVICE_NOT_FOUND;
|
||||
|
||||
auto& mic = ::at32(mic_thr.mic_list, dev_num);
|
||||
|
@ -1117,7 +1148,7 @@ error_code cellMicGetStatus(s32 dev_num, vm::ptr<CellMicStatus> status)
|
|||
|
||||
// TODO
|
||||
|
||||
if (mic_thr.mic_list.contains(dev_num))
|
||||
if (dev_num < static_cast<s32>(mic_thr.mic_list.size()))
|
||||
{
|
||||
const auto& mic = ::at32(mic_thr.mic_list, dev_num);
|
||||
status->raw_samprate = mic.get_raw_samplingrate();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utilities/Thread.h"
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
|
||||
#include "3rdparty/OpenAL/include/alext.h"
|
||||
|
||||
|
@ -351,10 +352,14 @@ public:
|
|||
void operator()();
|
||||
void load_config_and_init();
|
||||
|
||||
// Returns index of registered device
|
||||
u32 register_device(const std::string& name, const std::string& name_2_for_singstar = {});
|
||||
void unregister_device(u32 dev_num);
|
||||
|
||||
u64 event_queue_key = 0;
|
||||
u64 event_queue_source = 0;
|
||||
|
||||
std::unordered_map<s32, microphone_device> mic_list;
|
||||
std::vector<microphone_device> mic_list;
|
||||
|
||||
shared_mutex mutex;
|
||||
atomic_t<u8> init = 0;
|
||||
|
|
Loading…
Reference in New Issue