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: August 13, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT If you are developing applications, you'll want to join us to learn how applications are changing as a result of gesture recognition. This technology will change how you and your users interact - not simply with your devices, but with the world around you. Your devices will be able to see and hear what your users are doing. Are your applications ready for this? Join us to learn about Intel® RealSense™ Technology, including never been …

  • In this on-demand webcast, Oracle ACE and Toad Product Architect Bert Scalzo discusses 10 powerful and hidden features in Toad® that help increase your productivity and DB performance. Watch this webcast today.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds