diff --git a/rpcs3/Emu/Cell/Modules/cellAudioIn.h b/rpcs3/Emu/Cell/Modules/cellAudioIn.h index dc2ca6d130..7ceaa2d2bd 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioIn.h +++ b/rpcs3/Emu/Cell/Modules/cellAudioIn.h @@ -75,7 +75,7 @@ struct CellAudioInDeviceInfo u8 reserved[12]; be_t deviceId; be_t type; - char name[64]; + char name[64]; // Not necessarily null terminated! CellAudioInSoundMode availableModes[16]; }; diff --git a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp index ed0e3d7526..32b44ccd59 100644 --- a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp @@ -38,11 +38,17 @@ void fmt_class_string::format(std::string& out, u64 arg) struct avconf_manager { shared_mutex mutex; - std::vector devices; + + struct device_info + { + CellAudioInDeviceInfo info {}; + std::string full_device_name; // The device name may be too long for CellAudioInDeviceInfo, so we additionally save the full name. + }; + std::vector devices; CellAudioInDeviceMode inDeviceMode = CELL_AUDIO_IN_SINGLE_DEVICE_MODE; // TODO: use somewhere void copy_device_info(u32 num, vm::ptr info) const; - std::optional get_device_info(vm::cptr name) const; + std::optional get_device_info(vm::cptr name) const; avconf_manager(); @@ -62,78 +68,89 @@ avconf_manager::avconf_manager() switch (g_cfg.audio.microphone_type) { case microphone_handler::standard: + { for (u32 index = 0; index < mic_list.size(); index++) { - devices.emplace_back(); - - devices[curindex].portType = CELL_AUDIO_IN_PORT_USB; - devices[curindex].availableModeCount = 1; - devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; - devices[curindex].deviceId = 0xE11CC0DE + curindex; - devices[curindex].type = 0xC0DEE11C; - devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; - devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2; - devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; - devices[curindex].deviceNumber = curindex; - strcpy_trunc(devices[curindex].name, mic_list[index]); + device_info device {}; + device.info.portType = CELL_AUDIO_IN_PORT_USB; + device.info.availableModeCount = 1; + device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; + device.info.deviceId = 0xE11CC0DE + curindex; + device.info.type = 0xC0DEE11C; + device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; + device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2; + device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; + device.info.deviceNumber = curindex; + device.full_device_name = mic_list[index]; + strcpy_trunc(device.info.name, device.full_device_name); + devices.push_back(std::move(device)); curindex++; } break; + } case microphone_handler::real_singstar: case microphone_handler::singstar: + { // Only one device for singstar device - devices.emplace_back(); - - devices[curindex].portType = CELL_AUDIO_IN_PORT_USB; - devices[curindex].availableModeCount = 1; - devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; - devices[curindex].deviceId = 0x00000001; - devices[curindex].type = 0x14150000; - devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; - devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2; - devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; - devices[curindex].deviceNumber = curindex; - strcpy_trunc(devices[curindex].name, mic_list[0]); + device_info device {}; + device.info.portType = CELL_AUDIO_IN_PORT_USB; + device.info.availableModeCount = 1; + device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; + device.info.deviceId = 0x00000001; + device.info.type = 0x14150000; + device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; + device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2; + device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; + device.info.deviceNumber = curindex; + device.full_device_name = mic_list[0]; + strcpy_trunc(device.info.name, device.full_device_name); + devices.push_back(std::move(device)); curindex++; break; + } case microphone_handler::rocksmith: - devices.emplace_back(); - - devices[curindex].portType = CELL_AUDIO_IN_PORT_USB; - devices[curindex].availableModeCount = 1; - devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; - devices[curindex].deviceId = 0x12BA00FF; // Specific to rocksmith usb input - devices[curindex].type = 0xC0DE73C4; - devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; - devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1; - devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; - devices[curindex].deviceNumber = curindex; - strcpy_trunc(devices[curindex].name, mic_list[0]); + { + device_info device {}; + device.info.portType = CELL_AUDIO_IN_PORT_USB; + device.info.availableModeCount = 1; + device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; + device.info.deviceId = 0x12BA00FF; // Specific to rocksmith usb input + device.info.type = 0xC0DE73C4; + device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; + device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1; + device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; + device.info.deviceNumber = curindex; + device.full_device_name = mic_list[0]; + strcpy_trunc(device.info.name, device.full_device_name); + devices.push_back(std::move(device)); curindex++; break; + } case microphone_handler::null: - default: break; + default: + break; } } if (g_cfg.io.camera != camera_handler::null) { - devices.emplace_back(); - - devices[curindex].portType = CELL_AUDIO_IN_PORT_USB; - devices[curindex].availableModeCount = 1; - devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; - devices[curindex].deviceId = 0xDEADBEEF; - devices[curindex].type = 0xBEEFDEAD; - devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; - devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE; - devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; - devices[curindex].deviceNumber = curindex; - strcpy_trunc(devices[curindex].name, "USB Camera"); + device_info device {}; + device.info.portType = CELL_AUDIO_IN_PORT_USB; + device.info.availableModeCount = 1; + device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE; + device.info.deviceId = 0xDEADBEEF; + device.info.type = 0xBEEFDEAD; + device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; + device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE; + device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ; + device.info.deviceNumber = curindex; + device.full_device_name = "USB Camera"; + strcpy_trunc(device.info.name, device.full_device_name); + devices.push_back(std::move(device)); curindex++; } } @@ -142,14 +159,14 @@ void avconf_manager::copy_device_info(u32 num, vm::ptr in { memset(info.get_ptr(), 0, sizeof(CellAudioInDeviceInfo)); ensure(num < devices.size()); - *info = devices[num]; + *info = devices[num].info; } -std::optional avconf_manager::get_device_info(vm::cptr name) const +std::optional avconf_manager::get_device_info(vm::cptr name) const { - for (const CellAudioInDeviceInfo& device : devices) + for (const device_info& device : devices) { - if (strncmp(device.name, name.get_ptr(), sizeof(device.name)) == 0) + if (strncmp(device.info.name, name.get_ptr(), sizeof(device.info.name)) == 0) { return device; } @@ -398,8 +415,8 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr name, vm::pt auto& av_manager = g_fxo->get(); const std::lock_guard lock(av_manager.mutex); - std::optional info = av_manager.get_device_info(name); - if (!info || !memchr(info->name, '\0', sizeof(info->name))) + std::optional device = av_manager.get_device_info(name); + if (!device) { // TODO return CELL_AUDIO_IN_ERROR_DEVICE_NOT_FOUND; @@ -407,7 +424,7 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr name, vm::pt auto& mic_thr = g_fxo->get(); const std::lock_guard mic_lock(mic_thr.mutex); - const u32 device_number = mic_thr.register_device(info->name); + const u32 device_number = mic_thr.register_device(device->full_device_name); return not_an_error(device_number); } diff --git a/rpcs3/Emu/Cell/Modules/cellMic.cpp b/rpcs3/Emu/Cell/Modules/cellMic.cpp index 864df5baa1..a5ece1be59 100644 --- a/rpcs3/Emu/Cell/Modules/cellMic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMic.cpp @@ -322,6 +322,8 @@ error_code microphone_device::open_microphone(const u8 type, const u32 dsp_r, co num_channels = channels; #ifndef WITHOUT_OPENAL + enumerate_devices(); + // Adjust number of channels depending on microphone type switch (device_type) { @@ -662,8 +664,43 @@ u32 microphone_device::capture_audio() // Private functions #ifndef WITHOUT_OPENAL -ALCdevice* microphone_device::open_device(std::string& name, u32 samplingrate, ALCenum num_al_channels, u32 buf_size) +void microphone_device::enumerate_devices() { + cellMic.notice("Enumerating capture devices..."); + enumerated_devices.clear(); + + if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_TRUE) + { + if (const char* alc_devices = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER)) + { + while (alc_devices && *alc_devices != 0) + { + cellMic.notice("Found capture device: '%s'", alc_devices); + enumerated_devices.push_back(alc_devices); + alc_devices += strlen(alc_devices) + 1; + } + } + } + else + { + // Without enumeration we can only use one device + cellMic.error("OpenAl extension ALC_ENUMERATION_EXT not supported. The enumerated capture devices will only contain the default capture device."); + + if (const char* alc_device = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER)) + { + cellMic.notice("Found default capture device: '%s'", alc_device); + enumerated_devices.push_back(alc_device); + } + } +} + +ALCdevice* microphone_device::open_device(const std::string& name, u32 samplingrate, ALCenum num_al_channels, u32 buf_size) +{ + if (std::none_of(enumerated_devices.cbegin(), enumerated_devices.cend(), [&name](const std::string& dev){ return dev == name; })) + { + cellMic.error("Capture device '%s' not in enumerated devices", name); + } + ALCdevice* device = alcCaptureOpenDevice(name.c_str(), samplingrate, num_al_channels, buf_size); if (ALCenum err = alcGetError(device); err != ALC_NO_ERROR || !device) diff --git a/rpcs3/Emu/Cell/Modules/cellMic.h b/rpcs3/Emu/Cell/Modules/cellMic.h index e25488c19c..e4b416fa6a 100644 --- a/rpcs3/Emu/Cell/Modules/cellMic.h +++ b/rpcs3/Emu/Cell/Modules/cellMic.h @@ -327,7 +327,8 @@ private: inline u32 convert_16_bit_pcm_to_float(const std::vector& buffer, u32 num_bytes); #ifndef WITHOUT_OPENAL - ALCdevice* open_device(std::string& name, u32 samplingrate, ALCenum num_al_channels, u32 buf_size); + void enumerate_devices(); + ALCdevice* open_device(const std::string& name, u32 samplingrate, ALCenum num_al_channels, u32 buf_size); #endif u32 capture_audio(); @@ -349,6 +350,7 @@ private: std::vector buf; }; + std::vector enumerated_devices; std::vector devices; std::vector temp_buf; std::vector float_buf; @@ -380,7 +382,7 @@ public: void wake_up(); // Returns index of registered device - u32 register_device(const std::string& name); + u32 register_device(const std::string& device_name); void unregister_device(u32 dev_num); bool check_device(u32 dev_num);