Die WASAPI-Loopback-Erfassung gibt bei bidirektionalem Audio (Videoanrufen) trotz aktiver Sitzung 0 Byte vom Bluetooth-HC++

Programme in C++. Entwicklerforum
Anonymous
 Die WASAPI-Loopback-Erfassung gibt bei bidirektionalem Audio (Videoanrufen) trotz aktiver Sitzung 0 Byte vom Bluetooth-H

Post by Anonymous »

Ich möchte das Systemaudio mithilfe der WASAPI-Loopback-Aufzeichnung aufzeichnen (https://learn.microsoft.com/en-us/windo ... -recording).
Ich habe eine kleine Anwendung erstellt, die die verfügbaren Geräte und die darauf aktiven Sitzungen auflistet. Die Anwendung zeichnet dann einige Sekunden Audio auf und speichert sie in einer WAV-Datei.
Dies scheint gut zu funktionieren, aber das Problem tritt bei Bluetooth-Headsets in einem Videoanruf auf.
Was funktioniert
  • Aufnahme von einem kabelgebundenen Headset
  • Aufnahme von einem 2,4-GHz-Headset
  • Aufnahme von einem integrierten Laptop Lautsprecher
  • Aufnahme von einem Bluetooth-Headset wenn nur der Lautsprecher verwendet wird.
Was fehlschlägt
Wenn ein Bluetooth-Headset sowohl als Mikrofon als auch als Lautsprecher in einem Videoanruf verwendet wird (z. B. Chrome/WebRTC-Anruf), erzeugt die Loopback-Erfassung auf diesem Gerät null Bytes an Audio, obwohl der Sitzungsenumerator anzeigt, dass das Gerät aktiv ist Sitzung.
Was ich in meinen Protokollen sehe
Während eines Testanrufs (Chrome in einer Besprechung) druckt mein Rendergeräte-Enumerator etwa Folgendes aus:

Code: Select all

=== Render Devices ===
[0] Headphones (OnePlus Buds 3) : 0 active sessions
ID: {0.0.0.00000000}.{19c0ada4-d680-46a9-919c-dca80bee9807}
[1] Speakers (Realtek(R) Audio) : 0 active sessions
ID: {0.0.0.00000000}.{357dc357-13e3-4cdb-90c9-ab54f23dedcf}
[2] XG27ACS (Intel(R) Display Audio) : 0 active sessions
ID: {0.0.0.00000000}.{4af2ff2a-e7bf-4a47-8de4-876e9ba2d6ce}
[3] CABLE Input (VB-Audio Virtual Cable) : 0 active sessions
ID: {0.0.0.00000000}.{65fbe74c-81c9-4c39-8a75-55033aa39f4c}
[4] CABLE In 16ch (VB-Audio Virtual Cable) : 0 active sessions
ID: {0.0.0.00000000}.{a2a0ed57-95c3-4689-b0ff-efabb8c3efe1}
[5] Headphones (2- Razer BlackShark V2 HS BT) [Default: Console, Multimedia, Communications] : 1 active session
ID: {0.0.0.00000000}.{dd3f0c1e-aa79-46ff-a3f2-528034df115d}
- chrome.exe (PID: 19412)

Dann beginnt die Aufzeichnung für das aktive Gerät:

Code: Select all

=== Active Devices (1) ===
[0] Headphones (2- Razer BlackShark V2 HS BT)
File: Headphones_2-_Razer_BlackShark_V2_HS_BT_13fa25c5.wav
Sessions: 1
[0] Headphones (2- Razer BlackShark V2 HS BT)
File: Headphones_2-_Razer_BlackShark_V2_HS_BT_13fa25c5.wav
Mix format: 44100 Hz, 32-bit, 2 channels

=== Starting Captures ===
Recording from 1 device(s)...

=== Stopping Captures ===
[OK] Headphones (2- Razer BlackShark V2 HS BT): 0.00 MB

=== Verifying Captures ===
[WARN] Headphones (2- Razer BlackShark V2 HS BT): Possible silence/issues

Also:
  • Ich sehe das Bluetooth-Headset-Gerät.
  • Ich sehe eine aktive Sitzung darauf (Chrome, über IAudioSessionManager2 /
    IAudioSessionControl2).
  • Ich habe die Loopback-Erfassung auf genau diesem Endpunkt erfolgreich initialisiert.
  • Es kommen jedoch nie Daten im Loopback-Stream an (0 Bytes für volle
    Dauer).
  • IAudioCaptureClient::GetNextPacketSize gibt durchweg 0 zurück, und
    das Ereignis „Sample-ready“ wird nie signalisiert.
Wenn ich den gleichen Test wiederhole mit:
  • Ein kabelgebundenes Headset oder
  • Ein 2,4-GHz-USB-Headset oder
  • Dasselbe Bluetooth-Headset, aber Wiedergabe von Musik/Video (ohne dass das Mikrofon von einer Anwendung verwendet wird),
Dann funktioniert die Loopback-Erfassung und ich erhalte gültige WAV-Daten.
Code: Geräteaufzählung und Sitzungserkennung
So zähle ich Geräte auf und erkenne aktive Sitzungen:

Code: Select all

// Enumerate render devices
wil::com_ptr deviceEnum;
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
IID_PPV_ARGS(deviceEnum.put()));

wil::com_ptr deviceCollection;
deviceEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE,
deviceCollection.put());

UINT deviceCount = 0;
deviceCollection->GetCount(&deviceCount);

for (UINT i = 0; i < deviceCount; i++) {
wil::com_ptr device;
deviceCollection->Item(i, device.put());

// Get device ID
wil::unique_cotaskmem_string deviceId;
device->GetId(&deviceId);

// Get session manager to count active sessions
wil::com_ptr sessionMgr;
device->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL,
nullptr, (void**)sessionMgr.put());

wil::com_ptr sessionEnum;
sessionMgr->GetSessionEnumerator(sessionEnum.put());

int sessionCount = 0;
sessionEnum->GetCount(&sessionCount);

// Count active sessions (excluding system sounds if desired)
int activeSessions = 0;
for (int j = 0; j < sessionCount; j++) {
wil::com_ptr session;
sessionEnum->GetSession(j, session.put());

AudioSessionState state;
session->GetState(&state);

if (state == AudioSessionStateActive) {
activeSessions++;
}
}

// If device has active sessions, capture from it
if (activeSessions >  0) {
StartLoopbackCapture(deviceId.get());
}
}

So öffne ich die Loopback-Erfassung
Der Erfassungscode ist Standard-WASAPI-Loopback:
  • Rufen Sie das IMMDevice nach ID mit IMMDeviceEnumerator::GetDevice ab.
  • IMMDevice::Activate, um IAudioClient zu erhalten.
  • IAudioClient::GetMixFormat zum Abrufen des Gerätemixformats.
  • IAudioClient::Initialize im freigegebenen Modus mit Loopback-Flags:

    Code: Select all

    hr = audioClient->Initialize(
    AUDCLNT_SHAREMODE_SHARED,
    AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
    hnsBufferDuration,
    0,
    mixFormat,
    nullptr);
    
    
Meine Capture-Schleife:

Code: Select all

// Set up event callback
HANDLE sampleReadyEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
audioClient->SetEventHandle(sampleReadyEvent);

// Get capture client
wil::com_ptr captureClient;
audioClient->GetService(__uuidof(IAudioCaptureClient),
(void**)captureClient.put());

// Start capture
audioClient->Start();

// Capture loop
while (capturing) {
DWORD waitResult = WaitForSingleObject(sampleReadyEvent, 1000);

// Process all available packets
UINT32 packetLength = 0;
while (SUCCEEDED(captureClient->GetNextPacketSize(&packetLength))
&& packetLength > 0) {
BYTE* pData = nullptr;
UINT32 numFrames = 0;
DWORD flags = 0;

hr = captureClient->GetBuffer(&pData, &numFrames, &flags,
nullptr, nullptr);
if (SUCCEEDED(hr)) {
UINT32 bytesToWrite = numFrames * mixFormat->nBlockAlign;

if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT)) {
WriteFile(hFile, pData, bytesToWrite, &bytesWritten, nullptr);
totalBytes += bytesWritten;  // Always 0 for Bluetooth during calls
}

captureClient->ReleaseBuffer(numFrames);
}
}
}

audioClient->Stop();

Dinge, die ich bereits ausprobiert habe
  • Bestätigt, dass die Sitzung über IAudioSessionManager2 auf demselben Gerät sichtbar und aktiv ist, das ich für Loopback öffne.
  • Bestätigt, dass das Gerät im freigegebenen Modus geöffnet ist (AUDCLNT_SHAREMODE_SHARED).
  • Der exklusive Modus für Wiedergabe und Aufnahme wurde in mmsys.cpl für deaktiviert dieses Gerät (keine Änderung).
  • Versucht, den Standardkonsolenendpunkt und den Standardkommunikationsendpunkt zu verwenden und explizit nach Geräte-ID auszuwählen.
  • Überprüft, dass Initialize() und Start() beide S_OK zurückgeben – die APIs schlagen nicht fehl, sie liefern nur keine Daten
  • Überprüft, dass der gleiche Code funktioniert für:
  • Eingebaute Lautsprecher,
  • Kabelgebunden / USB / 2,4-GHz-Headsets,
  • Dasselbe Bluetooth-Headset beim Abspielen von Musik (YouTube, Spotify) ohne Verwendung des Mikrofons.
  • Dasselbe Bluetooth-Headset spielt Anrufaudio ab, während ein anderes Gerät für das Mikrofon verwendet wird
Umgebung
  • Windows 10/11 (auf mehreren Computern reproduziert).
  • Moderne Bluetooth-Headsets (z. B. OnePlus Buds 3, Razer BlackShark V2 HS BT, Anker Soundcore), die in meinem Fall als einzelner Audio-Endpunkt in den Windows-Soundeinstellungen angezeigt werden.
Fragen
  • Gibt es eine Möglichkeit, Audio von Bluetooth-Headsets während bidirektionaler Anrufe mithilfe von WASAPI-Loopback oder alternativen Windows-APIs zu erfassen?
  • Wenn nicht, dann ist dies der erwartetes Verhalten für Bluetooth-Headsets und WASAPI-Loopback?
  • Gibt es eine offizielle Microsoft-Dokumentation zu dieser Einschränkung?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post