简体   繁体   English

使用 WASAPI 捕获蓝牙音频数据

[英]capturing bluetooth audio data with WASAPI

I'm working on a small project where I need to mix incoming data from my internal microphone and a bluetooth headset (Bose).我正在做一个小项目,我需要混合来自内部麦克风和蓝牙耳机 (Bose) 的传入数据。 I thought I'd use WASAPI for it.我以为我会使用 WASAPI。 However, whilst I can easily read out my internal microphone, this is not the case for my Bluetooth headphones.然而,虽然我可以轻松读出我的内置麦克风,但我的蓝牙耳机却不是这样。 I followed the example given by the Docs almost to the letter, however I made a small change to be able to choose my own "input device" (internal microphone or headset) using th ID they have been given.我几乎完全按照文档给出的示例进行操作,但是我做了一个小改动,以便能够使用他们提供的 ID 选择我自己的“输入设备”(内部麦克风或耳机)。

Tho method is the following:方法如下:

HRESULT RecordAudioStreamBLE(MyAudioSink *pMySink, LPWSTR pwszID)
{

    HRESULT hr;
    REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
    REFERENCE_TIME hnsActualDuration;
    UINT32 bufferFrameCount;
    UINT32 numFramesAvailable;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    IAudioClient *pAudioClient = NULL;
    IAudioCaptureClient *pCaptureClient = NULL;
    WAVEFORMATEX *pwfx = NULL;
    UINT32 packetLength = 0;
    BOOL bDone = FALSE;
    BYTE *pData;
    DWORD flags;

    hr = CoInitialize(0);

    hr = CoCreateInstance(
           CLSID_MMDeviceEnumerator, NULL,
           CLSCTX_ALL, IID_IMMDeviceEnumerator,
           (void**)&pEnumerator);
    EXIT_ON_ERROR(hr)

    hr = pEnumerator->GetDevice(pwszID, &pDevice);
    EXIT_ON_ERROR(hr)

    hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL,
                          NULL, (void**)&pAudioClient);
    EXIT_ON_ERROR(hr)

    hr = pAudioClient->GetMixFormat(&pwfx);
    EXIT_ON_ERROR(hr)

    hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
                                  0, hnsRequestedDuration,
                                  0, pwfx, NULL);
    EXIT_ON_ERROR(hr)

    // Get the size of the allocated buffer.
    hr = pAudioClient->GetBufferSize(&bufferFrameCount);
    EXIT_ON_ERROR(hr)

    hr = pAudioClient->GetService(IID_IAudioCaptureClient,
                                  (void**)&pCaptureClient);
    EXIT_ON_ERROR(hr)

    // Notify the audio sink which format to use.
    hr = pMySink->SetFormat(pwfx);
    EXIT_ON_ERROR(hr)

    // Calculate the actual duration of the allocated buffer.
    hnsActualDuration = (double)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;

    hr = pAudioClient->Start();  // Start recording.
    EXIT_ON_ERROR(hr)

    // Each loop fills about half of the shared buffer.
    while (bDone == FALSE)
    {
        // Sleep for half the buffer duration.
        Sleep(hnsActualDuration/REFTIMES_PER_MILLISEC/2);

        hr = pCaptureClient->GetNextPacketSize(&packetLength);
        EXIT_ON_ERROR(hr)

        printf("packet size = %d\n", packetLength);
        while (packetLength != 0)
        {
            // Get the available data in the shared buffer.
            hr = pCaptureClient->GetBuffer( &pData,
                                            &numFramesAvailable,
                                            &flags, NULL, NULL);
            EXIT_ON_ERROR(hr)

            if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
            {
                pData = NULL;  // Tell CopyData to write silence.
            }

            // Copy the available capture data to the audio sink.
            hr = pMySink->CopyData(pData, numFramesAvailable, &bDone);
            EXIT_ON_ERROR(hr)

            hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
            EXIT_ON_ERROR(hr)

            hr = pCaptureClient->GetNextPacketSize(&packetLength);
            EXIT_ON_ERROR(hr)
        }
    }

    hr = pAudioClient->Stop();  // Stop recording.
    EXIT_ON_ERROR(hr)

Exit:
    printf("%s\n", hr);
    CoTaskMemFree(pwfx);
    SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pDevice)
    SAFE_RELEASE(pAudioClient)
    SAFE_RELEASE(pCaptureClient)

    return hr;
}

When doing this with the ID for the internal microphone, everything works normally.使用内部麦克风的 ID 执行此操作时,一切正常。 However, if the ID of the bluetooth device is used I get the following output: (I first list all the active devices and choose the ID in the terminal:但是,如果使用蓝牙设备的 ID,我会得到以下输出:(我首先列出所有活动设备并在终端中选择 ID:

Endpoint 0: "S24D330 (Intel(R) Display Audio)" ({0.0.0.00000000}.{0f483f83-6e29-482e-94b5-fb9cc257a03d})
Endpoint 1: "Hoofdtelefoon (LE-My headphone Hands-Free AG Audio)" ({0.0.0.00000000}.{75c8e0c3-2e44-4538-940d-f8c2ae6424ca})
Endpoint 2: "Hoofdtelefoon (My headphone Stereo)" ({0.0.0.00000000}.{849b4cc2-ed72-4d40-9725-d1ce6b4abfa0})
Endpoint 3: "Luidsprekers (2- High Definition Audio Device)" ({0.0.0.00000000}.{cb8d7625-257e-4fd0-84b8-26de6aeb1e1b})
Endpoint 4: "Microfoon (2- High Definition Audio Device)" ({0.0.1.00000000}.{5edec961-7a46-4554-bdcd-43fb7d9a9d9a})
Endpoint 5: "Hoofdtelefoon (LE-My headphone Hands-Free AG Audio)" ({0.0.1.00000000}.{f937a0fa-1475-495b-81be-7aec0c1c7ea5})
Which input would you like?5
samples per second 16000
packet size = 0
packet size = 0
packet size = 0
packet size = 0
packet size = 0
packet size = 0
packet size = 0
packet size = 0
packet size = 0
^C

The packet size is printed in the loop in the method shown above.数据包大小以上述方法在循环中打印。 Shows that the packet size each time is just 0. Does anybody know how to fix this, and just get "regular" data out of it?显示每次的数据包大小仅为 0。有谁知道如何解决这个问题,并从中获取“常规”数据? Do I maybe need to use a different API?我可能需要使用不同的 API 吗? Speed is key however.然而,速度是关键。

With kind regards亲切的问候

Many Bluetooth headsets support both the A2DP profile for stereo playback and the Hands-Free protocol for bidirectional mono communication, but not at the same time.许多蓝牙耳机同时支持用于立体声播放的 A2DP 配置文件和用于双向单声道通信的免提协议,但不能同时支持。

If one of these protocols is active, the other will stall.如果这些协议之一处于活动状态,另一个将停止。

I suspect the problem in your case is that something is playing to the A2DP endpoint "Hoofdtelefoon (My headphone Stereo)" and that is causing all activity on the two HF endpoints to stall.我怀疑您的情况的问题在于 A2DP 端点“Hoofdtelefoon(我的耳机立体声)”正在播放某些内容,这导致两个 HF 端点上的所有活动停止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM