service/audren_u: Handle audio USB output revision queries in ListAudioDeviceName()

Audio devices use the supplied revision information in order to
determine if USB audio output is able to be supported. In this case, we
can only really handle using this revision information in
ListAudioDeviceName(), where it checks if USB audio output is supported
before supplying it as a device name.

A few other scenarios exist where the revision info is checked, such as:

- Early exiting from SetAudioDeviceOutputVolume if USB audio is
  attempted to be set when that device is unsupported.

- Early exiting and returning 0.0f in GetAudioDeviceOutputVolume when
  USB output volume is queried and it's an unsupported device.

- Falling back to AHUB headphones in GetActiveAudioDeviceName when the
  device type is USB output, but is unsupported based off the revision
  info.

In order for these changes to also be implemented, a few other changes
to the interface need to be made.

Given we now properly handle everything about ListAudioDeviceName(), we
no longer need to describe it as a stubbed function.
This commit is contained in:
Lioncash 2019-07-19 03:56:21 -04:00
parent b9ebab71be
commit 16730c4c43
2 changed files with 46 additions and 17 deletions

View File

@ -160,7 +160,8 @@ private:
class IAudioDevice final : public ServiceFramework<IAudioDevice> { class IAudioDevice final : public ServiceFramework<IAudioDevice> {
public: public:
explicit IAudioDevice(Core::System& system) : ServiceFramework("IAudioDevice") { explicit IAudioDevice(Core::System& system, u32_le revision_num)
: ServiceFramework("IAudioDevice"), revision{revision_num} {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
{1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
@ -196,25 +197,40 @@ private:
"AudioTvOutput", "AudioTvOutput",
"AudioUsbDeviceOutput", "AudioUsbDeviceOutput",
}}; }};
enum class DeviceType {
AHUBHeadphones,
AHUBSpeakers,
HDA,
USBOutput,
};
void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called"); LOG_DEBUG(Service_Audio, "called");
const std::size_t num_names_requested = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName); const bool usb_output_supported =
const std::size_t num_to_copy = std::min(num_names_requested, audio_device_names.size()); IsFeatureSupported(AudioFeatures::AudioUSBDeviceOutput, revision);
std::vector<AudioDeviceName> name_buffer(num_to_copy); const std::size_t count = ctx.GetWriteBufferSize() / sizeof(AudioDeviceName);
std::vector<AudioDeviceName> name_buffer;
name_buffer.reserve(audio_device_names.size());
for (std::size_t i = 0; i < count && i < audio_device_names.size(); i++) {
const auto type = static_cast<DeviceType>(i);
if (!usb_output_supported && type == DeviceType::USBOutput) {
continue;
}
for (std::size_t i = 0; i < num_to_copy; i++) {
const auto& device_name = audio_device_names[i]; const auto& device_name = audio_device_names[i];
auto& entry = name_buffer.emplace_back();
device_name.copy(name_buffer[i].data(), device_name.size()); device_name.copy(entry.data(), device_name.size());
} }
ctx.WriteBuffer(name_buffer); ctx.WriteBuffer(name_buffer);
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(num_to_copy)); rb.Push(static_cast<u32>(name_buffer.size()));
} }
void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) { void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
@ -271,6 +287,7 @@ private:
rb.PushCopyObjects(audio_output_device_switch_event.readable); rb.PushCopyObjects(audio_output_device_switch_event.readable);
} }
u32_le revision = 0;
Kernel::EventPair buffer_event; Kernel::EventPair buffer_event;
Kernel::EventPair audio_output_device_switch_event; Kernel::EventPair audio_output_device_switch_event;
@ -597,12 +614,16 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
} }
void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) { void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called"); IPC::RequestParser rp{ctx};
const u64 aruid = rp.Pop<u64>();
LOG_DEBUG(Service_Audio, "called. aruid={:016X}", aruid);
// Revisionless variant of GetAudioDeviceServiceWithRevisionInfo that
// always assumes the initial release revision (REV1).
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioDevice>(system); rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
} }
void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
@ -612,14 +633,19 @@ void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
} }
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called"); struct Parameters {
u32 revision;
u64 aruid;
};
IPC::RequestParser rp{ctx};
const auto [revision, aruid] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_Audio, "called. revision={:08X}, aruid={:016X}", revision, aruid);
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
// TODO(ogniK): Figure out what is different based on the current revision
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioDevice>(system); rb.PushIpcInterface<IAudioDevice>(system, revision);
} }
void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
@ -636,6 +662,8 @@ bool IsFeatureSupported(AudioFeatures feature, u32_le revision) {
const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0'); const u32_be version_num = revision - Common::MakeMagic('R', 'E', 'V', '0');
switch (feature) { switch (feature) {
case AudioFeatures::AudioUSBDeviceOutput:
return version_num >= 4U;
case AudioFeatures::Splitter: case AudioFeatures::Splitter:
return version_num >= 2U; return version_num >= 2U;
case AudioFeatures::PerformanceMetricsVersion2: case AudioFeatures::PerformanceMetricsVersion2:

View File

@ -36,6 +36,7 @@ private:
// Describes a particular audio feature that may be supported in a particular revision. // Describes a particular audio feature that may be supported in a particular revision.
enum class AudioFeatures : u32 { enum class AudioFeatures : u32 {
AudioUSBDeviceOutput,
Splitter, Splitter,
PerformanceMetricsVersion2, PerformanceMetricsVersion2,
VariadicCommandBuffer, VariadicCommandBuffer,