mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
cellAudioOut: fix sound_mode exception
Turns out some games don't configure proper channel counts after all, which triggers an ensure in cellAudioOutGetState. Let's select the current sound_mode in cellAudioOutConfigure. Keep the old one if no match was found. Also moves some code from AudioBackend to cellAudioOut for thread safety (see mutex).
This commit is contained in:
parent
11c5230628
commit
ebabdd37b4
3 changed files with 81 additions and 63 deletions
|
@ -106,43 +106,7 @@ std::pair<AudioChannelCnt, AudioChannelCnt> AudioBackend::get_channel_count_and_
|
|||
std::lock_guard lock(audio_out_cfg.mtx);
|
||||
ensure(device_index < audio_out_cfg.out.size());
|
||||
const audio_out_configuration::audio_out& out = audio_out_cfg.out.at(device_index);
|
||||
|
||||
switch (out.downmixer)
|
||||
{
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_NONE:
|
||||
{
|
||||
switch (out.channels)
|
||||
{
|
||||
case 2: return { AudioChannelCnt::STEREO, AudioChannelCnt::STEREO };
|
||||
case 6: return { AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::SURROUND_5_1 };
|
||||
case 8: return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_7_1 };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count in cellAudioOut config: %d", out.channels);
|
||||
}
|
||||
}
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_A:
|
||||
{
|
||||
switch (out.channels)
|
||||
{
|
||||
case 2:
|
||||
return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_A in cellAudioOut config: %d", out.channels);
|
||||
}
|
||||
}
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_B:
|
||||
{
|
||||
switch (out.channels)
|
||||
{
|
||||
case 6:
|
||||
return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1 };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_B in cellAudioOut config: %d", out.channels);
|
||||
}
|
||||
}
|
||||
default:
|
||||
fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", out.downmixer);
|
||||
}
|
||||
return out.get_channel_count_and_downmixer();
|
||||
}
|
||||
|
||||
AudioChannelCnt AudioBackend::get_max_channel_count(u32 device_index)
|
||||
|
|
|
@ -73,6 +73,7 @@ audio_out_configuration::audio_out_configuration()
|
|||
// Pre-select the first available sound mode
|
||||
output.channels = channel;
|
||||
output.encoder = type;
|
||||
output.sound_mode = output.sound_modes.back();
|
||||
|
||||
selected = true;
|
||||
}
|
||||
|
@ -177,6 +178,46 @@ audio_out_configuration::audio_out_configuration()
|
|||
cellSysutil.notice("cellAudioOut: initial secondary output configuration: channels=%d, encoder=%d, downmixer=%d", secondary_output.channels, secondary_output.encoder, secondary_output.downmixer);
|
||||
}
|
||||
|
||||
std::pair<AudioChannelCnt, AudioChannelCnt> audio_out_configuration::audio_out::get_channel_count_and_downmixer() const
|
||||
{
|
||||
switch (downmixer)
|
||||
{
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_NONE:
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 2: return { AudioChannelCnt::STEREO, AudioChannelCnt::STEREO };
|
||||
case 6: return { AudioChannelCnt::SURROUND_5_1, AudioChannelCnt::SURROUND_5_1 };
|
||||
case 8: return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_7_1 };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count in cellAudioOut config: %d", channels);
|
||||
}
|
||||
}
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_A:
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 2:
|
||||
return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::STEREO };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_A in cellAudioOut config: %d", channels);
|
||||
}
|
||||
}
|
||||
case CELL_AUDIO_OUT_DOWNMIXER_TYPE_B:
|
||||
{
|
||||
switch (channels)
|
||||
{
|
||||
case 6:
|
||||
return { AudioChannelCnt::SURROUND_7_1, AudioChannelCnt::SURROUND_5_1 };
|
||||
default:
|
||||
fmt::throw_exception("Unsupported channel count for CELL_AUDIO_OUT_DOWNMIXER_TYPE_B in cellAudioOut config: %d", channels);
|
||||
}
|
||||
}
|
||||
default:
|
||||
fmt::throw_exception("Unknown downmixer in cellAudioOut config: %d", downmixer);
|
||||
}
|
||||
}
|
||||
|
||||
error_code cellAudioOutGetNumberOfDevice(u32 audioOut);
|
||||
|
||||
error_code cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
|
||||
|
@ -274,38 +315,14 @@ error_code cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr<CellAudio
|
|||
case CELL_AUDIO_OUT_PRIMARY:
|
||||
case CELL_AUDIO_OUT_SECONDARY:
|
||||
{
|
||||
const auto [channels, downmixer] = AudioBackend::get_channel_count_and_downmixer(audioOut);
|
||||
|
||||
audio_out_configuration& cfg = g_fxo->get<audio_out_configuration>();
|
||||
std::lock_guard lock(cfg.mtx);
|
||||
const audio_out_configuration::audio_out& out = cfg.out.at(audioOut);
|
||||
|
||||
const auto it = std::find_if(out.sound_modes.cbegin(), out.sound_modes.cend(), [channels = channels, &out](const CellAudioOutSoundMode& mode)
|
||||
{
|
||||
if (mode.type != out.encoder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out.downmixer == CELL_AUDIO_OUT_DOWNMIXER_TYPE_A)
|
||||
{
|
||||
return mode.channel == CELL_AUDIO_OUT_CHNUM_2;
|
||||
}
|
||||
|
||||
if (out.downmixer == CELL_AUDIO_OUT_DOWNMIXER_TYPE_B)
|
||||
{
|
||||
return mode.channel == CELL_AUDIO_OUT_CHNUM_6;
|
||||
}
|
||||
|
||||
return mode.channel == static_cast<u8>(channels);
|
||||
});
|
||||
|
||||
ensure(it != out.sound_modes.cend());
|
||||
|
||||
_state.state = out.state;
|
||||
_state.encoder = out.encoder;
|
||||
_state.downMixer = out.downmixer;
|
||||
_state.soundMode = *it;
|
||||
_state.soundMode = out.sound_mode;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -352,6 +369,38 @@ error_code cellAudioOutConfigure(u32 audioOut, vm::ptr<CellAudioOutConfiguration
|
|||
out.encoder = config->encoder;
|
||||
out.downmixer = config->downMixer;
|
||||
|
||||
// Try to find the best sound mode for this configuration
|
||||
const auto [channels, downmixer] = out.get_channel_count_and_downmixer();
|
||||
const auto it = std::find_if(out.sound_modes.cbegin(), out.sound_modes.cend(), [channels = channels, &out](const CellAudioOutSoundMode& mode)
|
||||
{
|
||||
if (mode.type != out.encoder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out.downmixer == CELL_AUDIO_OUT_DOWNMIXER_TYPE_A)
|
||||
{
|
||||
return mode.channel == CELL_AUDIO_OUT_CHNUM_2;
|
||||
}
|
||||
|
||||
if (out.downmixer == CELL_AUDIO_OUT_DOWNMIXER_TYPE_B)
|
||||
{
|
||||
return mode.channel == CELL_AUDIO_OUT_CHNUM_6;
|
||||
}
|
||||
|
||||
return mode.channel == static_cast<u8>(channels);
|
||||
});
|
||||
|
||||
if (it != out.sound_modes.cend())
|
||||
{
|
||||
out.sound_mode = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellSysutil.warning("cellAudioOutConfigure: Could not find an ideal sound mode for %d channel output. Keeping old mode: channels=%d, encoder=%d, fs=%d",
|
||||
static_cast<u32>(channels), out.sound_mode.channel, out.sound_mode.type, out.sound_mode.fs);
|
||||
}
|
||||
|
||||
needs_reset = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
// Error codes
|
||||
enum CellAudioOutError : u32
|
||||
{
|
||||
|
@ -194,7 +196,7 @@ struct CellAudioOutDeviceConfiguration
|
|||
|
||||
struct audio_out_configuration
|
||||
{
|
||||
std::mutex mtx;
|
||||
shared_mutex mtx;
|
||||
|
||||
struct audio_out
|
||||
{
|
||||
|
@ -204,6 +206,9 @@ struct audio_out_configuration
|
|||
u32 downmixer = CELL_AUDIO_OUT_DOWNMIXER_NONE;
|
||||
u32 copy_control = CELL_AUDIO_OUT_COPY_CONTROL_COPY_FREE;
|
||||
std::vector<CellAudioOutSoundMode> sound_modes;
|
||||
CellAudioOutSoundMode sound_mode{};
|
||||
|
||||
std::pair<AudioChannelCnt, AudioChannelCnt> get_channel_count_and_downmixer() const;
|
||||
};
|
||||
|
||||
std::array<audio_out, 2> out;
|
||||
|
|
Loading…
Add table
Reference in a new issue