Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔬Research how to handle auto device change when device is lost #344

Open
3 tasks
CalvinWilkinson opened this issue Apr 2, 2024 · 0 comments
Open
3 tasks
Labels
🔬research Research collection / investigation

Comments

@CalvinWilkinson
Copy link
Member

Complete The Item Below

  • I have updated the title without removing the 🔬 emoji.

What To Research

Perform some research around how we can handle when an audio device has been disconnected and a new device needs to be picked up.

Checking if a device is connected is an OpenAL extension. The name of the extension is ALC_EXT_disconnect and getting the list of extensions for an audio device done by using the this.alInvoker.GetString(this.device, AlcGetString.Extensions) call.

Not all devices support the same extensions and some support extensions that others do not. This is of course all done at the device level.

Possible Solution 1 (With Extension Support):
The idea here is to first see if the device supports the ALC_EXT_disconnect extension. If it does, then we can use the ALC API to be able to check if the device is or is not connected.

The ALC OpenAL function to do this would be alcGetIntegerv and is documented in the OpenAL guide.

This would require adding a new function API to the ALC class for function interop. The delegate would be called ALCGetInteger and the delegate pointer creation would be delegateFactory.CreateDelegate<ALCGetInteger>(libraryPointer, "alcGetIntegerv").

The function signature would be:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ALCGetInteger(ALDevice device, AlcGetInteger param, int size, ref int data);`

This function could then be used to find out if the device is connected. This would be done like:

public bool IsDeviceConnected(ALDevice device)
{
    var result = this.alc.GetInteger(device, AlcGetInteger.Connected, 1);

    return result > 0;
}

Possible Solution 2 (Without Extension Support):

The only thing we could do in this scenario is get the list of devices in the system at a particular interval and then inspect the list to see what has been removed so we can know if the current device in use was disconnected. One problem with this is that the function returns an array of strings. This would cause GC collections in scenarios where it is not ideal, such as a game engine. Research would have to be done to find a way to greatly reduce or remove the GC collections. We will be limited by the OpenAL API with this.

One possible way is to reuse the class array that holds all of the device names and overwrite the items with the new ones without creating a temporary array, which would cause an allocation.


Possible useful way to watch for device changes

This could be injected into the device manager and used to watch for device changes, and then react appropriately.
This implementation would work only for devices that support the disconnection extension but could be adapted to solution 2 mentioned above.

internal class DeviceWatcher : IDeviceWatcher
{
    private readonly CancellationTokenSource tokenSrc = new ();
    private readonly IOpenALInvoker alInvoker;
    private Task internalTask;
    private bool isDisposed;
    private ALDevice device;

    public DeviceWatcher(IOpenALInvoker alInvoker)
    {
        ArgumentNullException.ThrowIfNull(alInvoker);
        this.alInvoker = alInvoker;

        this.internalTask = new Task(CheckDevice, this.tokenSrc.Token);
    }

    public event Func<ALDevice>? DeviceDisconnected;

    public void StartWatchingDevice(ALDevice device)
    {
        this.device = device;
        this.internalTask.Start();
    }

    public void StopWatchingDevice() => this.tokenSrc.Cancel();

    private void CheckDevice()
    {
        while (!this.tokenSrc.IsCancellationRequested)
        {
            Thread.Sleep(100);

            if (!this.alInvoker.IsDeviceConnected(this.device))
            {
                if (this.DeviceDisconnected is not null)
                {
                    this.device = this.DeviceDisconnected.Invoke();
                }
            }
        }
    }
}

Research Results

No response

Acceptance Criteria

The items to complete to satisfy the Definition of Done.

ToDo Items

The items to complete to satisfy the Definition of Done.

Issue Dependencies

No response

Related Work

No response

Additional Information:

Priority Type Labels

Priority Type Label
Low Priority low priority
Medium Priority medium priority
High Priority high priority

Code of Conduct

  • I agree to follow this project's Code of Conduct.
@CalvinWilkinson CalvinWilkinson added the 🔬research Research collection / investigation label Apr 2, 2024
@github-project-automation github-project-automation bot moved this to ⚪Not Set in KD-Team Apr 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔬research Research collection / investigation
Projects
Status: ⚪Not Set
Development

No branches or pull requests

1 participant