Freigeben über


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

In diesem Artikel erfahren Sie, wie Sie AudioPlaybackConnection verwenden, um Bluetooth-verbundene Remotegeräte für die Wiedergabe von Audio auf dem lokalen Computer zu aktivieren.

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

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

Hinzufügen einer Benutzeroberfläche

Für die Beispiele in diesem Artikel verwenden wir die folgende einfache XAML-Benutzeroberfläche, die ListView-Steuerelement definiert, um verfügbare Remotegeräte anzuzeigen, ein TextBlock zum Anzeigen des Verbindungsstatus und drei Schaltflächen zum Aktivieren, Deaktivieren und Öffnen von Verbindungen.

<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 angibt, auf welche Arten von Geräten sie achten sollen. Übergeben Sie diese Zeichenfolge an den DeviceWatcher-Konstruktor .

Das DeviceWatcher.Added-Ereignis wird für jedes Gerät ausgelöst, das verbunden ist, wenn die Geräteüberwachung gestartet wird, sowie für jedes Gerät, das verbunden ist, während der Geräteüberwachung ausgeführt wird. 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 Hauptrastersteuerelement in der Benutzeroberfläche geladen wird. Weitere Informationen zur Verwendung von DeviceWatcher finden Sie unter "Aufzählen 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 Add-Ereignis des Geräteüberwachungsgeräts wird jedes ermittelte Gerät durch ein DeviceInformation-Objekt dargestellt. Fügen Sie jedes ermittelte Gerät zu einer observablen Auflistung 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 Öffnen einer Verbindung mit einem Gerät muss die Verbindung aktiviert sein. Dadurch wird das System darüber informiert, dass eine neue Anwendung audio vom Remotegerät auf dem PC wiedergegeben werden soll, die Audiowiedergabe jedoch erst beginnt, wenn die Verbindung geöffnet wird, die 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 von AudioPlaybackConnection-Objekten verwaltet, die aktiviert wurden. 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 erstellt wurde, fügen Sie das neue AudioPlaybackConnection-Objekt zum Wörterbuch der App hinzu, registrieren Sie einen Handler für das StateChanged-Ereignis des Objekts, und rufen SieStartAsync 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, der Sound beginnt jedoch erst, wenn die Verbindung durch Aufrufen von Open oder OpenAsync geöffnet wird. Rufen Sie im Klickhandler für die Schaltfläche "Audiowiedergabeverbindung öffnen" das aktuell ausgewählte Gerät ab, und verwenden Sie die ID, um die AudioPlaybackConnection aus dem Wörterbuch der Verbindungen 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 aktualisieren Sie ggf. das Textfeld für den 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 Verbindungszustands der Audiowiedergabe

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

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 eine Schaltfläche "Audiowiedergabeverbindung freigeben" bereitgestellt, mit der 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 und alle zugehörigen 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 der Geräteüberwachung. Zunächst wird die ID des entfernten Geräts verwendet, um das Gerät aus der feststellbaren Sammlung zu entfernen, die an das ListView-Steuerelement der App gebunden ist. Wenn sich eine verbindung, die diesem Gerät zugeordnet ist, 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