mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2025-03-13 16:08:59 +01:00
* Migrate audren to new IPC * Migrate audout * Migrate audin * Migrate hwopus * Bye bye old audio service * Switch volume control to IHardwareDeviceDriver * Somewhat unrelated changes * Remove Concentus reference from HLE * Implement OpenAudioRendererForManualExecution * Remove SetVolume/GetVolume methods that are not necessary * Remove SetVolume/GetVolume methods that are not necessary (2) * Fix incorrect volume update * PR feedback * PR feedback * Stub audrec * Init outParameter * Make FinalOutputRecorderParameter/Internal readonly * Make FinalOutputRecorder IDisposable * Fix HardwareOpusDecoderManager parameter buffers * Opus work buffer size and error handling improvements * Add AudioInProtocolName enum * Fix potential divisions by zero
252 lines
8 KiB
C#
252 lines
8 KiB
C#
using Ryujinx.Audio.Renderer.Device;
|
|
using Ryujinx.Audio.Renderer.Server;
|
|
using Ryujinx.Horizon.Common;
|
|
using Ryujinx.Horizon.Sdk.Applet;
|
|
using Ryujinx.Horizon.Sdk.OsTypes;
|
|
using Ryujinx.Horizon.Sdk.Sf;
|
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
|
using System;
|
|
|
|
namespace Ryujinx.Horizon.Sdk.Audio.Detail
|
|
{
|
|
partial class AudioDevice : IAudioDevice, IDisposable
|
|
{
|
|
private readonly VirtualDeviceSessionRegistry _registry;
|
|
private readonly VirtualDeviceSession[] _sessions;
|
|
private readonly bool _isUsbDeviceSupported;
|
|
|
|
private SystemEventType _audioEvent;
|
|
private SystemEventType _audioInputEvent;
|
|
private SystemEventType _audioOutputEvent;
|
|
|
|
public AudioDevice(VirtualDeviceSessionRegistry registry, AppletResourceUserId appletResourceId, uint revision)
|
|
{
|
|
_registry = registry;
|
|
|
|
BehaviourContext behaviourContext = new();
|
|
behaviourContext.SetUserRevision((int)revision);
|
|
|
|
_isUsbDeviceSupported = behaviourContext.IsAudioUsbDeviceOutputSupported();
|
|
_sessions = registry.GetSessionByAppletResourceId(appletResourceId.Id);
|
|
|
|
Os.CreateSystemEvent(out _audioEvent, EventClearMode.AutoClear, interProcess: true);
|
|
Os.CreateSystemEvent(out _audioInputEvent, EventClearMode.AutoClear, interProcess: true);
|
|
Os.CreateSystemEvent(out _audioOutputEvent, EventClearMode.AutoClear, interProcess: true);
|
|
}
|
|
|
|
private bool TryGetDeviceByName(out VirtualDeviceSession result, string name, bool ignoreRevLimitation = false)
|
|
{
|
|
result = null;
|
|
|
|
foreach (VirtualDeviceSession session in _sessions)
|
|
{
|
|
if (session.Device.Name.Equals(name))
|
|
{
|
|
if (!ignoreRevLimitation && !_isUsbDeviceSupported && session.Device.IsUsbDevice())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
result = session;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
[CmifCommand(0)]
|
|
public Result ListAudioDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<DeviceName> names, out int nameCount)
|
|
{
|
|
int count = 0;
|
|
|
|
foreach (VirtualDeviceSession session in _sessions)
|
|
{
|
|
if (!_isUsbDeviceSupported && session.Device.IsUsbDevice())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (count >= names.Length)
|
|
{
|
|
break;
|
|
}
|
|
|
|
names[count] = new DeviceName(session.Device.Name);
|
|
|
|
count++;
|
|
}
|
|
|
|
nameCount = count;
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(1)]
|
|
public Result SetAudioDeviceOutputVolume([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<DeviceName> name, float volume)
|
|
{
|
|
if (name.Length > 0 && TryGetDeviceByName(out VirtualDeviceSession result, name[0].ToString(), ignoreRevLimitation: true))
|
|
{
|
|
if (!_isUsbDeviceSupported && result.Device.IsUsbDevice())
|
|
{
|
|
result = _sessions[0];
|
|
}
|
|
|
|
result.Volume = volume;
|
|
}
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(2)]
|
|
public Result GetAudioDeviceOutputVolume([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan<DeviceName> name, out float volume)
|
|
{
|
|
if (name.Length > 0 && TryGetDeviceByName(out VirtualDeviceSession result, name[0].ToString()))
|
|
{
|
|
volume = result.Volume;
|
|
}
|
|
else
|
|
{
|
|
volume = 0f;
|
|
}
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(3)]
|
|
public Result GetActiveAudioDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<DeviceName> name)
|
|
{
|
|
VirtualDevice device = _registry.ActiveDevice;
|
|
|
|
if (!_isUsbDeviceSupported && device.IsUsbDevice())
|
|
{
|
|
device = _registry.DefaultDevice;
|
|
}
|
|
|
|
if (name.Length > 0)
|
|
{
|
|
name[0] = new DeviceName(device.Name);
|
|
}
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(4)]
|
|
public Result QueryAudioDeviceSystemEvent([CopyHandle] out int eventHandle)
|
|
{
|
|
eventHandle = Os.GetReadableHandleOfSystemEvent(ref _audioEvent);
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(5)]
|
|
public Result GetActiveChannelCount(out int channelCount)
|
|
{
|
|
VirtualDevice device = _registry.ActiveDevice;
|
|
|
|
if (!_isUsbDeviceSupported && device.IsUsbDevice())
|
|
{
|
|
device = _registry.DefaultDevice;
|
|
}
|
|
|
|
channelCount = (int)device.ChannelCount;
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(6)] // 3.0.0+
|
|
public Result ListAudioDeviceNameAuto([Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span<DeviceName> names, out int nameCount)
|
|
{
|
|
return ListAudioDeviceName(names, out nameCount);
|
|
}
|
|
|
|
[CmifCommand(7)] // 3.0.0+
|
|
public Result SetAudioDeviceOutputVolumeAuto([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan<DeviceName> name, float volume)
|
|
{
|
|
return SetAudioDeviceOutputVolume(name, volume);
|
|
}
|
|
|
|
[CmifCommand(8)] // 3.0.0+
|
|
public Result GetAudioDeviceOutputVolumeAuto([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ReadOnlySpan<DeviceName> name, out float volume)
|
|
{
|
|
return GetAudioDeviceOutputVolume(name, out volume);
|
|
}
|
|
|
|
[CmifCommand(10)] // 3.0.0+
|
|
public Result GetActiveAudioDeviceNameAuto([Buffer(HipcBufferFlags.Out | HipcBufferFlags.AutoSelect)] Span<DeviceName> name)
|
|
{
|
|
return GetActiveAudioDeviceName(name);
|
|
}
|
|
|
|
[CmifCommand(11)] // 3.0.0+
|
|
public Result QueryAudioDeviceInputEvent([CopyHandle] out int eventHandle)
|
|
{
|
|
eventHandle = Os.GetReadableHandleOfSystemEvent(ref _audioInputEvent);
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(12)] // 3.0.0+
|
|
public Result QueryAudioDeviceOutputEvent([CopyHandle] out int eventHandle)
|
|
{
|
|
eventHandle = Os.GetReadableHandleOfSystemEvent(ref _audioOutputEvent);
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(13)] // 13.0.0+
|
|
public Result GetActiveAudioOutputDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<DeviceName> name)
|
|
{
|
|
if (name.Length > 0)
|
|
{
|
|
name[0] = new DeviceName(_registry.ActiveDevice.GetOutputDeviceName());
|
|
}
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
[CmifCommand(14)] // 13.0.0+
|
|
public Result ListAudioOutputDeviceName([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<DeviceName> names, out int nameCount)
|
|
{
|
|
int count = 0;
|
|
|
|
foreach (VirtualDeviceSession session in _sessions)
|
|
{
|
|
if (!_isUsbDeviceSupported && session.Device.IsUsbDevice())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (count >= names.Length)
|
|
{
|
|
break;
|
|
}
|
|
|
|
names[count] = new DeviceName(session.Device.GetOutputDeviceName());
|
|
|
|
count++;
|
|
}
|
|
|
|
nameCount = count;
|
|
|
|
return Result.Success;
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
Os.DestroySystemEvent(ref _audioEvent);
|
|
Os.DestroySystemEvent(ref _audioInputEvent);
|
|
Os.DestroySystemEvent(ref _audioOutputEvent);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|