Click here to Skip to main content
Click here to Skip to main content

Muting all microphones on Vista/Win7

By , 12 Aug 2012
Rate this:
Please Sign up or sign in to vote.

Introduction   

I recently had to write a application that among other things makes sure all active/enabled audio capture device endpoints (usually microphones) are guaranteed muted while it runs. To accomplish this I wrote two pieces of software: a system service that implements a timer and the console application, presented in this article, that the timer's callback invokes every time a set interval elapses.

Background 

My target platforms for this project were XP, Vista and Win7. In order to do what I wanted I had two options. Either use XP/Legacy Audio APIs (e.g. Mixer API) that should still work, alas not that efficiently, on all three Windows versions but may be phased out in upcoming Win8 and later or use the new and lower level Core Audio APIs introduced with Vista. As XP is not supported by these APIs, the latter approach would require a separate implementation for XP, which in my case was Microsoft's Audio Mixer APIs (<mmsystem.h>, part of <Windows.h>). This article will present the Vista/Win7 version of the console application.

Using the code 

The console app is based on the EndpointVolume Microsoft sample that comes with SDK 7.1 under multimedia\audio. I have modified this sample significantly mainly because it was written as a general purpose console application that received a number of command line options that were irrelevant to my purpose but also because the code only dealt with output endpoints (like Speakers) and not input endpoints which was what I was interested in.

Most of the work is done in the console app's wmain() function which you can see below. Code includes explanatory inline comments.

int wmain(int argc, wchar_t* argv[])
{
    //
    //  A GUI application should use COINIT_APARTMENTTHREADED instead of COINIT_MULTITHREADED.
    //
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hr))
    {
        printf("Unable to initialize COM: %x\n", hr);
        goto Exit;
    }
 
    IMMDeviceEnumerator *deviceEnumerator = NULL;
 
    //We initialize the device enumerator here
    hr = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, 
                           IID_PPV_ARGS(&deviceEnumerator) );
    if (FAILED(hr))
    {
        printf("Unable to instantiate device enumerator: %x\n", hr);
        goto Exit;
    }

    IMMDeviceCollection *deviceCollection = NULL;
    
    //Here we enumerate the audio endpoints of interest (in this case audio capture endpoints)
    //into our device collection. We use "eCapture"
    //for audio capture endpoints, "eRender" for 
    //audio output endpoints and "eAll" for all audio endpoints 
    hr = deviceEnumerator->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, 
                                               &deviceCollection );
    if (FAILED(hr))
    {
        printf("Unable to retrieve device collection: %x\n", hr);
        goto Exit;
    }

    UINT deviceCount;
 
    hr = deviceCollection->GetCount(&deviceCount);
    if (FAILED(hr))
    {
        printf("Unable to get device collection length: %x\n", hr);
        goto Exit;
    }

    IMMDevice *device = NULL;
    
    //
    //This loop goes over each audio endpoint in our device collection,
    //gets and diplays its friendly name and then tries to mute it
    //
    for (UINT i = 0 ; i < deviceCount ; i += 1)
    {
        LPWSTR deviceName;
 
        //Here we use the GetDeviceName() function provided with the sample 
        //(see source code zip)
        deviceName = GetDeviceName(deviceCollection, i); //Get device friendly name

        if (deviceName == NULL) goto Exit;
        
        printf("Device to be muted has index: %d and name: %S\n", i, deviceName);

        //this needs to be done because name is stored in a heap allocated buffer
        free(deviceName);

        device = NULL;

        //Put device ref into device var
        hr = deviceCollection->Item(i, &device);
        if (FAILED(hr))
        {
            printf("Unable to retrieve device %d: %x\n", i, hr);
            goto Exit;
        }

        //This is the Core Audio interface of interest
        IAudioEndpointVolume *endpointVolume = NULL;
 
        //We activate it here
        hr = device->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, 
                               reinterpret_cast<void **>(&endpointVolume) );
        if (FAILED(hr))
        {
            printf("Unable to activate endpoint volume on output device: %x\n", hr);
            goto Exit;
        }

        hr = endpointVolume->SetMute(TRUE, NULL); //Try to mute endpoint here
        if (FAILED(hr))
        {
            printf("Unable to set mute state on endpoint: %x\n", hr);
            goto Exit;
        }
        else
            printf("Endpoint muted successfully!\n");
    }
 
Exit: //Core Audio and COM clean up here
    SafeRelease(&deviceCollection);
    SafeRelease(&deviceEnumerator);
    SafeRelease(&device);
    CoUninitialize();
    return 0;
}

Points of Interest  

Core Audio is a powerful low level API that provides direct access to kernel mode components of the audio subsystem. It is therefore a good choice for an application that wishes to have robust control over audio devices/endpoints.

The Core Audio interface most relevant to controlling volume level and mute status on an audio endpoint (be it a output or input one) at a low level is IAudioEndpointVolume. This interface provides methods like SetMute() and SetMasterVolumeLevel(). SetMute() works great in muting the microphones of a system.

The code above will mute all microphones and any other active/enabled audio capture device on a system. It does so by enumerating all available audio capture endpoints thusly:

hr = deviceEnumerator->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, 
                                               &deviceCollection );

Notice here how we call the EnumAudioEndpoints() function using the eCapture and DEVICE_STATE_ACTIVE constants. The possible values for the former are:

  • eRender
  • eCapture 
  • eAll 

while the possible vaues for the latter are:

  • DEVICE_STATE_ACTIVE
  • DEVICE_STATE_DISABLED
  • DEVICE_STATE_NOTPRESENT
  • DEVICE_STATE_UNPLUGGED 

Running the console app   

Once you build the attached Visual Studio project (Visual Studio 2010 required) you can run the console app by invoking the executable in your build directory. The console app will display the name of each audio capture endpoint it attempts to mute along with the result (success/failure) of the mute operation.

History

This is V.1.1 of the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Alex Fotios
Software Developer Freelancer
Brazil Brazil
I have a keen interest in IT Security, Internet applications, and systems/embedded development. My recent research interests have included secure networks, models of trust, trusted agents, information exchange, and software development methodologies.
 
http//linkedin.com/in/fotios
https://www.elance.com/s/fotios/
Follow on   Twitter

Comments and Discussions

 
QuestionC2220 PinmemberRoger652-Feb-14 5:20 
GeneralMy vote of 5 PinmemberFranc Morales10-Aug-12 23:43 
GeneralMy vote of 5. PinmemberHugo B. Slivinskis10-Aug-12 13:40 
GeneralRe: My vote of 5. PinmemberAlex Fotios10-Aug-12 13:58 
GeneralMy vote of 5 PinmemberVolynsky Alex9-Aug-12 5:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140415.2 | Last Updated 12 Aug 2012
Article Copyright 2012 by Alex Fotios
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid