zoukankan      html  css  js  c++  java
  • UE4 使用WASAPI获取系统音频

    多线程+WASAPI获取系统音频:

    #pragma once
    
    #include "CoreMinimal.h"
    //MultiThread
    #include "Runnable.h"
    #include "RunnableThread.h"
    #include "ThreadSafeCounter.h"
    #include "ThreadSafeBool.h"
    
    struct IAudioClient;
    struct IAudioCaptureClient;
    typedef LONGLONG REFERENCE_TIME;
    typedef struct tWAVEFORMATEX WAVEFORMATEX;
    class TESTJIGOU_API AudioStreamThread : public FRunnable
    {
    public:
        AudioStreamThread();
        ~AudioStreamThread();
    
        //暂停线程    
        void PauseThread();
        //继续线程
        void ContinueThread();
        //停止线程
        void StopThread();
    
        bool IsThreadPaused();
        bool IsThreadKilled();
    
        //向zego传音频数据
        void CopyData2Zego(unsigned char* data,int dataLen);
    public:
        WAVEFORMATEX* m_Format;
        //音频数据
        TArray<unsigned char> m_audioData;
    private:
        FRunnableThread* Thread;
        FThreadSafeCounter StopTaskCounter;
        FCriticalSection m_mutex;
    private:
    
        int curIndex;
        //WASAPI Variable
        IAudioClient* m_Client;
        IAudioCaptureClient* m_Capture;
        REFERENCE_TIME m_WaitTime;
        //WASAPI Function
        void SetWaveFormat(WAVEFORMATEX& format);
        bool InitLoopBack();
        void AudioStreamLoop();
        void StopAudioStream();
    private:
        //override function
        virtual bool Init() override;
        virtual uint32 Run() override;
        virtual void Stop() override;
        virtual void Exit() override;
    private:
        FThreadSafeBool m_Kill;
        FThreadSafeBool m_Pause;
    };
    #include "AudioStreamThread.h"
    #include "WindowsPlatformProcess.h"
    //WASAPI
    #include <mmdeviceapi.h>
    #include <AudioClient.h>
    
    
    AudioStreamThread::AudioStreamThread()
    {
        m_Kill = false;
        m_Pause = false;
    
        m_Client = nullptr;
        m_Capture = nullptr;
        m_Format = nullptr;
    
        curIndex = 0;
    
        Thread = FRunnableThread::Create(this, TEXT("AudioStreamThread"), 0, TPri_Normal);
    }
    
    AudioStreamThread::~AudioStreamThread()
    {
        if (Thread)
        {
            delete Thread;
            Thread = nullptr;
        }
    }
    
    void AudioStreamThread::PauseThread()
    {
        m_Pause = true;
    }
    
    void AudioStreamThread::ContinueThread()
    {
        m_Pause = false;
    }
    
    void AudioStreamThread::StopThread()
    {
        Stop();
        if (Thread)
        {
            Thread->WaitForCompletion();
        }
    }
    
    bool AudioStreamThread::IsThreadPaused()
    {
        return (bool)m_Pause;
    }
    
    bool AudioStreamThread::IsThreadKilled()
    {
        return (bool)m_Kill;
    }
    
    void AudioStreamThread::CopyData2Zego(unsigned char* data, int dataLen)
    {
        m_mutex.Lock();
        if (m_audioData.Num() >= dataLen)
        {
            memcpy(data, m_audioData.GetData(), dataLen);
            //curIndex += dataLen;
            m_audioData.RemoveAt(0, dataLen);
        }
        m_mutex.Unlock();
    }
    
    void AudioStreamThread::SetWaveFormat(WAVEFORMATEX& format)
    {
        if (format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
        {
            format.wFormatTag = WAVE_FORMAT_PCM;
        }
        else if (format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
        {
            PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(&format);
            if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat))
            {
                pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
                pEx->Samples.wValidBitsPerSample = 16;
            }
        }
        format.wBitsPerSample = 16;
        format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
        format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec;
    }
    
    bool AudioStreamThread::InitLoopBack()
    {
        IMMDeviceEnumerator* enumerator;
        HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&enumerator));
        IMMDevice* device;
        hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
        hr = device->Activate(__uuidof(IAudioClient), CLSCTX_SERVER, NULL, reinterpret_cast<void**>(&m_Client));
    
        hr = m_Client->GetMixFormat(&m_Format);
        SetWaveFormat(*m_Format);
        hr = m_Client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, m_Format, NULL);
    
        hr = m_Client->GetService(__uuidof(IAudioCaptureClient), reinterpret_cast<void**>(&m_Capture));
    
        hr = m_Client->GetDevicePeriod(&m_WaitTime, NULL);
        hr = m_Client->Start();
    
        if (enumerator != nullptr)
        {
            enumerator->Release();
        }
        if (device != nullptr)
        {
            device->Release();
        }
    
        return SUCCEEDED(hr);
    }
    
    void AudioStreamThread::AudioStreamLoop()
    {
        BYTE* data = nullptr;
        UINT32 size;
        DWORD flags;
        UINT64 device, performance;
        HRESULT hr = m_Capture->GetNextPacketSize(&size);
    
        hr = m_Capture->GetBuffer(&data, &size, &flags, &device, &performance);
        int byteWrite = size*m_Format->nBlockAlign;
        if (data != nullptr)
        {
            m_audioData.Append(data, size);
        }
        uint8_t* formatData = (uint8_t*)data;
        hr = m_Capture->ReleaseBuffer(size);
    }
    
     void AudioStreamThread::StopAudioStream()
     {
     
     }
    
    bool AudioStreamThread::Init()
    {
        return InitLoopBack();
    }
    
    uint32 AudioStreamThread::Run()
    {
        FPlatformProcess::Sleep(0.03);
        while (StopTaskCounter.GetValue() == 0 && !m_Kill)
        {
            if (m_Pause)
            {
                if (m_Kill)
                {
                    return 0;
                }
            }
            else
            {
    
                m_mutex.Lock();
                //需要同步处理的内容
    
                //AudioStreamLoop();
                BYTE* data = nullptr;
                UINT32 size;
                DWORD flags;
                UINT64 device, performance;
                HRESULT hr = m_Capture->GetNextPacketSize(&size);
    
                hr = m_Capture->GetBuffer(&data, &size, &flags, &device, &performance);
                int byteWrite = size*m_Format->nBlockAlign;
                if (data != nullptr)
                {
                    m_audioData.Append(data, byteWrite);
                }
                uint8_t* formatData = (uint8_t*)data;
                hr = m_Capture->ReleaseBuffer(size);
    
                m_mutex.Unlock();
    
                FPlatformProcess::Sleep((m_WaitTime) / 2 / (10 * 1000) / 1000);
            }
        }
        return 0;
    }
    
    void AudioStreamThread::Stop()
    {
        StopTaskCounter.Increment();
        m_Kill = true;
        m_Pause = false;
    }
    
    void AudioStreamThread::Exit()
    {
    
    }

    音频数据存储在m_AudioData,因为是实时获取,这里得到相应长度的数据后就会把它删除,如果要实现录音功能,改为不删除取出的数据即可。

  • 相关阅读:
    10款AJAX/CSS/HTML的在线表单生成器
    SQLServer中使用索引视图(物化视图)
    Github for Windows使用介绍
    微软一站式示例代码库
    SQL中存储过程中使用事务,并且加入异常处理机制.
    .NET 性能分析工具
    公众号和app和web都是客户端,都可以对接一个后台
    服务器session,Tomcat有自己的session维护机制,apache有自己的session维护机制
    主账户经验
    spring mvc中的@propertysource
  • 原文地址:https://www.cnblogs.com/litmin/p/8371274.html
Copyright © 2011-2022 走看看