Wiedergeben von Audio- und Videoinhalten mit „MediaPlayer“

In diesem Artikel erfahren Sie, wie Sie Medien in Ihrer universellen Windows-App mit der MediaPlayer-Klasse wiedergeben. Mit Windows 10, Version 1607, wurden erhebliche Verbesserungen an den Medienwiedergabe-APIs vorgenommen, einschließlich eines vereinfachten Einzelprozessentwurfs für Hintergrundaudio, der automatischen Integration mit den System Media Transport Controls (SMTC), der Möglichkeit, mehrere Medienplayer zu synchronisieren, die Möglichkeit, Videoframes auf einer Windows.UI.Composition-Oberfläche zu rendern, und eine einfache Schnittstelle zum Erstellen und Planen von Medienunterbrechungen in Ihren Inhalten. Um diese Verbesserungen optimal zu nutzen, sollten Sie für die Medienwiedergabe anstelle von MediaElement die MediaPlayer-Klasse verwenden. Das einfache XAML-Steuerelement MediaPlayerElement wurde eingeführt, damit Sie Medieninhalte auf einer XAML-Seite rendern können. Viele der von MediaElement bereitgestellten Wiedergabesteuerelemente und Status-APIs sind jetzt über das neue MediaPlaybackSession-Objekt verfügbar. MediaElement gewährleistet weiterhin die Abwärtskompatibilität. Dieser Klasse werden jedoch keine weiteren Features hinzugefügt.

Dieser Artikel erläutert die Features von MediaPlayer, die von einer typischen App zur Medienwiedergabe verwendet werden. Beachten Sie, dass MediaPlayer die MediaSource-Klasse als Container für alle Medienelemente verwendet. Diese Klasse ermöglicht Ihnen das Laden und Wiedergeben von Medien aus verschiedenen Quellen – z. B. aus lokalen Dateien, Speicherdatenströmen und Netzwerkquellen – über die gleiche Schnittstelle. Verschiedene Klassen auf höherer Ebene arbeiten ebenfalls mit MediaSource, z. B. MediaPlaybackItem und MediaPlaybackList. Sie stellen erweiterte Features bereit wie Wiedergabelisten und die Möglichkeit, Medienquellen mit mehreren Audio-, Video- und Metadatentiteln zu verwalten, Weitere Informationen zu MediaSource und verwandten APIs finden Sie unter Medienelemente, Wiedergabelisten und Titel.

Hinweis

Windows 10 N- und Windows 10 KN-Editionen enthalten nicht die Medienfeatures, die für die Verwendung von MediaPlayer für die Wiedergabe erforderlich sind. Diese Features können manuell installiert werden. Weitere Informationen finden Sie unter Media Feature Pack für Windows 10 N- und Windows 10 KN-Editionen.

Wiedergeben einer Mediendatei mit „MediaPlayer“

Die grundlegende Medienwiedergabe mit MediaPlayer ist sehr einfach zu implementieren. Erstellen Sie zunächst eine neue Instanz der MediaPlayer-Klasse. In Ihrer App können mehrere MediaPlayer-Instanzen gleichzeitig aktiv sein. Legen Sie dann für die Source-Eigenschaft des Players ein Objekt fest, welches die IMediaPlaybackSource implementiert, z. B. eine MediaSource, ein MediaPlaybackItem oder eine MediaPlaybackList. In diesem Beispiel wird ein MediaSource-Objekt aus einer Datei im lokalen Speicher der App erstellt. Anschließend wird aus der Quelle ein MediaPlaybackItem-Objekt erstellt und der Source-Eigenschaft des Players zugewiesen.

Anders als MediaElement startet MediaPlayer nicht standardmäßig automatisch mit der Wiedergabe. Sie können die Wiedergabe starten, indem Sie Play aufrufen, für die AutoPlay -Eigenschaft „true“ festlegen oder warten, bis der Benutzer die Wiedergabe mit den integrierten Media-Steuerelementen startet.

mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer.Play();

Wenn Ihre App die Verwendung eines MediaPlayers beendet hat, sollten Sie die MethodeClose aufrufen (Dispose-Methode in C#), um die vom Player verwendeten Ressourcen zu bereinigen.

mediaPlayer.Dispose();

Rendern von Videos in XAML mit MediaPlayerElement

Sie können Medien in einem MediaPlayer wiedergeben, ohne sie in XAML anzuzeigen. Viele Medienwiedergabe-Apps versuchen jedoch, die Medien auf einer XAML-Seite zu rendern. Verwenden Sie hierfür das einfache MediaPlayerElement-Steuerelement. Wie mit MediaElement können Sie mit MediaPlayerElement festlegen, ob die integrierten Transport-Steuerelemente angezeigt werden sollen.

<MediaPlayerElement x:Name="_mediaPlayerElement" AreTransportControlsEnabled="False" HorizontalAlignment="Stretch"  Grid.Row="0"/>

Sie können die MediaPlayer -Instanz festlegen, an die das Element gebunden ist, indem Sie SetMediaPlayer aufrufen.

_mediaPlayerElement.SetMediaPlayer(mediaPlayer);

Sie können für das MediaPlayerElement auch die Wiedergabequelle festlegen. Das Element erstellt dann automatisch eine neue MediaPlayer-Instanz, auf die Sie mithilfe der MediaPlayer-Eigenschaft zugreifen können.

_mediaPlayerElement.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer = _mediaPlayerElement.MediaPlayer;
mediaPlayer.Play();

Hinweis

Wenn Sie MediaPlaybackCommandManager für MediaPlayer deaktivieren, indem Sie IsEnabled auf „false“ festlegen, wird die von MediaPlayerElement bereitgestellte Verknüpfung zwischen MediaPlayer und TransportControls getrennt, sodass die integrierten Transportsteuerelemente nicht mehr automatisch die Wiedergabe des Players steuern. Stattdessen müssen Sie Ihre eigenen Steuerelemente zum Steuern des MediaPlayers implementieren.

Allgemeine MediaPlayer-Aufgaben

In diesem Abschnitt erfahren Sie, wie Sie verschiedene Features des MediaPlayers verwenden.

Festlegen der AudioCategory-Eigenschaft

Legen Sie für die Audiocategory-Eigenschaft eines MediaPlayers einen der Werte der MediaPlayerAudioCategory-Enumeration fest, um dem System mitzuteilen, welche Art von Medien Sie wiedergeben. Spiele sollten als Kategorie ihrer Musikdatenströme GameMedia angeben, sodass die Musik des Spiels automatisch auf stumm geschaltet wird, wenn eine andere Anwendung im Hintergrund Musik wiedergibt. Musik- oder Video-Apps sollten als Kategorien für ihre Datenströme Media oder Movie angeben, sodass ihnen gegenüber GameMedia-Datenströmen Priorität eingeräumt wird.

mediaPlayer.AudioCategory = MediaPlayerAudioCategory.Media;

Ausgabe an einen bestimmten Audio-Endpunkt

Die Audioausgabe eines MediaPlayers wird standardmäßig zum Standard-Audio-Endpunkt des Systems geleitet. Sie können jedoch auch einen bestimmten Audio-Endpunkt als Ausgabe für den MediaPlayer festlegen. Im folgenden Beispiel gibt MediaDevice.GetAudioRenderSelector eine Zeichenfolge zur eindeutigen Identifizierung der Audiorendering-Kategorie von Geräten zurück. Als Nächstes wird die DeviceInformation-Methode FindAllAsync aufgerufen, um eine Liste aller verfügbaren Geräte des ausgewählten Typs zu erstellen. Sie können programmgesteuert festlegen, welches Gerät Sie verwenden möchten, oder die zurückgegebenen Geräte zu einer ComboBox hinzufügen, damit der Benutzer ein Gerät auswählen kann.

string audioSelector = MediaDevice.GetAudioRenderSelector();
var outputDevices = await DeviceInformation.FindAllAsync(audioSelector);
foreach (var device in outputDevices)
{
    var deviceItem = new ComboBoxItem();
    deviceItem.Content = device.Name;
    deviceItem.Tag = device;
    _audioDeviceComboBox.Items.Add(deviceItem);
}

Im SelectionChanged-Ereignis für das Geräte-Kombinationsfeld wird die AudioDevice-Eigenschaft des MediaPlayers auf das ausgewählte Gerät festgelegt, die in der Tag-Eigenschaft des ComboBoxItem gespeichert wurde.

private void _audioDeviceComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    DeviceInformation selectedDevice = (DeviceInformation)((ComboBoxItem)_audioDeviceComboBox.SelectedItem).Tag;
    if (selectedDevice != null)
    {
        mediaPlayer.AudioDevice = selectedDevice;
    }
}

