kcat / openal-soft

OpenAL Soft is a software implementation of the OpenAL 3D audio API.
Other
2.22k stars 536 forks source link

[Question] Get current ports of sink and source devices #1017

Open Switch0621 opened 4 months ago

Switch0621 commented 4 months ago

Greetings! Please advice me, how can i get actual info about current sink and source ports?

I want to my app is notifying user about connecting/disconnecting microphone and headphones. So, two state - no active sink/source port : active port is port name

P.S.: likely error, after set log callback, i open device (with empty name) and create context for this device and all is freezed.

kcat commented 4 months ago

Calling alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) (or alcGetString(NULL, ALC_DEVICE_SPECIFIER) if ALC_ENUMERATE_ALL_EXT isn't supported) will return a nul-separated list of available device names. Like this:

const char *names = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
while(names && *names)
{
    printf("%s\n", names);
    names += strlen(names)+1;
}

It shouldn't freeze creating a context. Even if there's no devices, opening the default devices (using an empty name) should fail if there's nothing to open. Or if there is a device but it's unusable, opening the device or creating the context should fail. Something's wrong if it freezes. Can you provide a backtrace from a debug build?

Switch0621 commented 4 months ago

I think to compile a little CSharp project is more simple way. There is a code of simple console application in dotnet8.0 on Linux:

` using System.Runtime.InteropServices;

namespace ConsoleApp1;

class Program { private const string OpenAlLinux = "libopenal.so.1"; private static IntPtr _openalLinux = IntPtr.Zero;

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void LogDelegate(IntPtr user, char level, string message, int length);

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate void LogCallbackSetter(LogDelegate callback, IntPtr user);

[DllImport(OpenAlLinux, EntryPoint = "alGetProcAddress", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress([In] string fname);

[DllImport(OpenAlLinux, EntryPoint = "alcOpenDevice", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern IntPtr OpenDevice([In] string devicename);

[DllImport(OpenAlLinux, EntryPoint = "alcCloseDevice", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern bool CloseDevice([In] IntPtr device);

[DllImport(OpenAlLinux, EntryPoint = "alcCreateContext", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr CreateContext([In] IntPtr device, [In] int[] attributeList);

private static IntPtr CreateContext(IntPtr device, OpenAlContextAttributes attributes) => CreateContext(device, attributes.CreateAttributeArray());

[DllImport(OpenAlLinux, EntryPoint = "alcDestroyContext", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern void DestroyContext(IntPtr context);

static void Main(string[] args)
{
    // load openAl library
    _openalLinux = NativeLibrary.Load(OpenAlLinux);
    if (_openalLinux == IntPtr.Zero)
        throw new Exception("Can't load library libopenal.so");

    // set log callback
    var sptr = GetProcAddress("alsoft_set_log_callback");
    var logSetter = Marshal.GetDelegateForFunctionPointer<LogCallbackSetter>(sptr);
    logSetter.Invoke(AlLogCallback, IntPtr.Zero);

    // try to create context

    var contextAttributes = new OpenAlContextAttributes();
    var defaultPlayingDevice = OpenDevice(string.Empty);
    var defaultPlayingDeviceContext = IntPtr.Zero;
    if (defaultPlayingDevice != IntPtr.Zero)
        defaultPlayingDeviceContext = CreateContext(defaultPlayingDevice, contextAttributes);

    // wait
    Console.ReadKey();

    // dispose
    if (defaultPlayingDeviceContext != IntPtr.Zero)
        DestroyContext(defaultPlayingDeviceContext);
    if (defaultPlayingDevice != IntPtr.Zero)
        CloseDevice(defaultPlayingDevice);
}

private static void AlLogCallback(IntPtr user, char level, string message, int length) { }

} `

The program is shutdown on context creation. If i comment 'set log callback' code block - it's working fine.