Aktivieren der Audiowiedergabe auf Geräten mit Remoteverbindung über Bluetooth

In diesem Artikel erfahren Sie, wie Sie AudioPlaybackConnection verwenden, um mit Bluetooth verbundenen Remotegeräten die Wiedergabe von Audio auf dem lokalen Computer zu ermöglichen.

Ab Windows 10 können Remoteaudioquellen der Version 2004 Audiodaten an Windows-Geräte streamen, sodass Szenarien wie das Konfigurieren eines PCs für das Verhalten eines Bluetooth-Lautsprechers und das Hören von Audiodaten von ihrem Smartphone ermöglicht werden. Die Implementierung verwendet die Bluetooth-Komponenten im Betriebssystem, um eingehende Audiodaten zu verarbeiten und auf den Audioendpunkten des Systems wiederzugeben, z. B. integrierte PC-Lautsprecher oder kabelgebundene Kopfhörer. Die Aktivierung der zugrunde liegenden Bluetooth A2DP-Senke wird von Apps verwaltet, die für das Endbenutzerszenario verantwortlich sind, und nicht vom System.

Die AudioPlaybackConnection-Klasse wird verwendet, um Verbindungen von einem Remotegerät zu aktivieren und zu deaktivieren sowie um die Verbindung zu erstellen, sodass die Remoteaudiowiedergabe gestartet werden kann.

Hinzufügen einer Benutzeroberfläche

Für die Beispiele in diesem Artikel verwenden wir die folgende einfache XAML-Benutzeroberfläche, die das ListView-Steuerelement zum Anzeigen verfügbarer Remotegeräte, einen TextBlock zum Anzeigen der Verbindung status und drei Schaltflächen zum Aktivieren, Deaktivieren und Öffnen von Verbindungen definiert.

<Grid x:Name="MainGrid" Loaded="MainGrid_Loaded">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Connection state: "/>
        <TextBlock x:Name="ConnectionState" Grid.Row="0" Text="Disconnected."/>
    </StackPanel>
    <ListView x:Name="DeviceListView" ItemsSource="{x:Bind devices}" Grid.Row="1">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="enumeration:DeviceInformation">
                <StackPanel Orientation="Horizontal" Margin="6">
                    <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                    <StackPanel>
                        <TextBlock Text="{x:Bind Name}" FontWeight="Bold"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <StackPanel Orientation="Vertical" Grid.Row="2">
        <Button x:Name="EnableAudioPlaybackConnectionButton" Content="Enable Audio Playback Connection" Click="EnableAudioPlaybackConnectionButton_Click"/>
        <Button x:Name="ReleaseAudioPlaybackConnectionButton" Content="Release Audio Playback Connection" Click="ReleaseAudioPlaybackConnectionButton_Click"/>
        <Button x:Name="OpenAudioPlaybackConnectionButtonButton" Content="Open Connection" Click="OpenAudioPlaybackConnectionButtonButton_Click" IsEnabled="False"/>
    </StackPanel>
     
</Grid>

Verwenden von DeviceWatcher zum Überwachen von Remotegeräten

Mit der DeviceWatcher-Klasse können Sie verbundene Geräte erkennen. Die AudioPlaybackConnection.GetDeviceSelector-Methode gibt eine Zeichenfolge zurück, die dem Geräteüberwachungsgerät mitteilt, für welche Arten von Geräten watch werden soll. Übergeben Sie diese Zeichenfolge an den DeviceWatcher-Konstruktor .

Das DeviceWatcher.Added-Ereignis wird für jedes Gerät ausgelöst, das beim Starten des Geräteüberwachungsgeräts verbunden ist, sowie für jedes Gerät, das während der Ausführung des Geräteüberwachungsgeräts verbunden ist. Das DeviceWatcher.Removed-Ereignis wird ausgelöst, wenn ein zuvor verbundenes Gerät getrennt wird.

Rufen Sie DeviceWatcher.Start auf, um mit der Überwachung verbundener Geräte zu beginnen, die Audiowiedergabeverbindungen unterstützen. In diesem Beispiel starten wir den Geräte-Manager, wenn das Standard Grid-Steuerelement auf der Benutzeroberfläche geladen wird. Weitere Informationen zur Verwendung von DeviceWatcher finden Sie unter Auflisten von Geräten.

private void MainGrid_Loaded(object sender, RoutedEventArgs e)
{
    audioPlaybackConnections = new Dictionary<string, AudioPlaybackConnection>();

    // Start watching for paired Bluetooth devices. 
    this.deviceWatcher = DeviceInformation.CreateWatcher(AudioPlaybackConnection.GetDeviceSelector());

    // Register event handlers before starting the watcher. 
    this.deviceWatcher.Added += this.DeviceWatcher_Added;
    this.deviceWatcher.Removed += this.DeviceWatcher_Removed;

    this.deviceWatcher.Start();
}

