Recording Audio in Silverlight on Windows Phone 7

It’s fairly easy to record PCM audio data directly from the phone’s microphone in Windows Phone 7, but there are a few things to remember.

Firstly, the phone runs Silverlight 3.  Audio recording support only came to Silverlight in version 4, so there is no direct support for it in WP7 Silverlight apps.  The good news is that XNA does support recording audio for games, and we can still make use of the XNA libraries even though we’re in Silverlight.

So start by adding a reference to:

Microsoft.Xna.Framework

Then add a using statement for

using Microsoft.Xna.Framework.Audio; 

Once this is done you can use the Microphone.Default class to begin recording audio, by handling the BufferReady event. The BufferReady event fires when ever the buffer has been filled with audio data.

using System;
using Microsoft.Xna.Framework.Audio;

    public class Recorder
    {
        private Microphone _microphone;
        private byte[] _buffer;
        private TimeSpan _duration;

        public Recorder()
        {
            _microphone = Microphone.Default;
            _microphone.BufferDuration = TimeSpan.FromMilliseconds(300);
            _duration = _microphone.BufferDuration;
            _buffer = new byte[_microphone.GetSampleSizeInBytes(_microphone.BufferDuration)];
            _microphone.BufferReady += new EventHandler<EventArgs>(MicrophoneBufferReady);
            _microphone.Start();
        }

        private void MicrophoneBufferReady(object sender, EventArgs e)
        {
            _microphone.GetData(_buffer);
            //Do something with the data&nbsp;&nbsp;&nbsp;
        }
    }

Since our buffer duration here is 300ms the BufferReady event will fire every 300ms. This can be adjusted as required.  There is still a problem however.  If you run the code above as is you will get this helpful FrameworkDispatcher.Update has not been called exception.

image

This is because unlike Silverlight, the XNA framework is not event driven.  It is built for games and rather than using eventing as Silverlight does, games implement what is called a ‘game loop’, where the game is essentially operates in an infinite while loop.  What does this mean?  It means we need to mimic the game loop in our Silverlight application in order to use some of the XNA framework APIs.  Fortunately this is easy enough, we can simply set up a timer to periodically tell XNA to update, just as it would with each iteration of a game loop.  Here is an XNAAsyncDispatcher class takes care of this for us.

    public class XNAAsyncDispatcher : IApplicationService
    {
        private DispatcherTimer _frameworkDispatcherTimer;
        public XNAAsyncDispatcher(TimeSpan dispatchInterval)
        {
            FrameworkDispatcher.Update();
            this._frameworkDispatcherTimer = new DispatcherTimer();
            this._frameworkDispatcherTimer.Tick += new EventHandler(frameworkDispatcherTimer_Tick);
            this._frameworkDispatcherTimer.Interval = dispatchInterval;
        }
        void IApplicationService.StartService(ApplicationServiceContext context)
        {
            this._frameworkDispatcherTimer.Start();
        }

        void IApplicationService.StopService()
        {
            this._frameworkDispatcherTimer.Stop();
        }

        void frameworkDispatcherTimer_Tick(object sender, EventArgs e)
        {
            FrameworkDispatcher.Update();
        }
    }

This class implements a service which will mimic the game loop for XNA and tell the framework to update itself periodically.  To use this class simply add an instance of it to the phone apps App.ApplicationLifetimeObjects collection in the App constructor as  follows

// Constructor
public App()
{
    // Global handler for uncaught exceptions.
    // Note that exceptions thrown by ApplicationBarItem.Click will not get caught here.
    UnhandledException += Application_UnhandledException;

    // Standard Silverlight initialization
    InitializeComponent();

    // Phone-specific initialization
     InitializePhoneApplication();

    ApplicationLifetimeObjects.Add(new XNAAsyncDispatcher(TimeSpan.FromMilliseconds(50)));
}

You can even test your code using the emulator, as it supports recording through the host PC’s microphone input, although, in Beta1 at least, the results are a bit choppy.

About these ads

