Determining/Controlling your Environment - Sound

Hello there. Today I'll discuss System Contexts area. Do you know what's that? That's your environment - your computer's sound level, your presence, current window context - say is your active window maximized or of normal size, your tasks etc.

Windows as OS is great in terms of APIs it provides. Actually what I do really love in Windows is that you can leverage its capabilities in more user-friendly ways its default Shell, explorer, provides them. Of course there are several issues - say like you can't manage sound volume for each application in Windows Vista using APIs but I believe that in next release they may become public as it is with all new APIs - we need to test them in our OS before releasing them to independent developers.

So let me start.

Determining your Sound Environment

In Windows Vista, the whole Audio Stack was rewritten. Also I do not know the whole story here, it is needed to be kept in mind that new Audio Stack starts with CoreAudioAPI that we will try to leverage:

To start working with Core Audio API in Windows Vista, you will need to get the interop library CoreAudioAPI, then you can code:

 

 public SystemSoundContext GetState()
        {
            // Volume settings
            MMDevice device;
            try
            {
                device = new MMDeviceEnumerator().GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);

                if (device.AudioEndpointVolume.Mute)
                {
                    return new SystemSoundContext(SoundState.Muted);
                }
                else if (!device.AudioEndpointVolume.Mute)
                {
                    return new SystemSoundContext(SoundState.Normal);
                }
            }
            catch
            {
                return new SystemSoundContext(SoundState.NoAudioDeviceIsPresent);
            }
            return new SystemSoundContext(SoundState.Unknown);
        }

Here goes the SystemSoundContext class, that I use to retrieve/set sound properties for Windows. As far as there is no way to manage specific applications sound volume so I can just mute or get sound back to normal.

MMDevice is a class from CoreAudioAPI library, it is a MultiMedia Device represented like a class. You can read more about native MMDevice APIs here in MSDN2: MMDevice API.

All sounds exposed from sound devices are played in different streams/sessions, you can read about Sessions in Session Volume Controls article in MSDN2. Actually they are belonging to different applications like Windows Media Player or Skype. Unfortunately the library I have doesn't provide access to these APIs but this is only a start, right?

So far, we know can get default Audio Endpoint using Core Audio APIs and them set AudioEndpointVolume, and either retrieve Muted is sound or not, or set it.

This sounds really easy, but because I do not know if there is any MMDevice at all, I temporary use Try..Catch block to avoid exceptions here.

Here is enum for SoundStates:

 public enum SoundState
    {
        Muted,
        Normal,
        NoAudioDeviceIsPresent,
        Unknown
    }

So far, here we can now control your's Sound Environment, also our capabilities to manage it are limited right now.

Let's now try to set the definition of SystemSoundContext. In Semantics, the project this blog is all about, Context is defined as a base abstract class, that has its name, set of keywords (Keyword is base for Verb, Action, State classes):

 public class Context : IContext
{
    public List<Keyword> Keywords;

    public Context()
    {
        this.m_contextName = "Context";
        this.m_keywords = new List<Keyword>();
    }
    
    public string ContextName;
 }

Here is a IContext interface that I defined for all contexts. Actually I am not sure wherever I'll use it or not in future. It was originally designed to define methods all Contexts in Semantics should use, but right now I removed methods defined there because the whole vision of these classes was refactored. Anyway I will keep it, and add methods to it in future when needed.

Here I defined two kinds of Contexts - System*Contexts and UserContexts. In this post, I'm discussing only SystemSoundContext as it is pretty easy.

The difference between System*Contexts and UserContexts is that System*Contexts can be predefined and are already known in runtime while UserContexts mostly will be created in runtime.

Here is a graphical representation of SystemSoundContext:

image

There are two main methods that are the requirement of ISystemContext interface implementation - SetState() and GetState().

First aims to change current System*Context state, while second helps to get its current state.

When you call GetState(), you receive SystemSoundContext class instance which is instantiated as follows:

 public SystemSoundContext(SoundState state)
        {
            m_SoundState = state;
            switch (state)
            {
                case SoundState.Muted:
                    base.ContextName = "Muted";
                    base.Keywords.Add(new ObjectState("Muted", "Sound Volume"));
                    break;

                case SoundState.Normal:
                    base.ContextName = "Normal";
                    base.Keywords.Add(new ObjectState("Normal", "Sound Volume"));
                    break;

                case SoundState.NoAudioDeviceIsPresent:
                    base.ContextName = "No Audio Device Is Present";
                    base.Keywords.Add(new ObjectState("No Audio Device", "Audio Device Presence"));
                    base.Keywords.Add(new ObjectState("None", "Sound Volume"));
                    break;

                case SoundState.Unknown:
                    base.ContextName = "Unknown Sound Context";
                    base.Keywords.Add(new ObjectState("Unknown", ("Sound Volume")));
                    base.Keywords.Add(new ObjectState("Umknown", ("Audio Device Presence")));
                    break;
            }
        }

As you can see, I used Keywords to save state of the Context so that in application it was easy to get information about state.

Concluding

So far we know now how to retrieve and update SystemSoundContext. This is just a way to control your Sound Environment.

Example of usage:

  • When you are on the meeting, Semantics can detect that you're at the meeting and will automatically turn all sounds off.

By the way, here is a moment - we need to handle two kinds of information - by analyzing current user's context (Environment/tasks he works on) using OS, and physical context information - here I suppose we will need to get info using sensors. How? That's a great question. :)

Next post?

Okay, I think this would be enough for now, and in the next post I will try to cover SystemWindowContext management - here I mean the way to detect current Active Window, get its title, get its WindowStyle.