Im Added-Ereignis des Geräteüberwachungsgeräts wird jedes ermittelte Gerät durch ein DeviceInformation-Objekt dargestellt. Fügen Sie jedes ermittelte Gerät einer beobachtbaren Sammlung hinzu, die an das ListView-Steuerelement in der Benutzeroberfläche gebunden ist.

private ObservableCollection<Windows.Devices.Enumeration.DeviceInformation> devices =
    new ObservableCollection<Windows.Devices.Enumeration.DeviceInformation>();

private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo)
{
    // Collections bound to the UI are updated in the UI thread. 
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
    {
        this.devices.Add(deviceInfo);
    });
}

Aktivieren und Freigeben von Audiowiedergabeverbindungen

Vor dem Herstellen einer Verbindung mit einem Gerät muss die Verbindung aktiviert sein. Dadurch wird das System darüber informiert, dass es eine neue Anwendung gibt, die audio vom Remotegerät auf dem PC wiedergegeben werden soll, aber die Audiowiedergabe erst beginnt, wenn die Verbindung geöffnet ist, was in einem späteren Schritt angezeigt wird.

Rufen Sie im Klickhandler für die Schaltfläche Audiowiedergabeverbindung aktivieren die Geräte-ID ab, die dem aktuell ausgewählten Gerät im ListView-Steuerelement zugeordnet ist. In diesem Beispiel wird ein Wörterbuch mit aktivierten AudioPlaybackConnection-Objekten verwaltet. Diese Methode überprüft zunächst, ob bereits ein Eintrag im Wörterbuch für das ausgewählte Gerät vorhanden ist. Als Nächstes versucht die -Methode, eine AudioPlaybackConnection für das ausgewählte Gerät zu erstellen, indem TryCreateFromId aufgerufen und die ausgewählte Geräte-ID übergeben wird.

Wenn die Verbindung erfolgreich hergestellt wurde, fügen Sie das neue AudioPlaybackConnection-Objekt zum Wörterbuch der App hinzu, registrieren einen Handler für das StateChanged-Ereignis des Objekts, und rufenSie StartAsync auf, um das System zu benachrichtigen, dass die neue Verbindung aktiviert ist.

private Dictionary<String, AudioPlaybackConnection> audioPlaybackConnections;
private async void EnableAudioPlaybackConnectionButton_Click(object sender, RoutedEventArgs e)
{
    if (! (DeviceListView.SelectedItem is null))
    {
        var selectedDeviceId = (DeviceListView.SelectedItem as DeviceInformation).Id;
        if (!this.audioPlaybackConnections.ContainsKey(selectedDeviceId))
        {
            // Create the audio playback connection from the selected device id and add it to the dictionary. 
            // This will result in allowing incoming connections from the remote device. 
            var playbackConnection = AudioPlaybackConnection.TryCreateFromId(selectedDeviceId);

            if (playbackConnection != null)
            {
                // The device has an available audio playback connection. 
                playbackConnection.StateChanged += this.AudioPlaybackConnection_ConnectionStateChanged;
                this.audioPlaybackConnections.Add(selectedDeviceId, playbackConnection);
                await playbackConnection.StartAsync();
                OpenAudioPlaybackConnectionButtonButton.IsEnabled = true;
            }
        }
    }
}

Öffnen der Audiowiedergabeverbindung

Im vorherigen Schritt wurde eine Audiowiedergabeverbindung erstellt, aber der Sound wird erst wiedergegeben, wenn die Verbindung durch Aufrufen von Open oder OpenAsync geöffnet wird. Rufen Sie auf der Schaltfläche Audiowiedergabeverbindung öffnen auf den Klickhandler das aktuell ausgewählte Gerät ab, und verwenden Sie die ID, um audioPlaybackConnection aus dem Verbindungsverzeichnis der App abzurufen. Warten Sie auf einen Aufruf von OpenAsync , und überprüfen Sie den Statuswert des zurückgegebenen AudioPlaybackConnectionOpenResultStatus-Objekts , um festzustellen, ob die Verbindung erfolgreich geöffnet wurde, und wenn ja, aktualisieren Sie das Textfeld verbindungsstatus.