Wiedergabesitzung

Wie zuvor in diesem Artikel beschrieben, wurden viele der von der MediaElement-Klasse verfügbar gemachten Funktionen in die MediaPlaybackSession-Klasse verschoben. Dazu gehören Informationen über den Wiedergabestatus des Players, z. B. die aktuelle Wiedergabeposition, ob der Player Medien wiedergibt bzw. angehalten wurde sowie die aktuelle Wiedergabegeschwindigkeit. MediaPlaybackSession stellt außerdem einige Ereignisse bereit, um Sie bei Statusänderungen zu benachrichtigen. Dazu gehören der aktuelle Puffer- und Download-Status der wiedergegebenen Inhalte sowie die natürliche Größe und das Seitenverhältnis des aktuell wiedergegebenen Videoinhalts.

Das folgende Beispiel zeigt, wie Sie einen Klickhandler für Schaltflächen implementieren können, der bei der Medienwiedergabe 10 Sekunden überspringt. Zuerst wird das MediaPlaybackSession-Objekt für den Player mit der PlaybackSession-Eigenschaft abgerufen. Als Nächstes wird die Position-Eigenschaft auf die aktuelle Wiedergabeposition plus 10 Sekunden festgelegt.

private void _skipForwardButton_Click(object sender, RoutedEventArgs e)
{
    var session = mediaPlayer.PlaybackSession;
    session.Position = session.Position + TimeSpan.FromSeconds(10);
}

Das nächste Beispiel zeigt, wie durch Einstellen der PlaybackRate-Eigenschaft der Sitzung mithilfe einer Schaltfläche zwischen der normalen Wiedergabegeschwindigkeit und zweifacher Geschwindigkeit gewechselt werden kann.

private void _speedToggleButton_Checked(object sender, RoutedEventArgs e)
{
    mediaPlayer.PlaybackSession.PlaybackRate = 2.0;
}
private void _speedToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
    mediaPlayer.PlaybackSession.PlaybackRate = 1.0;
}

Ab Windows 10, Version 1803, können Sie die Drehung, mit der das Video im MediaPlayer präsentiert wird, in Schritten von 90 Grad festlegen.

mediaPlayer.PlaybackSession.PlaybackRotation = MediaRotation.Clockwise90Degrees;

Erkennen erwarteter und unerwarteter Puffer

Das im vorherigen Abschnitt beschriebene MediaPlaybackSession-Objekt bietet zwei Ereignisse zum Erkennen, wann die aktuell wiedergegebene Mediendatei beginnt und die Pufferung beendet: BufferingStarted und BufferingEnded. Dadurch können Sie Ihre Benutzeroberfläche so aktualisieren, dass dem Benutzer angezeigt wird, dass puffert. Die anfängliche Pufferung wird erwartet, wenn eine Mediendatei zum ersten Mal geöffnet wird oder wenn der Benutzer zu einem neuen Element in einer Wiedergabeliste wechselt. Unerwartete Pufferung kann auftreten, wenn die Netzwerkgeschwindigkeit beeinträchtigt wird oder wenn das Inhaltsverwaltungssystem, das die Inhalte bereitstellt, technische Probleme hat. Ab RS3 können Sie das BufferingStarted-Ereignis verwenden, um zu bestimmen, ob das Pufferereignis erwartet wird oder ob es unerwartet ist und die Wiedergabe unterbricht. Sie können diese Informationen als Telemetriedaten für Ihre App oder Ihren Medienübermittlungsdienst verwenden.

Registrieren Sie Handler für die Ereignisse BufferingStarted und BufferingEnded , um Pufferstatusbenachrichtigungen zu empfangen.

mediaPlayer.PlaybackSession.BufferingStarted += MediaPlaybackSession_BufferingStarted;
mediaPlayer.PlaybackSession.BufferingEnded += MediaPlaybackSession_BufferingEnded;

Wandeln Sie im BufferingStarted-Ereignishandler die an das Ereignis übergebenen Ereignisargumente in ein MediaPlaybackSessionBufferingStartedEventArgs-Objekt um, und überprüfen Sie die IsPlaybackInterruption-Eigenschaft . Wenn dieser Wert true ist, ist der Puffer, der das Ereignis ausgelöst hat, unerwartet und unterbricht die Wiedergabe. Andernfalls wird eine anfängliche Pufferung erwartet.