14 thoughts on “Recording Audio in Silverlight on Windows Phone 7

  1. Hi,
    how do you read the data? What format is it stored in and is there a way to play it back? If possible can you create a sample of that? Thanks, this was a good article.

    • Hi Ed

      You can read the data by hooking the BufferReady event. That event gets raised as soon as the record buffer is full of recorded audio data. The size of the buffer depends on how large you set the buffer duration. When the BufferReady event is raised call the GetBuffer() method to get the contents of the buffer. The GetBuffer() method will return an array of bytes which represent a section of recorded audio.

      In my example I set the BufferDuration to 300ms, so my BufferReady even will fire roughly every 300ms and will the GetBuffer() method will return exactly 300ms worth of audio data.

      As for what format the data is in? Presumably that is raw PCM wave data. You would need to encode it somehow to generate a WAV or MP3 file, if that is what you are looking for. See this link for an end to end guide on recording audio with Windows Phone 7.

  2. Hi,

    I’m trying to get this code running and I find that the BufferReady event is never called. I’m using the emulator, and I have the sound control panel up and can see the activity as I talk into the microphone…but still no event. do you have any ideas of things to look at?

    (btw, I’ve stepped through the debugger to ensure that I’m creating and adding the event, that the methods are being despatched by the UI, that the FrameworkDispatcher.Update() is called, etc.)

    thanks,

    joe

    • Hi Joe

      I’m not sure whats going on with your code. What I can say is that it is probably nothing to do with the FrameworkDispatcher – if that wasn’t working you would get an exception as soon as you started your app. It probably also isn’t to do with your microphone or audio settings. As soon as you call microphone.Start() the event should start firing (roughly every 300 m/sec if that is your BufferDuration) – regardless of whether actual sound is reaching the app or not. It is not the case that you only receive the event once you actually start talking. The event fires when the buffer is full of audio data. If the mic or windows audio settings are wrong the you’ll still get 300 m/sec of audio data, but it will just be silence.

      I’m afraid there must be something wrong with the code. You could either try posting your code to the AppHub Windows Phone 7 forum where I or someone else can have a look at it. Or CESPage.com have posted a complete tutorial on audio recording. You could just download their tutorial project and use that as a starting place to build out your own project.

  3. Pingback: Resume the User’s music after MediaPlay « WP7 development on a Real Device

  4. Aiden,

    Thanks for the clearly written article…

    Like the other “Ed”, I’ve been trying to implement and can’t seen to get the time buffer ready event to fire. Perhaps these questions may shed light where my problem lies….

    Can you tell me where the code for the XNAAsyncDispatcher class goes? In a seperate class? in the App.xaml.cs in the MainPage of my app?

    My intent is to have three buttons on my main app form

    “Start” – Create Recorder / Start Collecting data to MemoryStream
    “Stop” – Stop Recorder / Save Stream to Isolated Storage as a WAV.
    “Play” filel recorder
    “Playback”

    and not sure if this “timer” should be running at all times or just when Start is running.

    Upon clicking Stop, I’d like to save this recording to the IsolatedStorage as a Wav file or upload to the cloud as a byte stream for dynamic retrieval later.

    • Hi Fast_Eddie

      The XNAAsyncDispatcher is just a class so you can put it where ever you want, but it would make sense to put it in a file called XNAAsyncDispatcher.cs in your project.

      Then you need to add an instance of it to the app’s ApplicationLifetimeObjects by adding the line of code mentioned in the article to the App class’s constructor. This is all you need to do. You don’t need to worry about starting the timer or whether it is running or not – just add it to the ApplicationLifetimeObjects and forget about it.

      Your requirements are very similar to CESPage tutorial on creating an audio app on Windows Phone 7. If I were you I would download their sample code and use it as a starting point for your own app.

  5. After I sent you the message, I did follow tutorial (actually 3rd time around) and now seem to be finally building a byte array. (before it had a length of zero so mic must be working now but not sure what is being recorded) Problem is that I just can’t hear it during the playback routine. Any suggestions? My desktop speakers are able to play music from a desktop app so perhaps it is a volume / mixing issue. Haven’t been able to examine byte stream yet.

    I was thinking of taking a “known good sound file saved as a wav” and sending that byte stream when play is clicked instead of memorystream to see if speakers work. Will that work or do I need to send a “RAW” stream.

    Basically, my app calls for saving a “voice recording” and being able to replay on my Windows Phone OR my desktop app. I’ve got a MVVM view in place which allows me to save / retrieve the byte stream from a service.

    Guess my question is how to go from a RAW stream to a WAV or what sort of conversion is required. I thought WAV format had a header record with content info (e.g. format, length etc…).

    I will continue to work thru problem but any advice would be much appreciated.

    • As I understand it you can create a WAV file from the RAW PCM data by appending the correct header information to the array of bytes you receive from the microphone. You would have to look at the WAV file specification to see what exactly is required.

  6. Pingback: Windows Phone 7 Recorder - Interns Rise2Power

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s