Windows 10, UWP, AudioGraph–Recording Microphone to WAV File

Just a snippet of code to share – I hadn’t tried to record from the system’s microphone before with Windows 10/UWP and I wanted to record PCM into a file so I had to spend 20 minutes trying to figure it out.

This sample was incredibly helpful and I stripped it down for my purposes to having a UI with a Start and a Stop button wired to these handlers below and that seemed to work in letting me record mono, 16K PCM, mono file with 16-bits per sample into a file on my desktop.

  using System;
  using System.Collections.Generic;
  using System.Threading.Tasks;
  using Windows.Devices.Enumeration;
  using Windows.Media.Audio;
  using Windows.Media.Capture;
  using Windows.Media.Devices;
  using Windows.Media.MediaProperties;
  using Windows.Media.Render;
  using Windows.Storage;
  using Windows.Storage.Pickers;
  using Windows.UI.Xaml;
  using Windows.UI.Xaml.Controls;

  public sealed partial class MainPage : Page
  {
    public MainPage()
    {
      this.InitializeComponent();
    }

    async void OnStart(object sender, RoutedEventArgs e)
    {
      var file = await this.PickFileAsync();

      if (file != null)
      {
        var result = await AudioGraph.CreateAsync(
               new AudioGraphSettings(AudioRenderCategory.Speech));

        if (result.Status == AudioGraphCreationStatus.Success)
        {
          this.graph = result.Graph;

          var microphone = await DeviceInformation.CreateFromIdAsync(
            MediaDevice.GetDefaultAudioCaptureId(AudioDeviceRole.Default));

          // In my scenario I want 16K sampled, mono, 16-bit output
          var outProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.Low);
          outProfile.Audio = AudioEncodingProperties.CreatePcm(16000, 1, 16);

          var outputResult = await this.graph.CreateFileOutputNodeAsync(file,
            outProfile);

          if (outputResult.Status == AudioFileNodeCreationStatus.Success)
          {
            this.outputNode = outputResult.FileOutputNode;

            var inProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.High);

            var inputResult = await this.graph.CreateDeviceInputNodeAsync(
              MediaCategory.Speech,
              inProfile.Audio,
              microphone);

            if (inputResult.Status == AudioDeviceNodeCreationStatus.Success)
            {
              inputResult.DeviceInputNode.AddOutgoingConnection(
                this.outputNode);

              this.graph.Start();
            }
          }
        }
      }
    }
    async void OnStop(object sender, RoutedEventArgs e)
    {
      if (this.graph != null)
      {
        this.graph?.Stop();

        await this.outputNode.FinalizeAsync();

        // assuming that disposing the graph gets rid of the input/output nodes?
        this.graph?.Dispose();

        this.graph = null;
      }
    }
    async Task<StorageFile> PickFileAsync()
    {
      FileSavePicker picker = new FileSavePicker();
      picker.FileTypeChoices.Add("Wave File (PCM)", new List<string> { ".wav" });
      picker.SuggestedStartLocation = PickerLocationId.Desktop;

      var file = await picker.PickSaveFileAsync();

      return (file);
    }
    AudioGraph graph;
    AudioFileOutputNode outputNode;
  }

it’s clearly quite a rough bit of code – all mistakes are mine and I hadn’t tried out AudioGraph before.

7 thoughts on “Windows 10, UWP, AudioGraph–Recording Microphone to WAV File

  1. Pingback: “Project Oxford”–Speaker Verification from a Windows 10/UWP App – Mike Taulty

  2. Thanks for these – I am enjoying trying out all the new stuff. Your posts are just enough to get started and that helps a lot.

    Just tried this and this statement:

    inputResult.DeviceInputNode.AddOutgoingConnection(this.outputNode);

    seems to be giving it fits. This error:

    $exception {“Exception from HRESULT: 0x88960001”} System.Exception

    Did you run across this? The manifest is set to Microphone and a cursory inspection seems like everything is working fine.

    TIA…

    • Hi,

      I did find that some combinations of input and output seemed to throw fairly esoteric exceptions for me (fortunately, not the one that I actually wanted). Maybe try tweaking a parameter or two?

      Mike.

    • Hi,

      Sorry that this is so much later than when you asked the question. I hit the exact same error with that code today by running it on a different machine and then scratching my head over what was happening.

      I suspect that I was being too specific about the input end of the equation here because I don’t really care where the input comes from – my main concern is around getting a particular format of audio out (PCM, 16Kbps, mono, 16-bit).

      I revised my code to look like this…


      var result = await AudioGraph.CreateAsync(
      new AudioGraphSettings(AudioRenderCategory.Media));

      if (result.Status == AudioGraphCreationStatus.Success)
      {
      this.graph = result.Graph;

      // Low gives us 1 channel, 16-bits per sample, 16K sample rate.
      var outProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.Low);
      outProfile.Audio = AudioEncodingProperties.CreatePcm(16000, 1, 16);

      // I want to write to a file.
      var outputResult = await this.graph.CreateFileOutputNodeAsync(
      this.RecordingFile,
      outProfile);

      if (outputResult.Status == AudioFileNodeCreationStatus.Success)
      {
      this.outputNode = outputResult.FileOutputNode;

      // I'll take input from whatever the default communications
      // device is set to me on windows.
      var inputResult = await this.graph.CreateDeviceInputNodeAsync(
      MediaCategory.Communications);

      if (inputResult.Status == AudioDeviceNodeCreationStatus.Success)
      {
      // Now wire the input to the output
      inputResult.DeviceInputNode.AddOutgoingConnection(
      this.outputNode);

      this.graph.Start();
      }
      }
      }

      I hope that helps a little, it helped me get past that exception.

      Mike

Comments are closed.