Why does Windows.Media.Audio.AudioGraph has inferior resampling quality compared to Windows.Media.Playback.MediaPlayer ?

Serhii Tyshchenko 0 Reputation points
2023-03-29T08:06:52.17+00:00

I'm working on a modulated signal generator that uses audio render as output.

So far I tested two methods of output from my application to hardware:

  • Windows.Media.Playback.MediaPlayer
  • Windows.Media.Audio.AudioGraph

My generated input data encoding is always AudioEncodingProperties.CreatePcm(44100, 1, 8). Byte stream is as follows:

  • repeated sequence of { 0xfb, 0x05, 0x80 } bytes when "carrier present"
  • repeated sequence of { 0x80 } bytes otherwise

To verify output signal I record it from WASAPI loopback device using Audacity.

When the system shared mode default format is 44100 Hz I have bit-perfect output from both MediaPlayer and AudioGraph (here and later: the top chart is a whole frame, the bottom chart is zoomed in part of it):

frame

zoom in

But when the default format is 48000 Hz looks like the system does resampling. And the quality of this resampling differs so much, that modulated signal receiver accepts the signal output from MediaPlayer but not from AudioGraph. Here's how those signals look like (not sure if I have to record that signals when Audacity Project Rate selected 44100 Hz or 48000 Hz, so I present both variants here):

  • MediaPlayer (Audacity Project Rate is 44100 Hz)MediaStreamSignalOutput_44k1Hz_48kHz_44k1Hz_zoom1 MediaStreamSignalOutput_44k1Hz_48kHz_44k1Hz_zoom2
  • MediaPlayer (Audacity Project Rate is 48000 Hz)MediaStreamSignalOutput_44k1Hz_48kHz_48kHz_zoom1 MediaStreamSignalOutput_44k1Hz_48kHz_48kHz_zoom2
  • AudioGraph (Audacity Project Rate is 44100 Hz)AudioGraphSignalOutput_44k1Hz_48kHz_44k1Hz_zoom1 AudioGraphSignalOutput_44k1Hz_48kHz_44k1Hz_zoom2
  • AudioGraph (Audacity Project Rate is 48000 Hz)AudioGraphSignalOutput_44k1Hz_48kHz_48kHz_zoom1 AudioGraphSignalOutput_44k1Hz_48kHz_48kHz_zoom2

Difference is huge enough, so MediaPlayer output signal works for the receiver even when system output set to 48 kHz, while AudioGraph in the same circumstances doesn't.

My primary question is: Why?

And, if it's possible to somehow correct AudioGraph's output, then How?

Here are some important code snippets for context (the code is the same for all the above-recorded signals):

  • MediaPlayer init:
        var encProps = AudioEncodingProperties.CreatePcm(44100, 1, 8);
        var streamDesc = new AudioStreamDescriptor(encProps);
        var streamSource = new MediaStreamSource(streamDesc);
        streamSource.Starting += StreamSource_Starting;
        streamSource.SampleRequested += StreamSource_SampleRequested;
        streamSource.Closed += StreamSource_Closed;
        //streamSource.IsLive = true; // No effect?
        streamSource.BufferTime = TimeSpan.Zero;
        
        // if don't want to customize SMTC (System Media Transport Controls)
        //mediaPlayer.SetMediaSource(streamSource);

        // if want to customize SMTC (System Media Transport Controls)
        var mediaSource = MediaSource.CreateFromMediaStreamSource(streamSource);
        var playbackItem = new MediaPlaybackItem(mediaSource);
        var mediaItemDisplayProperties = playbackItem.GetDisplayProperties();
        mediaItemDisplayProperties.Type = Windows.Media.MediaPlaybackType.Music;
        mediaItemDisplayProperties.MusicProperties.Title = "LG Flatron Mx94D-PZ IR Control";
        mediaItemDisplayProperties.MusicProperties.Artist = "Media Stream Signal Output";
        playbackItem.ApplyDisplayProperties(mediaItemDisplayProperties);
        mediaPlayer.Source = playbackItem;
        
        mediaPlayer.RealTimePlayback = true;
  • AudioGraph init:
        var audioGraphSettings = new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Media);
        audioGraphSettings.EncodingProperties =
            AudioEncodingProperties.CreatePcm(44100, 1, 8);
        var audioGraphCreationResult = await AudioGraph.CreateAsync(audioGraphSettings);
        if (audioGraphCreationResult.Status != AudioGraphCreationStatus.Success)
        {
            throw audioGraphCreationResult.ExtendedError;
        }

        audioGraph = audioGraphCreationResult.Graph;

        var deviceOutputNodeCreationResult = await audioGraph.CreateDeviceOutputNodeAsync();
        if (deviceOutputNodeCreationResult.Status != AudioDeviceNodeCreationStatus.Success)
        {
            throw deviceOutputNodeCreationResult.ExtendedError;
        }

        audioDeviceOutputNode = deviceOutputNodeCreationResult.DeviceOutputNode;

        var encProps = AudioEncodingProperties.CreatePcm(CarrierSampleSet.SampleRate, 1, 8);
        audioFrameInputNode = audioGraph.CreateFrameInputNode(encProps);
        audioFrameInputNode.AddOutgoingConnection(audioDeviceOutputNode);
        audioFrameInputNode.Stop(); // Initialize the Frame Input Node in the stopped state
        audioFrameInputNode.QuantumStarted += AudioFrameInputNode_QuantumStarted;
        audioFrameInputNode.AudioFrameCompleted += AudioFrameInputNode_AudioFrameCompleted;

I tried to influence AudioGraph's output.

In the AudioGraph init I:

  • tried setting encoding properties for the whole AudioGraph object (so all the children nodes have the same Pcm(44100, 1, 8) encoding),
  • tried setting Pcm(44100, 1, 8) encoding for audioFrameInputNode only, so the rest of AudioGraph nodes get encoding with the system default sample rate.

Looks like audioDeviceOutputNode ignores its EncodingProperties.SampleRate and just obeys the system default setting. The results are the same. Well, not just the same... identical!

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,374 questions
Universal Windows Platform (UWP)
{count} votes