#include #include #include "include/base/cef_logging.h" #include "LiveRoom/AudioPlay.h" #include "LiveRoom/const.h" #include #include #include #include // #include "utils.h" #define Debug25dAudio 0 #if Debug25dAudio #include #include #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(HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, totalBufferSize ))) == NULL) { LOG(ERROR) << "Memory allocation error"; ExitProcess(1); } WAVEHDR* blocks = reinterpret_cast(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 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(&voiceData[0]); WriteAudio(hWavout_, reinterpret_cast(data), voiceData.size()); } void AudioPlayer::OnRenderCallback() { ++currentFinish_; }