Unable to get a SessionNotification

May 30, 2014 at 9:49 AM
Howdy,

first of all, congrats to this nice library. However, I'm experiencing some trouble here. I'd like to get a notification, if a new stream gets created. This can be done by using the "RegisterSessionNotification" in "IAudioSessionManager2". I'm subscribing to this event, but it's not working. The Event won't get called.
            _devEnum = new MMDeviceEnumerator();
            _device = _devEnum.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
            _audioSessionManager2 = AudioSessionManager2.FromMMDevice(_device);
            _audioSessionNotification = new AudioSessionNotification();
            _audioSessionNotification.SessionCreated += _audioSessionNotification_SessionCreated;

            _audioSessionManager2.RegisterSessionNotification(_audioSessionNotification);
Now, if one reads the documentation of IAudioSessionNotification, you'll realize that your application needs to be initialized as MTA, which I did. But, as far as I know, you are doing some kind of calli-magic after the postbuild. Any ideas?

P.S.: I'm using the latest version, commit dd85da68da63 and build it by myself, so I can do some debugging.
Coordinator
May 30, 2014 at 3:59 PM
Hello Mithrandir,

Thanks for reporting that bug. You are right. It is quite weird but it seems like that you have to invoke RegisterSessionNotification from an MTA-Thread. But there was at least one more problem. I've uploaded a new version which fixes the bug. But you still have to make sure, that are invoking from an MTA thread. I've just tested it and as far as I can see, it is only necessary to call the RegisterSessionNotification-method on an MTA-Thread. If the thread gets destroyed afterwards... you wills till receive notifications. So you could use something like this (since is just one STA thread/process -> all other threads have to be an MTA thread):
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA)
{
    _audioSessionManager2.RegisterSessionNotification(_audioSessionNotification);
}
else
{
    using (ManualResetEvent waitHandle = new ManualResetEvent(false))
    {
        ThreadPool.QueueUserWorkItem(
            (o) =>
            {
                try
                {
                    _audioSessionManager2.RegisterSessionNotification(_audioSessionNotification);
                }
                finally
                {
                    waitHandle.Set();
                }
            });
        waitHandle.WaitOne();
    }
}
Another important point is that you have to enumerate all sessions after calling RegisterSessionNotification.

All in all... I've modified your code to make it working:
private static MMDeviceEnumerator _devEnum;
private static MMDevice _device;
private static AudioSessionManager2 _audioSessionManager2;
private static AudioSessionNotification _audioSessionNotification;

[MTAThread]
private static void Main(string[] args)
{
    _devEnum = new MMDeviceEnumerator();
    _device = _devEnum.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console);
    _audioSessionManager2 = AudioSessionManager2.FromMMDevice(_device);

    _audioSessionNotification = new AudioSessionNotification();
    _audioSessionNotification.SessionCreated += _audioSessionNotification_SessionCreated;

    if (Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA)
    {
        _audioSessionManager2.RegisterSessionNotification(_audioSessionNotification);
    }
    else
    {
        using (ManualResetEvent waitHandle = new ManualResetEvent(false))
        {
            ThreadPool.QueueUserWorkItem(
                (o) =>
                {
                    try
                    {
                        _audioSessionManager2.RegisterSessionNotification(_audioSessionNotification);
                    }
                    finally
                    {
                        waitHandle.Set();
                    }
                });
            waitHandle.WaitOne();
        }
    }

    //enumerate all sessions
    _audioSessionManager2.GetSessionEnumerator().ToArray();

    Console.ReadKey();

    _audioSessionManager2.UnregisterSessionNotification(_audioSessionNotification);
}

private static void _audioSessionNotification_SessionCreated(object sender, SessionCreatedEventArgs e)
{
    Console.WriteLine(e.NewSession.QueryInterface<AudioSessionControl2>().Process.MainWindowTitle);
}
Coordinator
May 30, 2014 at 4:00 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.