Well…, I finally figured out how to use the new Windows.Phone.Media.Capture API to record audio on my Nokia 920 Windows Phone 8 device!

Unlike the XNA-based recording feature which works on Windows Phone 7.x that only retrieves raw data, this new (to WP8) API allows the capture of audio in one of 3 formats:

  • AAC – Advanced Audio Coding
  • AMR – Adaptive Multi-Rate Encoding
  • PCM – Good ‘ol WAV file format

After days of searching and finding no sample code I decided to just try to “think like the developer” and try to make anything work.

The biggest issue, once I figured out that there was no callback features which I could use to create a ‘VU’ meter-like effect (to show the amplitude of the incoming single), was to hunt for how to create an IRandomAccessStream from a MemoryStream object.   The answer is… you don’t! 

The two tricks to making it work were (a) understanding that it ONLY records to files not to memory and (b) you MUST use the new WinRT Windows.Storage APIs to create the file.

Here’s the guts of a simple app that has a “Record” button and a “Stop” button.  I started with the Windows Phone App template (not the databound one) and added two buttons then added the code.

Here’s the XAML:

<!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel"
              Grid.Row="1"
              Margin="12,0,12,0">
            <StackPanel Orientation="Vertical">
                <Button x:Name="Button1"
                        Content="Record to file as AAC"
                        HorizontalAlignment="Center"
                        Margin="0,50,0,0"
                        Click="Button_Click_1" />
                <Button x:Name="Button2"
                        Content="Stop Recording"
                        HorizontalAlignment="Center"
                        Margin="0,50,0,0"
                        Click="Button2_Click"
                        Visibility="Collapsed"/>
            </StackPanel>
        </Grid>

 

And here’s the code-behind:

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 PhoneApp1.Resources;
using Windows.Phone.Media.Capture;
using Windows.Storage.Streams;
using Windows.Storage;
 
namespace PhoneApp1
{
    public partial class MainPage : PhoneApplicationPage
    {
        //
        // file for the recorded audio
        //
        StorageFile outputFile;
 
        //
        // Audio capture device instance
        //
        AudioVideoCaptureDevice dev;
 
        /// <summary>
        /// Handle tap on the "Record" button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            //

// First, we have to get a reference to

// our applications "local" folder

            //
            StorageFolder applicationFolder = ApplicationData.Current.LocalFolder;
            
            //
            // Then we have to see if we can create a folder 
            // named 'data' underneath that
            //
            StorageFolder dataFolder = null;
 
            //
            // Note:  The way to determine if a Folder exists is to 'get' it
            // and catch the FileNotFound exception
            //
            try
            {
                dataFolder = await applicationFolder.GetFolderAsync("data");
            }
            catch
            {
                dataFolder = null;
            }
 
            //
            // If we didn't get it, let's create it
            //
            if (dataFolder == null)
            {
                dataFolder = await applicationFolder.CreateFolderAsync("data");
            }
 
            //
            // Now we create the file
            //
            outputFile = await dataFolder.CreateFileAsync("test.aac", 
                               CreationCollisionOption.ReplaceExisting);
 
            //
            // and then open it as a stream so we can write to it
            //
            var stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite);
            
            //
            // Next, open the capture device for audio only and set the recording format
            //
            dev = await AudioVideoCaptureDevice.OpenForAudioOnlyAsync();
            dev.AudioEncodingFormat = CameraCaptureAudioFormat.Amr;
 
            //
            // Finally, let's start recording and disable our button so the
            // user can't try to start recording before stopping
            //
            dev.StartRecordingToStreamAsync(stream);
            
            Button2.Visibility = System.Windows.Visibility.Visible;
            Button1.IsEnabled = false;
        }
 
        /// <summary>
        /// Handle a tap on the "Stop" button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void Button2_Click(object sender, RoutedEventArgs e)
        {
            //
            // Stop recording and re-enable our record button
            //
            await dev.StopRecordingAsync();
            Button2.Visibility = System.Windows.Visibility.Collapsed;
            Button1.IsEnabled = true;
        }
 
 
        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }
 
    }
}

 

And that’s it!