private void MediaPlaybackSession_BufferingStarted(MediaPlaybackSession sender, object args)
{
    MediaPlaybackSessionBufferingStartedEventArgs bufferingStartedEventArgs = args as MediaPlaybackSessionBufferingStartedEventArgs;
    if (bufferingStartedEventArgs != null && bufferingStartedEventArgs.IsPlaybackInterruption)
    {
        // update the playback quality telemetry report to indicate that
        // playback was interrupted
    }

    // update the UI to indicate that playback is buffering
}
private void MediaPlaybackSession_BufferingEnded(MediaPlaybackSession sender, object args)
{
    // update the UI to indicate that playback is no longer buffering
}

Zwei-Finger-Zoomen von Video

MediaPlayer ermöglicht Ihnen, im Videoinhalt das zu rendernde Quellrechteck festzulegen und so in das Video hineinzuzoomen. Das angegebene Rechteck bezieht sich auf ein normalisiertes Rechteck (0,0,1,1) wobei 0,0 der oberen linken Ecke des Frames entspricht und 1,1 die volle Breite und Höhe des Frames angibt. Um beispielsweise das Zoomrechteck so festzulegen, dass der obere rechte Quadrant des Videos gerendert wird, müssten Sie das Rechteck wie folgt angeben: (.5,0,.5,.5). Es ist wichtig, die Werte zu überprüfen, um sicherzustellen, dass Ihr Quellrechteck sich innerhalb des normalisierten Rechtecks (0,0,1,1) befindet. Durch den Versuch, einen Wert außerhalb dieses Bereichs festzulegen, wird eine Ausnahme ausgelöst.

Um den Zwei-Finger-Zoom mithilfe von Multitouchbewegungen zu implementieren, müssen Sie zunächst angeben, welche Gesten unterstützt werden sollen. In diesem Beispiel wurden Gesten zum Skalieren und Übersetzen angefordert. Das ManipulationDelta-Ereignis wird ausgelöst, wenn eine der abonnierten Gesten auftritt. Das DoubleTapped-Ereignis wird verwendet, um den Zoom auf den vollständigen Frame zurückzusetzen.

_mediaPlayerElement.ManipulationMode = ManipulationModes.Scale | ManipulationModes.TranslateX | ManipulationModes.TranslateY;
_mediaPlayerElement.ManipulationDelta += _mediaPlayerElement_ManipulationDelta;
_mediaPlayerElement.DoubleTapped += _mediaPlayerElement_DoubleTapped;

Deklarieren Sie als Nächstes ein Rect-Objekt, welches das aktuelle Zoom-Quellrechteck speichert.

Rect _sourceRect = new Rect(0, 0, 1, 1);

Der ManipulationDelta-Handler passt die Skalierung oder die Übersetzung des Zoom-Rechtecks an. Ist der Deltawert für die Skalierung nicht 1, bedeutet dies, dass der Benutzer eine Zwei-Finger-Zoom-Geste ausgeführt hat. Wenn der Wert größer als 1 ist, muss das Quellrechteck verkleinert werden, um den Inhalt zu vergrößern. Wenn der Wert kleiner als 1 ist, sollte das Quellrechteck vergrößert werden, um verkleinert zu werden. Vor dem Festlegen der neuen Skalierungswerte wird das resultierende Rechteck überprüft, um sicherzustellen, dass es vollständig innerhalb der Grenzwerte (0,0,1,1) liegt.

Wenn der Skalierungswert 1 ist, wird die Übersetzungsgeste behandelt. Das Rechteck wird wie folgt übersetzt: Anzahl der Pixel in der Geste geteilt durch die Breite und Höhe des Steuerelements. Wieder wird das resultierende Rechteck überprüft, um sicherzustellen, dass es innerhalb der Grenzen von (0,0,1,1) liegt.

Schließlich wird die NormalizedSourceRect-Eigenschaft der MediaPlaybackSession auf das neu angepasste Rechteck festgelegt. Dabei wird der Bereich innerhalb des Video-Frames angegeben, der gerendert werden soll.

private void _mediaPlayerElement_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{

    if (e.Delta.Scale != 1)
    {
        var halfWidth = _sourceRect.Width / 2;
        var halfHeight = _sourceRect.Height / 2;

        var centerX = _sourceRect.X + halfWidth;
        var centerY = _sourceRect.Y + halfHeight;

        var scale = e.Delta.Scale;
        var newHalfWidth = (_sourceRect.Width * e.Delta.Scale) / 2;
        var newHalfHeight = (_sourceRect.Height * e.Delta.Scale) / 2;

        if (centerX - newHalfWidth > 0 && centerX + newHalfWidth <= 1.0 &&
            centerY - newHalfHeight > 0 && centerY + newHalfHeight <= 1.0)
        {
            _sourceRect.X = centerX - newHalfWidth;
            _sourceRect.Y = centerY - newHalfHeight;
            _sourceRect.Width *= e.Delta.Scale;
            _sourceRect.Height *= e.Delta.Scale;
        }
    }
    else
    {
        var translateX = -1 * e.Delta.Translation.X / _mediaPlayerElement.ActualWidth;
        var translateY = -1 * e.Delta.Translation.Y / _mediaPlayerElement.ActualHeight;

        if (_sourceRect.X + translateX >= 0 && _sourceRect.X + _sourceRect.Width + translateX <= 1.0 &&
            _sourceRect.Y + translateY >= 0 && _sourceRect.Y + _sourceRect.Height + translateY <= 1.0)
        {
            _sourceRect.X += translateX;
            _sourceRect.Y += translateY;
        }
    }

    mediaPlayer.PlaybackSession.NormalizedSourceRect = _sourceRect;
}

Im DoubleTapped-Ereignishandler wird das Quellrechteck wieder auf (0,0,1,1) festgelegt, damit der gesamte Videoframe gerendert wird.

private void _mediaPlayerElement_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
    _sourceRect = new Rect(0, 0, 1, 1);
    mediaPlayer.PlaybackSession.NormalizedSourceRect = _sourceRect;
}

HINWEIS In diesem Abschnitt wird die Toucheingabe beschrieben. Touchpad sendet Zeigerereignisse und sendet keine Manipulationsereignisse.

Behandeln von richtlinienbasierten Wiedergabeeinbußen

