Wiedergeben von Audio- und Videoinhalten mit „MediaPlayer“

In diesem Artikel erfahren Sie, wie Sie Medien in Ihrer Universal Windows-App mithilfe der MediaPlayer-Klasse wieder geben. Mit Windows 10, Version 1607, wurden erhebliche Verbesserungen an den Medienwiedergabe-APIs vorgenommen, einschließlich eines vereinfachten Einzelprozessentwurfs für Hintergrundaudiodaten, der automatischen Integration in die System Media Transport Controls (SMTC), der Möglichkeit, mehrere Medienplayer zu synchronisieren, der Möglichkeit, Videoframes in einer Windows . BENUTZEROBERFLÄCHE. Kompositionsoberfläche 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 for Windows 10 N and Windows 10 KN editions (Medienfeaturepaket 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 dargestellt wird, in Schritten von 90 Grad festlegen.

mediaPlayer.PlaybackSession.PlaybackRotation = MediaRotation.Clockwise90Degrees;

Erkennen der erwarteten und unerwarteten Pufferung

Das im vorherigen Abschnitt beschriebene MediaPlaybackSession-Objekt stellt zwei Ereignisse zum Erkennen des Beginns und Endes der Pufferung der aktuell wiedergegebenen Mediendatei zur Verfügung: BufferingStarted und BufferingEnded. Auf diese Weise können Sie die Benutzeroberfläche aktualisieren, um dem Benutzer zu zeigen, dass eine Pufferung erfolgt. Die erste 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 abgestuft wird oder wenn das Inhaltsverwaltungssystem, das den Inhalt zur Verfügung stellt, technische Probleme hat. Ab RS3 können Sie das BufferingStarted-Ereignis verwenden, um zu bestimmen, ob das Pufferungsereignis erwartet wird oder ob es unerwartet ist und die Wiedergabe unterbrochen wird. Sie können diese Informationen als Telemetriedaten für Ihre App oder Ihren Medienbereitstellungsdienst verwenden.

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

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

Cast the event args passed into the event to a MediaPlaybackSessionBufferingStartedEventArgs object and check the IsPlaybackInterruption property. (Im BufferingStarted-Ereignishandler werden die an das Ereignis übergebenen Ereignis args in ein MediaPlaybackSessionBufferingStartedEventArgs-Objekt umgekniffen, und überprüfen Sie die IsPlaybackInterruption-Eigenschaft .) Wenn dieser Wert true ist, ist die Pufferung, die 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 es zu verkleinern. 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 Leistungseinbußen bei der richtlinienbasierten Wiedergabe

Unter bestimmten Umständen kann das System die Wiedergabe eines Medienelements beeinträchtigen, z. B. die Reduzierung der Auflösung (Einegung) basierend auf einer Richtlinie anstelle eines Leistungsproblems. Beispielsweise kann das Video vom System beeinträchtigt werden, wenn es mit einem nicht signierten Videotreiber abgespielt wird. Sie können MediaPlaybackSession.GetOutputDegradationPolicyState aufrufen, um zu ermitteln, ob und warum diese richtlinienbasierte Degredierung auftritt, und den Benutzer warnen 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 Grund für die Richtlinienverengung des Videos an. Wenn der Wert nicht None ist, protokolliert dieses Beispiel den Grund für die Verschlechterung zu Telemetriezwecken. Dieses Beispiel zeigt auch das Festlegen der Bitrate der aktuell abgespielten AdaptiveMediaSource auf die niedrigste Bandbreite, um die Datennutzung zu sparen, da das Video verengt ist und ohnehin 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 Zeitachsencontrollerobjekt 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. Wenn dies nicht der Fall ist, wird eine Ausnahme mit der folgenden Meldung ausgelöst: "Attaching Media Timeline Controller is blocked because of the current state of the object." (Das Anfügen des Medienzeitachsencontrollers wird aufgrund des aktuellen Zustands des Objekts blockiert.) Weitere Informationen zur Integration von Media Player in 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 Zeitachsencontrollers 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 equirectangular-Projektion für die sphärische Videowiedergabe. Sphärische Videoinhalte unterscheiden sich nicht von regulären, flachen Videos, in denen MediaPlayer das Video rendert, solange die Videocodierung unterstützt wird. Für sphärisches Video, das ein Metadatentag enthält, das angibt, dass das Video die equirectangular-Projektion verwendet, kann MediaPlayer das Video mit einem angegebenen Sichtfeld und einer angegebenen Ansichtsausrichtung rendern. Dies ermöglicht Szenarien wie die Wiedergabe von Virtual Reality-Videos mit einem mit dem Kopf eingebundenen Display oder das einfache Schwenken innerhalb von sphärischen Videoinhalten mithilfe der Maus- oder Tastatureingabe.

Um sphärische Videos wiederzuspielen, verwenden Sie die Schritte zum Wiedergeben von Videoinhalten, die zuvor in diesem Artikel beschrieben wurden. Ein zusätzlicher 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 sphärische Videowiedergabe 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 SpheuneVideoFrameFormat.Equirectangular ist, kann das System den Videoinhalt automatisch pro projektieren. 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 Projektieren des Videoinhalts verwendet. In diesem Beispiel wird das Sichtfeld durch Festlegen der HorizontalFieldOfViewInDegrees-Eigenschaft auf einen breiten Wert von 120 Grad festgelegt.

Wenn der Videoinhalt sphärisch ist, aber in einem anderen Format als equirectangular vorliegt, 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 Pfeiltasten nach links und rechts 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, sollten Sie Wiedergabeelemente identifizieren, die sphärische Videos in Ihrer Benutzeroberfläche enthalten. Medienwiedergabelisten werden im Artikel Medienelemente, Wiedergabelisten und Titel 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 SpheuneVideoFrameFormat.None ist, enthält die Videospur sphärisches Video, und Sie können Ihre Benutzeroberfläche bei Bedarf entsprechend aktualisieren.

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 Pixel-Shadern zum Verarbeiten von Videoframes, die vom MediaPlayer bereitgestellt werden. Ihre App ist dafür verantwortlich, jeden Frame nach der Verarbeitung anzuzeigen, z. B. indem der Frame in einem XAML-Bildsteuerelement angezeigt wird.

Im folgenden Beispiel wird ein neuer MediaPlayer initialisiert und Videoinhalte 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 anzeigt.

Wenn der VideoFrameAvailable-Handler aufgerufen wird, wird die CopyFrameToVideoSurface-Methode verwendet, um den Inhalt des Frames in eine IDirect3DSurface zu kopieren. Sie können auch CopyFrameToStereo contentsVideoSurfaces verwenden, um 3D-Inhalte in zwei Oberflächen zu kopieren, um den Inhalt 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. CanvasImageSource ist ein Win2D-Objekt, das als Quelle für ein Image-Steuerelement verwendet werden kann. Daher wird ein neues Objekt 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, wodurch der aktuelle Frame aus dem MediaPlayer in die CanvasBitmap kopiert wird. 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 das CanvasImageSource-Element zu zeichnen, das dem Bildsteuerelement zugeordnet wurde, wodurch 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 Repository win2D GitHub. 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 Änderungen der Audioebene durch das System

Ab Windows 10 Version 1803 kann Ihre App erkennen, wenn das System die Audioebene eines derzeit abgespielten MediaPlayers herunter- oder stummschaltt. Das System kann z. B. die Audiowiedergabestufe beim Läuten eines Alarms senken oder "veralten". Das System stummschaltt Ihre App, wenn sie in den Hintergrund geht, wenn Ihre App die backgroundMediaPlayback-Funktion nicht 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 Audiostreams ändert. Greifen Sie auf die AudioStateMonitor-Eigenschaft eines MediaPlayer zu , und registrieren Sie einen Handler für das SoundLevelChanged-Ereignis , das 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 abgespielten Inhalts unterschiedliche Aktionen ausführen. Wenn Sie derzeit Musik abspielen, sollten Sie die Musik weiter abspielen lassen, während das Volume überhingt ist. Wenn Sie jedoch einen Podcast wiedergeben, möchten Sie die Wiedergabe wahrscheinlich anhalten, während die Audiodaten gestreamt sind, damit der Benutzer keinen der Inhalte ausbehlt.

In diesem Beispiel wird eine Variable deklariert, um zu verfolgen, ob es sich bei dem aktuell abgespielten Inhalt um einen Podcast handelt. Es wird davon ausgegangen, dass Sie diesen auf den entsprechenden Wert festlegen, wenn Sie den Inhalt für den MediaPlayer auswählen. Wir erstellen auch eine Klassenvariable, die nachverfolgt wird, wenn die Wiedergabe programmgesteuert angehalten wird, wenn sich die Audioebene ä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 die neue Lautstärke voll ist, d. h., das System hat das Stummschalten oder Einnischen der Lautstärke beendet, oder ob der Tonpegel gesenkt wurde, aber keine Podcast-Inhalte wiederklangen. Wenn einer dieser Beiden true ist und der Inhalt zuvor programmgesteuert angehalten wurde, wird die Wiedergabe fortgesetzt. Wenn die neue Tonstufe stumm geschaltet ist oder der aktuelle Inhalt ein Podcast ist und die Tonstufe niedrig ist, wird die Wiedergabe angehalten, und die Variable wird so festgelegt, dass sie nachverfolgt, dass 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 Audiodaten vom System gestreamt werden. Dieses Beispiel zeigt Ereignishandler für eine Wiedergabe und eine Pausenschaltfläche. Wenn der Click-Handler für die Pausenschaltfläche angehalten ist und die Wiedergabe bereits programmgesteuert angehalten wurde, aktualisieren wir die Variable, um anzugeben, dass der Benutzer den Inhalt angehalten hat. Im Wiedergabeschaltflächen-Klickhandler setzen wir die Wiedergabe wieder auf und löschen unsere 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();
}