private async void OpenAudioPlaybackConnectionButtonButton_Click(object sender, RoutedEventArgs e)
{
    var selectedDevice = (DeviceListView.SelectedItem as DeviceInformation).Id;
    AudioPlaybackConnection selectedConnection;

    if (this.audioPlaybackConnections.TryGetValue(selectedDevice, out selectedConnection))
    {
        if ((await selectedConnection.OpenAsync()).Status == AudioPlaybackConnectionOpenResultStatus.Success)
        {
            // Notify that the AudioPlaybackConnection is connected. 
            ConnectionState.Text = "Connected";
        }
        else
        {
            // Notify that the connection attempt did not succeed. 
            ConnectionState.Text = "Disconnected (attempt failed)";
        }
    }
}

Überwachen des Verbindungsstatus der Audiowiedergabe

Das AudioPlaybackConnection.ConnectionStateChanged-Ereignis wird ausgelöst, wenn sich der Zustand der Verbindung ändert. In diesem Beispiel aktualisiert der Handler für dieses Ereignis das Textfeld status. Denken Sie daran, die Benutzeroberfläche innerhalb eines Aufrufs von Dispatcher.RunAsync zu aktualisieren, um sicherzustellen, dass die Aktualisierung im UI-Thread vorgenommen wird.

private async void AudioPlaybackConnection_ConnectionStateChanged(AudioPlaybackConnection sender, object args)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        if (sender.State == AudioPlaybackConnectionState.Closed)
        {
            ConnectionState.Text = "Disconnected";
        }
        else if (sender.State == AudioPlaybackConnectionState.Opened)
        {
            ConnectionState.Text = "Connected";
        }
        else
        {
            ConnectionState.Text = "Unknown";
        }
    });
}

Freigeben von Verbindungen und Behandeln entfernter Geräte

In diesem Beispiel wird die Schaltfläche Verbindung für die Audiowiedergabe freigeben bereitgestellt, damit der Benutzer eine Audiowiedergabeverbindung freigeben kann. Im Handler für dieses Ereignis rufen wir das aktuell ausgewählte Gerät ab und verwenden die Geräte-ID, um die AudioPlaybackConnection im Wörterbuch nachzuschlagen. Rufen Sie Dispose auf, um den Verweis freizugeben, alle zugeordneten Ressourcen freizugeben und die Verbindung aus dem Wörterbuch zu entfernen.


private void ReleaseAudioPlaybackConnectionButton_Click(object sender, RoutedEventArgs e)
{
    // Check if an audio playback connection was already created for the selected device Id. If it was then release its reference to deactivate it. 
    // The underlying transport is deactivated when all references are released. 
    if (!(DeviceListView.SelectedItem is null))
    {
        var selectedDeviceId = (DeviceListView.SelectedItem as DeviceInformation).Id;
        if (audioPlaybackConnections.ContainsKey(selectedDeviceId))
        {
            AudioPlaybackConnection connectionToRemove = audioPlaybackConnections[selectedDeviceId];
            connectionToRemove.Dispose();
            this.audioPlaybackConnections.Remove(selectedDeviceId);

            // Notify that the media device has been deactivated. 
            ConnectionState.Text = "Disconnected";
            OpenAudioPlaybackConnectionButtonButton.IsEnabled = false;
        }
    }
}

Sie sollten den Fall behandeln, in dem ein Gerät entfernt wird, während eine Verbindung aktiviert oder geöffnet ist. Implementieren Sie dazu einen Handler für das DeviceWatcher.Removed-Ereignis des Geräteüberwachungsgeräts. Zunächst wird die ID des entfernten Geräts verwendet, um das Gerät aus der beobachtbaren Sammlung zu entfernen, die an das ListView-Steuerelement der App gebunden ist. Wenn sich als Nächstes eine Verbindung mit diesem Gerät im Wörterbuch der App befindet, wird Dispose aufgerufen, um die zugeordneten Ressourcen freizugeben, und dann wird die Verbindung aus dem Wörterbuch entfernt. All dies erfolgt innerhalb eines Aufrufs von Dispatcher.RunAsync , um sicherzustellen, dass die Ui-Updates im UI-Thread ausgeführt werden.

private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate)
{
    // Collections bound to the UI are updated in the UI thread. 
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        // Find the device for the given id and remove it from the list. 
        foreach (DeviceInformation device in this.devices)
        {
            if (device.Id == deviceInfoUpdate.Id)
            {
                this.devices.Remove(device);
                break;
            }
        }

        if (audioPlaybackConnections.ContainsKey(deviceInfoUpdate.Id))
        {
            AudioPlaybackConnection connectionToRemove = audioPlaybackConnections[deviceInfoUpdate.Id];
            connectionToRemove.Dispose();
            this.audioPlaybackConnections.Remove(deviceInfoUpdate.Id);
        }
    });
}

Medienwiedergabe