Unter bestimmten Umständen kann das System die Wiedergabe eines Medienelements beeinträchtigen, z. B. die Reduzierung der Auflösung (Einschnürung), basierend auf einer Richtlinie und nicht auf einem Leistungsproblem. Beispielsweise kann das Video vom System beeinträchtigt werden, wenn es mit einem nicht signierten Videotreiber wiedergegeben wird. Sie können MediaPlaybackSession.GetOutputDegradationPolicyState aufrufen, um zu bestimmen, ob und warum diese richtlinienbasierte Degredation auftritt, und den Benutzer benachrichtigen oder den Grund für Telemetriezwecke aufzeichnen.

Das folgende Beispiel zeigt eine Implementierung eines Handlers für das MediaPlayer.MediaOpened-Ereignis , das ausgelöst wird, wenn der Player ein neues Medienelement öffnet. GetOutputDegradationPolicyState wird für den MediaPlayer aufgerufen, der an den Handler übergeben wird. Der Wert von VideoConstrictionReason gibt den Richtliniengrund für die Verengung des Videos an. Wenn der Wert nicht None ist, protokolliert dieses Beispiel den Grund für die Beeinträchtigung für Telemetriezwecke. Dieses Beispiel zeigt auch, dass die Bitrate der AdaptiveMediaSource , die derzeit wiedergegeben wird, auf die niedrigste Bandbreite festgelegt wird, um die Datennutzung zu sparen, da das Video verengt ist und sowieso nicht mit hoher Auflösung angezeigt wird. Weitere Informationen zur Verwendung von AdaptiveMediaSource finden Sie unter Adaptives Streaming.

private void MediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
    MediaPlaybackSessionOutputDegradationPolicyState info = sender.PlaybackSession.GetOutputDegradationPolicyState();

    if (info.VideoConstrictionReason != MediaPlaybackSessionVideoConstrictionReason.None)
    {
        // Switch to lowest bitrate to save bandwidth
        adaptiveMediaSource.DesiredMaxBitrate = adaptiveMediaSource.AvailableBitrates[0];

        // Log the degradation reason or show a message to the user
        System.Diagnostics.Debug.WriteLine("Logging constriction reason: " + info.VideoConstrictionReason);
    }
}

Rendern von Videos auf einer Windows.UI.Composition-Oberfläche mit MediaPlayerSurface

Ab Windows 10, Version 1607, können Sie mit MediaPlayer Videos auf einer ICompositionSurface rendern. Dadurch kann der Player mit den APIs im Windows.UI.Composition-Namespace verwendet werden. Das Kompositions-Framework ermöglicht Ihnen, auf der visuellen Ebene zwischen XAML und den DirectX-Grafik-APIs auf niedriger Ebene Grafiken zu verwenden. Dies ermöglicht Szenarien wie das Rendering von Videos in alle XAML-Steuerelemente. Weitere Informationen zur Verwendung der Composition-APIs finden Sie unter visuelle Ebene.

Das folgende Beispiel veranschaulicht das Rendern von Inhalten des Videoplayers auf ein Canvas-Steuerelement. Die mediaplayerspezifischen Aufrufe in diesem Beispiel sind SetSurfaceSize und GetSurface. SetSurfaceSize teilt dem System die Größe des Puffers mit, der für das Rendern von Inhalten zugeordnet werden muss. GetSurface verwendet einen Compositor als Argument und ruft eine Instanz der MediaPlayerSurface-Klasse ab. Diese Klasse ermöglicht den Zugriff auf den MediaPlayer und den Compositor, mit denen die Oberfläche erstellt wird. Die Klasse macht außerdem die Oberfläche selbst über die CompositionSurface-Eigenschaft verfügbar.

Der restliche Code in diesem Beispiel erstellt ein SpriteVisual-Element, in den das Video gerendert wird, und legt als Größe die Größe des Canvas-Elements fest, das das Visual anzeigt. Als Nächstes wird ein CompositionBrush aus der MediaPlayerSurface erstellt und der Brush-Eigenschaft des Visuals zugeordnet. Dann wird ein ContainerVisual erstellt, und das SpriteVisual wird auf der oberen Ebene der visuellen Struktur eingefügt. Schließlich wird SetElementChildVisual aufgerufen, um das Container-Visual dem Canvas zuzuordnen.

mediaPlayer.SetSurfaceSize(new Size(_compositionCanvas.ActualWidth, _compositionCanvas.ActualHeight));

var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
MediaPlayerSurface surface = mediaPlayer.GetSurface(compositor);

SpriteVisual spriteVisual = compositor.CreateSpriteVisual();
spriteVisual.Size =
    new System.Numerics.Vector2((float)_compositionCanvas.ActualWidth, (float)_compositionCanvas.ActualHeight);

CompositionBrush brush = compositor.CreateSurfaceBrush(surface.CompositionSurface);
spriteVisual.Brush = brush;

ContainerVisual container = compositor.CreateContainerVisual();
container.Children.InsertAtTop(spriteVisual);

ElementCompositionPreview.SetElementChildVisual(_compositionCanvas, container);

Synchronisieren von Inhalten zwischen mehreren Playern mit MediaTimelineController

Wie in diesem Artikel bereits erläutert, können in Ihrer App mehrere MediaPlayer-Objekte gleichzeitig aktiv sein. Standardmäßig funktioniert jeder von Ihnen erstellte MediaPlayer unabhängig. In einigen Szenarien, z. B. beim Synchronisieren einer Kommentarspur mit einem Video, müssen möglicherweise der Status des Players, die Wiedergabeposition und die Wiedergabegeschwindigkeit von mehreren Playern synchronisiert werden. Ab Windows 10, Version 1607, können Sie dieses Verhalten mithilfe der MediaTimelineController-Klasse implementieren.

Implementieren der Wiedergabe-Steuerelemente

Das folgende Beispiel zeigt, wie Sie mit einem MediaTimelineController zwei Instanzen des MediaPlayers steuern können. Zuerst werden alle Instanzen des MediaPlayers instanziiert und eine Mediendatei als Source festgelegt. Als Nächstes wird eine neue MediaTimelineController-Klasse erstellt. Bei jedem MediaPlayer wird der mit den einzelnen Playern verknüpfte MediaPlaybackCommandManager deaktiviert, indem die IsEnabled-Eigenschaft auf „false“ festgelegt wird. Anschließend wird die TimelineController-Eigenschaft auf das Zeitleiste-Controllerobjekt festgelegt.

MediaTimelineController _mediaTimelineController;
mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);


