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

  • Enterprise endpoint backup can satisfy data collection and preservation requirements in a more streamlined and cost-effective manner than traditional e-discovery methods. Enterprise IT teams face increasing challenges as the amount of valuable data living on endpoints continues to grow. Due to the exploding volume, mobility and compliance requirements of enterprise data, the need to collect and preserve that data for the purpose of e-discovery becomes more critical--and more difficult. Traditionally, …

  • Live Event Date: February 25, 2015 @ 2:00 p.m. ET / 11:00 a.m. PT Secure Shell (SSH) keys provide unmitigated access for privileged users and applications. However, managing and securing these critical privileged credentials poses a real challenge for organizations, putting sensitive data at risk. In fact, more than 50% of organizations report experiencing an SSH Key related compromise. Check out this upcoming eSeminar and join Adam Bosnian, EVP of Global Business Development at CyberArk, as he discusses the …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date