HumanRender/human_render/LiveRoom/AudioPlay.cpp

209 lines
5.8 KiB
C++
Raw Normal View History

2024-12-19 17:46:41 +00:00
#include <windows.h>
#include <mmsystem.h>
#include "include/base/cef_logging.h"
#include "LiveRoom/AudioPlay.h"
#include "LiveRoom/const.h"
#include <chrono>
#include <thread>
#include <string>
#include <atomic>
// #include "utils.h"
#define Debug25dAudio 0
#if Debug25dAudio
#include <iostream>
#include <fstream>
#endif
BOOL bFirstDataPlay = TRUE;
WAVEHDR wh;
unsigned char* ptmpAudioBuffer = NULL;
constexpr int BLOCK_SIZE = 6400;
constexpr int BLOCK_COUNT = 10;
static HWAVEOUT hWaveOut; /* device handle */
static CRITICAL_SECTION waveCriticalSection;
static WAVEHDR* waveBlocks;
static volatile int waveFreeBlockCount;
static int waveCurrentBlock;
WAVEHDR* AllocateBlocks(int size, int count) {
unsigned char* buffer;
DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
if ((buffer = reinterpret_cast<unsigned char*>(HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
totalBufferSize
))) == NULL) {
LOG(ERROR) << "Memory allocation error";
ExitProcess(1);
}
WAVEHDR* blocks = reinterpret_cast<WAVEHDR*>(buffer);
buffer += sizeof(WAVEHDR) * count;
for (int i = 0; i < count; i++) {
blocks[i].dwBufferLength = size;
blocks[i].lpData = (LPSTR)buffer;
//blocks[i].dwFlags = WHDR_INQUEUE;
blocks[i].dwFlags = 0;
buffer += size;
}
return blocks;
}
void FreeBlocks(WAVEHDR* blockArray) {
HeapFree(GetProcessHeap(), 0, blockArray);
}
static int audio_id = 0;
void save_audio_to_file(unsigned char* paudioData, DWORD dwBufferLength) {
#if Debug25dAudio
std::string file_name = "wav/tempAudio_" + std::to_string(audio_id) + ".wav";
WritePcmToWav((const char*)paudioData, dwBufferLength, file_name.c_str(), 16000, 1, 16);
++audio_id;
#endif
}
std::atomic<int64_t> currentAudioIndex = 0;
void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
if (uMsg != WOM_DONE)
return;
EnterCriticalSection(&waveCriticalSection);
waveFreeBlockCount++;
LeaveCriticalSection(&waveCriticalSection);
AudioPlayer* audioPlayer = (AudioPlayer*)dwInstance;
if (nullptr == audioPlayer) {
return;
}
audioPlayer->OnRenderCallback();
}
HWAVEOUT InitAudioPlayer(AudioPlayer* audioPlayer) {
HWAVEOUT hWaveOut = nullptr;
WAVEFORMATEX wfx;
waveBlocks = AllocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
waveFreeBlockCount = BLOCK_COUNT;
waveCurrentBlock = 0;
InitializeCriticalSection(&waveCriticalSection);
// 打开音频输出设备
WAVEFORMATEX waveform;
waveform.wFormatTag = WAVE_FORMAT_PCM;
waveform.nChannels = Audio_channel_count;
waveform.nSamplesPerSec = Audio_sample_rate;
waveform.nAvgBytesPerSec = Audio_sample_rate * Audio_channel_count * 2; // 采样率 * 通道数 * 位深度 / 8
waveform.nBlockAlign = Audio_channel_count * 2; // 通道数 * 位深度 / 8
waveform.wBitsPerSample = 16;
waveform.cbSize = 0;
//waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, (DWORD_PTR)waveOutProc, (DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION);
waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, (DWORD_PTR)waveOutProc, (DWORD_PTR)audioPlayer, CALLBACK_FUNCTION);
if (hWaveOut == NULL) {
LOG(ERROR) << "Failed to open audio device.";
return nullptr;
}
return hWaveOut;
}
void WriteAudio(HWAVEOUT hWaveOut, LPSTR data, int size) {
WAVEHDR* current;
int remain;
current = &waveBlocks[waveCurrentBlock];
while (size > 0) {
if (current->dwFlags & WHDR_PREPARED) {
waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
}
if (size < (int)(BLOCK_SIZE - current->dwUser)) {
memcpy(current->lpData + current->dwUser, data, size);
current->dwUser += size;
break;
}
remain = BLOCK_SIZE - current->dwUser;
memcpy(current->lpData + current->dwUser, data, remain);
size -= remain;
data += remain;
current->dwBufferLength = BLOCK_SIZE;
waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
EnterCriticalSection(&waveCriticalSection);
waveFreeBlockCount--;
LeaveCriticalSection(&waveCriticalSection);
while (!waveFreeBlockCount) {
Sleep(1);
LOG(INFO) << "audio so fast";
}
waveCurrentBlock++;
waveCurrentBlock %= BLOCK_COUNT;
current = &waveBlocks[waveCurrentBlock];
current->dwUser = 0;
}
}
void UninitAudioPlayer(HWAVEOUT* hWaveOut) {
waveOutReset(*hWaveOut);
for (int i = 0; i < waveFreeBlockCount; i++) {
if (waveBlocks[i].dwFlags & WHDR_PREPARED) {
waveOutUnprepareHeader(*hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));
}
}
do {
MMRESULT ret = waveOutClose(*hWaveOut);
if (MMSYSERR_NOERROR == ret) {
break;
} else if (WAVERR_STILLPLAYING == ret) {
::Sleep(1);
} else if (MMSYSERR_NOMEM == ret) {
LOG(ERROR) << "MMSYSERR_NOMEM";
break;
} else {
LOG(INFO) << __func__ << "ret:" << ret;
break;
}
} while (true);
DeleteCriticalSection(&waveCriticalSection);
FreeBlocks(waveBlocks);
*hWaveOut = nullptr;
}
bool AudioPlayer::Init() {
hWavout_ = InitAudioPlayer(this);
return true;
}
void AudioPlayer::Uninit() {
UninitAudioPlayer(&hWavout_);
}
void AudioPlayer::OnRender(const VoiceData& voiceData) {
if (nullptr == hWavout_) {
LOG(WARNING) << "hWaveout is nullptr";
return;
}
++current_;
unsigned char* data = const_cast<unsigned char*>(&voiceData[0]);
WriteAudio(hWavout_, reinterpret_cast<LPSTR>(data), voiceData.size());
}
void AudioPlayer::OnRenderCallback() {
++currentFinish_;
}