How to Build a Windows Phone Application that Accepts Microphone Input

Introduction

To build applications that work with voice and audio inputs, Microsoft has provided programmatic APIs as part of the XNA framework, which is part of Windows Phone platform. This allows developers to build sound recording applications by using the Microphone class.

Microphone Basics

The Microphone class resides in the Microsoft.Xna.Framework.Audio namespace as part of the XNA support offered in the Windows Phone platform (in the Microsoft.Xna.framework.dll assembly).

The Microphone class has the BufferReady event, which occurs when the audio capture buffer is ready to be processed.

One thing to note is that since the Microphone class is part of XNA framework, it is important to use DispatchTimer and FrameworkDispatcher to simulate the Game loop (See http://msdn.microsoft.com/en-us/library/bb203873.aspx for more details) to support successful use of the class.

The Start and Stop methods on the Microphone class are used to begin and end audio capture.

Hands-On

We will build a simple application that will record microphone input and play it back to the user.

To start, create a new Windows Phone project in Visual Studio 2013 titled WPMicrophoneDemo.

 New Project
New Project

Next, add  buttons to MainPage, two for starting and stopping the recording and two for starting and stopping the playback.

Your controls will look like the screenshot below:

Start/Stop Controls
Start/Stop Controls

Next, we will declare the microphone capability in the application manifest file. Open WMAppManifest.xml (by double clicking it) and under the Capabilities section, select ID_CAP_MICROPHONE.

ID_CAP_MICROPHONE
ID_CAP_MICROPHONE

Next, we will declare some namespaces that we will use in our application.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using WPMicrophoneDemo.Resources;
using Microsoft.Xna.Framework.Audio;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using Microsoft.Xna.Framework;

Next, open the code-behind for MainPage.xaml and declare instances of the following classes.

    public partial class MainPage : PhoneApplicationPage
    {
        Microphone microPhone = Microphone.Default;
        byte[] recordingBuffer;
        MemoryStream memoryStream = new MemoryStream();
        SoundEffect soundEffect;
        SoundEffectInstance soundEffectInstance;
        // Constructor
        public MainPage()

RecordingBuffer will be used to storing the audio samples captured from the microphone before they are written into memoryStream.  For playback, we will use instances of SoundEffect and SoundEffectInstance classes.

In the constructor, we will create an instance of DispatchTimer (to establish the Game loop required for the XNA framework). We will also register the event handler for the BufferReady event on the microphone.

        public MainPage()
        {
            InitializeComponent();
            buttonStopRecording.IsEnabled = false;
            buttonStartPlayback.IsEnabled = false;
            buttonStopPlayback.IsEnabled = false;
 
            DispatcherTimer dt = new DispatcherTimer();
            dt.Interval = TimeSpan.FromMilliseconds(50);
            dt.Tick += new EventHandler(dt_Tick);
            dt.Start();
     
            microPhone.BufferReady += microPhone_BufferReady;
            // Sample code to localize the ApplicationBar
            //BuildLocalizedApplicationBar();
        }

Our implementation of dt_Tick event handler is below. In this event handler, we will monitor when the playback is complete and enable the buttons accordingly.

void dt_Tick(object sender, EventArgs e)
        {
            try { FrameworkDispatcher.Update(); }
            catch { }
 
            if (soundEffectInstance != null)
            {
                if (soundEffectInstance.State != SoundState.Playing)
                {
                    buttonStopPlayback.IsEnabled = false;
                    buttonStartRecording.IsEnabled = true;
                    buttonStartPlayback.IsEnabled = true;
                    buttonStopRecording.IsEnabled = false;
 
 
                    
                }
            }
        }

The BufferReady event handler involves writing the buffer contents into a memory stream instance.

void microPhone_BufferReady(object sender, EventArgs e)
        {
            microPhone.GetData(recordingBuffer);
            memoryStream.Write(recordingBuffer, 0, recordingBuffer.Length);
            
        }

The click event handler for the Start Recording button will contain code to start the microphone audio capture.

private void buttonStartRecording_Click(object sender, RoutedEventArgs e)
        {
            microPhone.BufferDuration = TimeSpan.FromMilliseconds(500);
            recordingBuffer = new byte[microPhone.GetSampleSizeInBytes(microPhone.BufferDuration)];
            memoryStream.SetLength(0);
            microPhone.Start();
            buttonStartRecording.IsEnabled = false;
            buttonStartPlayback.IsEnabled = false;
            buttonStopPlayback.IsEnabled = false;
            buttonStopRecording.IsEnabled = true;
        }

We will call the Stop method on the Microphone class when the Stop Recording button is clicked.

private void buttonStopRecording_Click(object sender, RoutedEventArgs e)
        {
            microPhone.Stop();
            buttonStartRecording.IsEnabled = true;
            buttonStartPlayback.IsEnabled = true;
            buttonStopRecording.IsEnabled = false;
            buttonStopPlayback.IsEnabled = false;
 
        }
 

The click event handlers for the Playback buttons are below.

private void buttonStartPlayback_Click(object sender, RoutedEventArgs e)
        {
            if (memoryStream.Length == 0)
                return;
            Thread playThread = new Thread(new ThreadStart(playMethod));
            playThread.Start();
            buttonStartPlayback.IsEnabled = false;
            buttonStopPlayback.IsEnabled = true;
            buttonStartRecording.IsEnabled = false;
            buttonStopRecording.IsEnabled = false;
        }
        
        void playMethod()
        {
            soundEffect = new SoundEffect(memoryStream.ToArray(), microPhone.SampleRate, AudioChannels.Stereo);
            soundEffectInstance = soundEffect.CreateInstance();
            soundEffectInstance.Play();
        }
 
        private void buttonStopPlayback_Click(object sender, RoutedEventArgs e)
        {
            if (soundEffectInstance != null)
            {
                if (soundEffectInstance.State == SoundState.Playing || soundEffectInstance.State == SoundState.Paused)
                    soundEffectInstance.Stop();
            }
            buttonStopPlayback.IsEnabled = false;
            buttonStartRecording.IsEnabled = true;
            buttonStartPlayback.IsEnabled = true;
            buttonStopRecording.IsEnabled = false;
        }

If you want to trim the audio capture, you can remove bytes from the memory stream.

Our application is now ready. You can run the application on your device (since you will not be able to record audio in the emulator).

Summary

In this article, we learned how to build a simple Windows Phone application that accepts microphone input. If you want to download the sample code, you can download it below.

About the Author

Vipul Patel is a Program Manager currently working at Amazon Corporation. He has formerly worked at Microsoft in the Lync team and in the .NET team (in the Base Class libraries and the Debugging and Profiling team). He can be reached at vipul.patel@hotmail.com



Related Articles

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • With the average hard drive now averaging one terabyte in size, the fallout from the explosion of user-created data has become an overwhelming volume of potential evidence that law-enforcement and corporate investigators spend countless hours examining. Join Us and SANS' Rob Lee for our 45-minute webinar, A Triage and Collection Strategy for Time-Sensitive Investigations, will demonstrate how to: Identify the folders and files that often contain key insights Reduce the time spent sifting through content by …

Most Popular Programming Stories

More for Developers

RSS Feeds