_mediaPlayer2 = new MediaPlayer();
_mediaPlayer2.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video_2.mkv"));
_mediaPlayerElement2.SetMediaPlayer(_mediaPlayer2);

_mediaTimelineController = new MediaTimelineController();

mediaPlayer.CommandManager.IsEnabled = false;
mediaPlayer.TimelineController = _mediaTimelineController;

_mediaPlayer2.CommandManager.IsEnabled = false;
_mediaPlayer2.TimelineController = _mediaTimelineController;

Achtung Die MediaPlaybackCommandManager-Klasse stellt eine automatische Integration zwischen MediaPlayer und den Steuerelementen für den Systemmedientransport (System Media Transport Controls, SMTC) bereit. Diese automatische Integration kann jedoch nicht für Media Player verwendet werden, die über eine MediaTimelineController-Klasse gesteuert werden. Daher müssen Sie vor dem Festlegen des Zeitachsencontrollers des Players den Befehlsmanager des Media Players deaktivieren. Andernfalls wird eine Ausnahme mit folgender Meldung ausgelöst: "Der Medienzeitachsencontroller wird aufgrund des aktuellen Zustands des Objekts blockiert." Weitere Informationen zur Media Player-Integration mit dem SMTC finden Sie unter Integrieren in die Systemmedientransportsteuerelemente. Auch wenn Sie eine MediaTimelineController-Klasse verwenden, können Sie die SMTC weiterhin manuell steuern. Weitere Informationen finden Sie unter Manuelle Steuerung der Steuerelemente für den Systemmedientransport.

Nachdem Sie eine MediaTimelineController-Klasse einem oder mehreren Media Player zugewiesen haben, können Sie den Wiedergabestatus mit den vom Controller bereitgestellten Methoden steuern. Im folgenden Beispiel wird Start aufgerufen, um die Wiedergabe aller zugeordneten Media Player zu Beginn des Mediums zu starten.

private void PlayButton_Click(object sender, RoutedEventArgs e)
{
    _mediaTimelineController.Start();
}

Dieses Beispiel veranschaulicht das Anhalten und Fortsetzen aller zugeordneten Media Player.

private void PauseButton_Click(object sender, RoutedEventArgs e)
{
    if(_mediaTimelineController.State == MediaTimelineControllerState.Running)
    {
        _mediaTimelineController.Pause();
        _pauseButton.Content = "Resume";
    }
    else
    {
        _mediaTimelineController.Resume();
        _pauseButton.Content = "Pause";
    }
}

Für den schnellen Vorlauf aller verbundenen Media Player muss die Wiedergabegeschwindigkeit auf einen Wert größer als 1 festgelegt werden.

private void FastForwardButton_Click(object sender, RoutedEventArgs e)
{
    _mediaTimelineController.ClockRate = 2.0;
}

Das nächste Beispiel zeigt die Verwendung eines Slider-Steuerelements, um die aktuelle Wiedergabeposition des Zeitachsencontrollers in Relation zum Inhalt eines der verbundenen Media Player anzuzeigen. Zunächst wird eine neue MediaSource erstellt und ein Handler für das OpenOperationCompleted-Ereignis der Medienquelle registriert.

var mediaSource = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaSource.OpenOperationCompleted += MediaSource_OpenOperationCompleted;
mediaPlayer.Source = mediaSource;
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);

Der OpenOperationCompleted-Handler bietet eine Möglichkeit, um die Dauer des Inhalts der Medienquelle festzustellen. Sobald die Dauer bestimmt ist, wird der Höchstwert des Slider-Steuerelements auf die Gesamtzahl der Sekunden des Medienelements festgelegt. Der Wert wird innerhalb eines Aufrufs von RunAsync festgelegt, um sicherzustellen, dass es im UI-Thread ausgeführt wird.

TimeSpan _duration;
private async void MediaSource_OpenOperationCompleted(MediaSource sender, MediaSourceOpenOperationCompletedEventArgs args)
{
    _duration = sender.Duration.GetValueOrDefault();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        _positionSlider.Minimum = 0;
        _positionSlider.Maximum = _duration.TotalSeconds;
        _positionSlider.StepFrequency = 1;
    }); 
}

Als Nächstes wird ein Handler für das PositionChanged-Ereignis des Zeitleiste Controllers registriert. Dieses wird in regelmäßigen Abständen durch das System aufgerufen, ungefähr viermal pro Sekunde.

_mediaTimelineController.PositionChanged += _mediaTimelineController_PositionChanged;

Im Handler für PositionChanged wird der Schiebereglerwert aktualisiert, sodass er die aktuelle Position des Zeitachsencontrollers wiedergibt.

private async void _mediaTimelineController_PositionChanged(MediaTimelineController sender, object args)
{
    if (_duration != TimeSpan.Zero)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            _positionSlider.Value = sender.Position.TotalSeconds / (float)_duration.TotalSeconds;
        });
    }
}

Versetzen der Wiedergabeposition in Relation zur Zeitachsenposition

In einigen Fällen soll möglicherweise die Wiedergabeposition eines oder mehrerer mit einem Zeitachsencontroller verknüpften Media Player in Relation zu den anderen Playern versetzt werden. Dafür können Sie die TimelineControllerPositionOffset-Eigenschaft des MediaPlayer-Objekts festlegen, welches versetzt werden soll. Im folgenden Beispiel wird anhand der jeweiligen Dauer des Inhalts von zwei Media Playern der Minimal- und Maximalwert von zwei Schieberegler-Steuerelementen festgelegt, um die Länge des Elements zu verkürzen bzw. zu verlängern.

_timelineOffsetSlider1.Minimum = -1 * _duration.TotalSeconds;
_timelineOffsetSlider1.Maximum = _duration.TotalSeconds;
_timelineOffsetSlider1.StepFrequency = 1;

_timelineOffsetSlider2.Minimum = -1 * _duration2.TotalSeconds;
_timelineOffsetSlider2.Maximum = _duration2.TotalSeconds;
_timelineOffsetSlider2.StepFrequency = 1;

Im ValueChanged-Ereignis jedes Schiebereglers wird TimelineControllerPositionOffset für jeden Player auf den entsprechenden Wert festgelegt.

private void _timelineOffsetSlider1_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    mediaPlayer.TimelineControllerPositionOffset = TimeSpan.FromSeconds(_timelineOffsetSlider1.Value);
}

private void _timelineOffsetSlider2_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    _mediaPlayer2.TimelineControllerPositionOffset = TimeSpan.FromSeconds(_timelineOffsetSlider2.Value);
}

Beachten Sie: Wird der Offsetwert eines Players einer negativen Wiedergabeposition zugeordnet, wird der Clip angehalten, bis der Offset den Wert Null erreicht. Anschließend beginnt die Wiedergabe. Wenn der Offsetwert einer Wiedergabeposition zugeordnet ist, welche die Dauer des Medientitels überschreitet, wird entsprechend das letzte Bild angezeigt. Dies entspricht dem Vorgehen, wenn ein einzelner Media Player das Ende der Inhaltswiedergabe erreicht.

Wiedergeben von sphärischen Videos mit MediaPlayer

Ab Windows 10 Version 1703 unterstützt MediaPlayer die equirektangulare Projektion für die wiedergabe von sphärischen Videos. Sphärische Videoinhalte unterscheiden sich nicht von regulären, flachen Videos, da MediaPlayer das Video rendert, solange die Videocodierung unterstützt wird. Für sphärische Videos, die ein Metadatentag enthalten, das angibt, dass das Video eine äquirectangulare Projektion verwendet, kann MediaPlayer das Video mithilfe eines angegebenen Ansichtsfelds und einer angegebenen Ansichtsausrichtung rendern. Dies ermöglicht Szenarien wie die Wiedergabe von Virtual Reality-Videos mit einem Head-Mounted-Display oder einfach das Schwenken innerhalb von kugelförmigen Videoinhalten mithilfe der Maus- oder Tastatureingabe.

Um sphärische Videos wiederzugeben, führen Sie die schritte für die Wiedergabe von Videoinhalten aus, die zuvor in diesem Artikel beschrieben wurden. Der eine zusätzliche Schritt besteht darin, einen Handler für das MediaPlayer.MediaOpened-Ereignis zu registrieren. Dieses Ereignis bietet Ihnen die Möglichkeit, die Parameter für die wiedergabe von sphärischen Videos zu aktivieren und zu steuern.

mediaPlayer = new MediaPlayer();
mediaPlayer.MediaOpened += _mediaPlayer_MediaOpened;
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video_spherical.mp4"));
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);
mediaPlayer.Play();

Überprüfen Sie im MediaOpened-Handler zunächst das Frameformat des neu geöffneten Medienelements, indem Sie die PlaybackSession.SphericalVideoProjection.FrameFormat-Eigenschaft überprüfen. Wenn dieser Wert SphericaVideoFrameFormat.Equirectangular ist, kann das System den Videoinhalt automatisch projizieren. Legen Sie zunächst die PlaybackSession.SphericalVideoProjection.IsEnabled-Eigenschaft auf true fest. Sie können auch Eigenschaften wie die Ansichtsausrichtung und das Ansichtsfeld anpassen, die der Media Player zum Projizieren des Videoinhalts verwendet. In diesem Beispiel wird das Sichtfeld auf einen breiten Wert von 120 Grad festgelegt, indem die HorizontalFieldOfViewInDegrees-Eigenschaft festgelegt wird.

Wenn der Videoinhalt kugelförmig, aber in einem anderen Format als dem äquirectangular ist, können Sie Ihren eigenen Projektionsalgorithmus implementieren, indem Sie den Frameservermodus des Media Players verwenden, um einzelne Frames zu empfangen und zu verarbeiten.

private void _mediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
    if (sender.PlaybackSession.SphericalVideoProjection.FrameFormat == SphericalVideoFrameFormat.Equirectangular)
    {
        sender.PlaybackSession.SphericalVideoProjection.IsEnabled = true;
        sender.PlaybackSession.SphericalVideoProjection.HorizontalFieldOfViewInDegrees = 120;

    }
    else if (sender.PlaybackSession.SphericalVideoProjection.FrameFormat == SphericalVideoFrameFormat.Unsupported)
    {
        // If the spherical format is unsupported, you can use frame server mode to implement a custom projection
    }
}

Der folgende Beispielcode veranschaulicht, wie die Ausrichtung der sphärischen Videoansicht mithilfe der NACH-LINKS- und NACH-RECHTS-TASTE angepasst wird.

protected override void OnKeyDown(KeyRoutedEventArgs e)
{
    if (mediaPlayer.PlaybackSession.SphericalVideoProjection.FrameFormat != SphericalVideoFrameFormat.Equirectangular)
    {
        return;
    }

    switch (e.Key)
    {
        case Windows.System.VirtualKey.Right:
            mediaPlayer.PlaybackSession.SphericalVideoProjection.ViewOrientation *= Quaternion.CreateFromYawPitchRoll(.1f, 0, 0);
            break;
        case Windows.System.VirtualKey.Left:
            mediaPlayer.PlaybackSession.SphericalVideoProjection.ViewOrientation *= Quaternion.CreateFromYawPitchRoll(-.1f, 0, 0);
            break;
    }
}

Wenn Ihre App Wiedergabelisten von Videos unterstützt, möchten Sie möglicherweise Wiedergabeelemente identifizieren, die sphärische Videos auf Der Benutzeroberfläche enthalten. Medienwiedergabelisten werden im Artikel, in Medienelementen, Wiedergabelisten und Titeln ausführlich erläutert. Das folgende Beispiel zeigt das Erstellen einer neuen Wiedergabeliste, das Hinzufügen eines Elements und das Registrieren eines Handlers für das MediaPlaybackItem.VideoTracksChanged-Ereignis , das auftritt, wenn die Videospuren für ein Medienelement aufgelöst werden.

var playbackList = new MediaPlaybackList();
var item = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/RIFTCOASTER HD_injected.mp4")));
item.VideoTracksChanged += Item_VideoTracksChanged;
playbackList.Items.Add(item);
mediaPlayer.Source = playbackList;

Rufen Sie im VideoTracksChanged-Ereignishandler die Codierungseigenschaften für alle hinzugefügten Videospuren ab, indem Sie VideoTrack.GetEncodingProperties aufrufen. Wenn die SphericalVideoFrameFormat-Eigenschaft der Codierungseigenschaften ein anderer Wert als SphericaVideoFrameFormat.None ist, enthält die Videospur sphärisches Video, und Sie können Ihre Benutzeroberfläche entsprechend aktualisieren, wenn Sie dies auswählen.

private void Item_VideoTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    if (args.CollectionChange != CollectionChange.ItemInserted)
    {
        return;
    }
    foreach (var videoTrack in sender.VideoTracks)
    {
        if (videoTrack.GetEncodingProperties().SphericalVideoFrameFormat != SphericalVideoFrameFormat.None)
        {
            // Optionally indicate in the UI that this item contains spherical video
        }
    }
}

Verwenden von MediaPlayer im Frameservermodus

Ab Windows 10 Version 1703 können Sie MediaPlayer im Frameservermodus verwenden. In diesem Modus rendert der MediaPlayer Frames nicht automatisch in einem zugeordneten MediaPlayerElement. Stattdessen kopiert Ihre App den aktuellen Frame aus dem MediaPlayer in ein Objekt, das IDirect3DSurface implementiert. Das primäre Szenario, das dieses Feature ermöglicht, ist die Verwendung von Pixelshadern zum Verarbeiten von Videoframes, die vom MediaPlayer bereitgestellt werden. Ihre App ist für die Anzeige der einzelnen Frames nach der Verarbeitung verantwortlich, z. B. durch Anzeigen des Frames in einem XAML-Bildsteuerelement .

Im folgenden Beispiel wird ein neuer MediaPlayer initialisiert, und Videoinhalte werden geladen. Als Nächstes wird ein Handler für VideoFrameAvailable registriert. Der Frameservermodus wird aktiviert, indem die IsVideoFrameServerEnabled-Eigenschaft des MediaPlayer-Objekts auf true festgelegt wird. Schließlich wird die Medienwiedergabe mit einem Aufruf von Play gestartet.

mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer.VideoFrameAvailable += mediaPlayer_VideoFrameAvailable;
mediaPlayer.IsVideoFrameServerEnabled = true;
mediaPlayer.Play();

Das nächste Beispiel zeigt einen Handler für VideoFrameAvailable, der Win2D verwendet, um jedem Frame eines Videos einen einfachen Weichzeichnereffekt hinzuzufügen und dann die verarbeiteten Frames in einem XAML-Bildsteuerelement anzuzeigen.

Wenn der VideoFrameAvailable-Handler aufgerufen wird, wird die CopyFrameToVideoSurface-Methode verwendet, um den Inhalt des Frames in ein IDirect3DSurface zu kopieren. Sie können auch CopyFrameToStereoscopicVideoSurfaces verwenden, um 3D-Inhalte in zwei Oberflächen zu kopieren, um inhalte des linken und rechten Auges separat zu verarbeiten. Um ein Objekt abzurufen, das IDirect3DSurface implementiert, erstellt dieses Beispiel eine SoftwareBitmap und verwendet dieses Objekt dann, um eine Win2D CanvasBitmap zu erstellen, die die erforderliche Schnittstelle implementiert. Ein CanvasImageSource-Objekt ist ein Win2D-Objekt, das als Quelle für ein Image-Steuerelement verwendet werden kann. Daher wird ein neues Steuerelement erstellt und als Quelle für das Bild festgelegt, in dem der Inhalt angezeigt wird. Als Nächstes wird eine CanvasDrawingSession erstellt. Dies wird von Win2D verwendet, um den Weichzeichnereffekt zu rendern.

Nachdem alle erforderlichen Objekte instanziiert wurden, wird CopyFrameToVideoSurface aufgerufen, das den aktuellen Frame aus dem MediaPlayer in die CanvasBitmap kopiert. Als Nächstes wird ein Win2D GaussianBlurEffect erstellt, wobei canvasBitmap als Quelle des Vorgangs festgelegt ist. Schließlich wird CanvasDrawingSession.DrawImage aufgerufen, um das Quellbild mit angewendetem Weichzeichnereffekt in die CanvasImageSource zu zeichnen, die dem Image-Steuerelement zugeordnet wurde, sodass es in der Benutzeroberfläche gezeichnet wird.

private async void mediaPlayer_VideoFrameAvailable(MediaPlayer sender, object args)
{
    CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        if(frameServerDest == null)
        {
            // FrameServerImage in this example is a XAML image control
            frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, (int)FrameServerImage.Width, (int)FrameServerImage.Height, BitmapAlphaMode.Ignore);
        }
        if(canvasImageSource == null)
        {
            canvasImageSource = new CanvasImageSource(canvasDevice, (int)FrameServerImage.Width, (int)FrameServerImage.Height, DisplayInformation.GetForCurrentView().LogicalDpi);//96); 
            FrameServerImage.Source = canvasImageSource;
        }

        using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDest))
        using (CanvasDrawingSession ds = canvasImageSource.CreateDrawingSession(Windows.UI.Colors.Black))
        {

            mediaPlayer.CopyFrameToVideoSurface(inputBitmap);

            var gaussianBlurEffect = new GaussianBlurEffect
            {
                Source = inputBitmap,
                BlurAmount = 5f,
                Optimization = EffectOptimization.Speed
            };

            ds.DrawImage(gaussianBlurEffect);

        }
    });
}

private void FrameServerSubtitlesButton_Click(object sender, RoutedEventArgs e)
{

    mediaPlayer = new MediaPlayer();
    var source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
    var item = new MediaPlaybackItem(source);

    item.TimedMetadataTracksChanged += Item_TimedMetadataTracksChanged;


    mediaPlayer.Source = item;
    mediaPlayer.VideoFrameAvailable += mediaPlayer_VideoFrameAvailable_Subtitle;
    mediaPlayer.IsVideoFrameServerEnabled = true;
    mediaPlayer.Play();

    mediaPlayer.IsMuted = true;

}

private void Item_TimedMetadataTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    if(sender.TimedMetadataTracks.Count > 0)
    {
        sender.TimedMetadataTracks.SetPresentationMode(0, TimedMetadataTrackPresentationMode.PlatformPresented);
    }
}

private async void mediaPlayer_VideoFrameAvailable_Subtitle(MediaPlayer sender, object args)
{
    CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        if (frameServerDest == null)
        {
            // FrameServerImage in this example is a XAML image control
            frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, (int)FrameServerImage.Width, (int)FrameServerImage.Height, BitmapAlphaMode.Ignore);
        }
        if (canvasImageSource == null)
        {
            canvasImageSource = new CanvasImageSource(canvasDevice, (int)FrameServerImage.Width, (int)FrameServerImage.Height, DisplayInformation.GetForCurrentView().LogicalDpi);//96); 
            FrameServerImage.Source = canvasImageSource;
        }

        using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDest))
        {
            using (CanvasDrawingSession ds = canvasImageSource.CreateDrawingSession(Windows.UI.Colors.Black))
            {

                mediaPlayer.CopyFrameToVideoSurface(inputBitmap);

                //Rect subtitleTargetRect = new Rect(0, 0, inputBitmap.Bounds.Width, inputBitmap.Bounds.Bottom * .1);
                Rect subtitleTargetRect = new Rect(0, 0, 100, 100);

                mediaPlayer.RenderSubtitlesToSurface(inputBitmap);//, subtitleTargetRect);

                //var gaussianBlurEffect = new GaussianBlurEffect
                //{
                //    Source = inputBitmap,
                //    BlurAmount = 5f,
                //    Optimization = EffectOptimization.Speed
                //};

                //ds.DrawImage(gaussianBlurEffect);

                ds.DrawImage(inputBitmap);
            }
        }
    });
}

Weitere Informationen zu Win2D finden Sie im Win2D-GitHub-Repository. Um den oben gezeigten Beispielcode auszuprobieren, müssen Sie das Win2D-NuGet-Paket mit den folgenden Anweisungen zu Ihrem Projekt hinzufügen.

So fügen Sie das Win2D-NuGet-Paket zum Effektprojekt hinzu

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie NuGet-Pakete verwalten aus.
  2. Wählen Sie oben im Fenster die Registerkarte Durchsuchen aus.
  3. Geben Sie im Suchfeld Win2D ein.
  4. Wählen Sie Win2D.uwp und anschließend im rechten Bereich Installieren aus.
  5. Im Dialogfeld Änderungen überprüfen wird das zu installierende Paket angezeigt. Klicken Sie auf OK.
  6. Akzeptieren Sie die Paketlizenz.

Erkennen und Reagieren auf Audiopegeländerungen durch das System

Ab Windows 10 Version 1803 kann Ihre App erkennen, wenn das System die Audioebene eines aktuell wiedergegebenen MediaPlayer herunter- oder stummschaltet. Beispielsweise kann das System den Audiowiedergabepegel verringern oder "enten" lassen, wenn ein Alarm klingelt. Das System schaltet Ihre App stumm, wenn sie in den Hintergrund wechselt, wenn Ihre App nicht die backgroundMediaPlayback-Funktion im App-Manifest deklariert hat. Mit der AudioStateMonitor-Klasse können Sie sich registrieren, um ein Ereignis zu empfangen, wenn das System die Lautstärke eines Audiodatenstroms ändert. Greifen Sie auf die AudioStateMonitor-Eigenschaft eines MediaPlayers zu, und registrieren Sie einen Handler für das SoundLevelChanged-Ereignis , der benachrichtigt wird, wenn die Audioebene für diesen MediaPlayer vom System geändert wird.

mediaPlayer.AudioStateMonitor.SoundLevelChanged += AudioStateMonitor_SoundLevelChanged;

Beim Behandeln des SoundLevelChanged-Ereignisses können Sie je nach Art des wiedergegebenen Inhalts unterschiedliche Aktionen ausführen. Wenn Sie gerade Musik wiedergeben, sollten Sie die Musik weiterhin wiedergeben lassen, während die Lautstärke geentert ist. Wenn Sie jedoch einen Podcast wiedergeben, möchten Sie die Wiedergabe wahrscheinlich anhalten, während die Audiodaten gedupft werden, damit der Benutzer keinen der Inhalte verpasst.

In diesem Beispiel wird eine Variable deklariert, um nachzuverfolgen, ob der aktuell wiedergegebene Inhalt ein Podcast ist. Es wird davon ausgegangen, dass Sie diesen wert auf den entsprechenden Wert festlegen, wenn Sie den Inhalt für den MediaPlayer auswählen. Außerdem erstellen wir eine Klassenvariable, die nachverfolgt, wenn die Wiedergabe programmgesteuert angehalten wird, wenn sich der Audiopegel ändert.

bool isPodcast;
bool isPausedDueToAudioStateMonitor;

Überprüfen Sie im SoundLevelChanged-Ereignishandler die SoundLevel-Eigenschaft des AudioStateMonitor-Absenders , um den neuen Soundpegel zu bestimmen. In diesem Beispiel wird überprüft, ob der neue Soundpegel die volle Lautstärke aufweist, d. h. das System hat das Stummschalten oder Enten der Lautstärke beendet, oder ob der Soundpegel gesenkt wurde, aber Nicht-Podcast-Inhalte wiedergibt. Wenn einer dieser Elemente zutrifft und der Inhalt zuvor programmgesteuert angehalten wurde, wird die Wiedergabe fortgesetzt. Wenn der neue Soundpegel stummgeschaltet ist oder der aktuelle Inhalt ein Podcast ist und der Soundpegel niedrig ist, wird die Wiedergabe angehalten, und die Variable wird so festgelegt, dass nachverfolgt wird, ob die Pause programmgesteuert initiiert wurde.

private void AudioStateMonitor_SoundLevelChanged(Windows.Media.Audio.AudioStateMonitor sender, object args)
{
    if ((sender.SoundLevel == SoundLevel.Full) || (sender.SoundLevel == SoundLevel.Low && !isPodcast))
    {
        if (isPausedDueToAudioStateMonitor)
        {
            mediaPlayer.Play();
            isPausedDueToAudioStateMonitor = false;
        }
    }
    else if ((sender.SoundLevel == SoundLevel.Muted) ||
         (sender.SoundLevel == SoundLevel.Low && isPodcast))
    {
        if (mediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Playing)
        {
            mediaPlayer.Pause();
            isPausedDueToAudioStateMonitor = true;
        }
    }

}

Der Benutzer kann entscheiden, dass er die Wiedergabe anhalten oder fortsetzen möchte, auch wenn die Audiowiedergabe vom System geentert wird. Dieses Beispiel zeigt Ereignishandler für eine Wiedergabe- und eine Pausenschaltfläche. Wenn die Wiedergabe bereits programmgesteuert angehalten wurde, aktualisieren wir die Variable, um anzugeben, dass der Benutzer den Inhalt angehalten hat. Im Klickhandler der Wiedergabeschaltfläche setzen wir die Wiedergabe fort und löschen die Nachverfolgungsvariable.

private void PauseButton_User_Click(object sender, RoutedEventArgs e)
{
    if (isPausedDueToAudioStateMonitor)
    {
        isPausedDueToAudioStateMonitor = false;
    }
    else
    {
        mediaPlayer.Pause();
    }
}

public void PlayButton_User_Click()
{
    isPausedDueToAudioStateMonitor = false;
    mediaPlayer.Play();
}