Reading the microphone’s audio stream in WinRT
I wanted to use the microphone on a Surface tablet to measure the audio level in the room. The technique I used was to implement my own stream, and then have the Microphone write to it.
Set up the MediaCapture class as usual:
var media = new MediaCapture(); var captureInitSettings = new MediaCaptureInitializationSettings(); captureInitSettings.StreamingCaptureMode = StreamingCaptureMode.Audio; await media.InitializeAsync(captureInitSettings); media.Failed += (_, ex) => new MessageDialog(ex.Message).ShowAsync(); var stream = new AudioAmplitudeStream(); // custom stream implementation media.StartRecordToStreamAsync(MediaEncodingProfile.CreateWav(AudioEncodingQuality.Low), stream); stream.AmplitudeReading += AmplitudeReading; // get an amplitude event
But you’ll notice I’m passing in an ‘AudioAmplitudeStream’. This is my custom stream implementation which just takes the average of the amplitude reported by the microphone. Here’s the code:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using Windows.Storage.Streams; namespace IoT.WinRT { class AudioAmplitudeStream : IRandomAccessStream { public bool CanRead { get { return false; } } public bool CanWrite { get { return true; } } public IRandomAccessStream CloneStream() { throw new NotImplementedException(); } public IInputStream GetInputStreamAt(ulong position) { throw new NotImplementedException(); } public IOutputStream GetOutputStreamAt(ulong position) { throw new NotImplementedException(); } public ulong Position { get { return 0; } } public void Seek(ulong position) { } public ulong Size { get { return 0; } set { throw new NotImplementedException(); } } public void Dispose() { } public Windows.Foundation.IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) { throw new NotImplementedException(); } public Windows.Foundation.IAsyncOperation FlushAsync() { return AsyncInfo.Run(_ => Task.Run(() => true)); } public Windows.Foundation.IAsyncOperationWithProgress<uint, uint> WriteAsync(IBuffer buffer) { return AsyncInfo.Run<uint, uint>((token, progress) => { return Task.Run(() => { using (var memoryStream = new MemoryStream()) using (var outputStream = memoryStream.AsOutputStream()) { outputStream.WriteAsync(buffer).AsTask().Wait(); var byteArray = memoryStream.ToArray(); var amplitude = Decode(byteArray).Select(Math.Abs).Average(x => x); if (AmplitudeReading != null) this.AmplitudeReading(this, amplitude); progress.Report((uint)memoryStream.Length); return (uint)memoryStream.Length; } }); }); } private IEnumerable Decode(byte[] byteArray) { for (var i = 0; i < byteArray.Length - 1; i += 2) { yield return (BitConverter.ToInt16(byteArray, i)); } } public delegate void AmplitudeReadingEventHandler(object sender, double reading); public event AmplitudeReadingEventHandler AmplitudeReading; } }
The stream is only partially implemented, not all the calls are required.
You can then subscribe to the event, and show the background noise level in your app!
void AmplitudeReading(object sender, double reading) { Debug.WriteLine("Noise level: {0:0} dB", ToDb(reading)); } static double ToDb(double value) { return 20 * Math.Log10(Math.Sqrt(value * 2)); }
Here is a sample application: https://github.com/richorama/WinRTdB
Have fun!
dineshramitc 5:19 pm on June 13, 2014 Permalink | Log in to Reply
Reblogged this on Dinesh Ram Kali..
abdallahshakhatreh 2:36 pm on April 14, 2015 Permalink | Log in to Reply
Great article, thanks Richard !
I have a few questions about your code :
1) What exactly the microphone measure, is it frequency or voltage ?
2) Why you converted the recorded audio to wav file ?
3) Can you please explain the Decode function for me ?
Richard 8:36 am on April 15, 2015 Permalink | Log in to Reply
Hi,
The microphone measures the vibrations in the air! I do some maths to get the amplitude of the vibrations.
I’m not recording anything as a wav file, I’m just reading the microphone readings as they come in.
Th decode function converts the microphone readings into a list of numbers. Although I notice that wordpress has slightly corrupted the code. Best to check the source in github.
Richard.
abdallahshakhatreh 1:20 pm on April 19, 2015 Permalink | Log in to Reply
Thanks Richard .
hopey 6:46 am on April 25, 2016 Permalink | Log in to Reply
Thanks for this code, just what I needed for my IoT project to send server room noise level to cloud 🙂