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: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds