add first

This commit is contained in:
jiegeaiai 2024-09-29 00:29:59 +08:00
commit ffb26ec077
19 changed files with 588 additions and 0 deletions

31
AudioRender.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35303.130
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AudioRender", "AudioRender\AudioRender.vcxproj", "{095FA653-16F9-4AAE-87E9-3E467A5E8564}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Debug|x64.ActiveCfg = Debug|x64
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Debug|x64.Build.0 = Debug|x64
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Debug|x86.ActiveCfg = Debug|Win32
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Debug|x86.Build.0 = Debug|Win32
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Release|x64.ActiveCfg = Release|x64
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Release|x64.Build.0 = Release|x64
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Release|x86.ActiveCfg = Release|Win32
{095FA653-16F9-4AAE-87E9-3E467A5E8564}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {50A43890-42B5-46B3-AF83-E4977344D4B1}
EndGlobalSection
EndGlobal

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\Project\\AudioRender\\AudioRender\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}

View File

@ -0,0 +1,27 @@
#include "AudioRender.h"
#include <assert.h>
#include <memory>
#include "IAudioRender.h"
static std::unique_ptr<IAudioRender> audiosRender_;
bool __stdcall Initialize(const char* sender_name, const char* receiver_name) {
assert(!audiosRender_);
audiosRender_.reset(IAudioRender::Create());
return true;
}
bool __stdcall Write(const unsigned char* data, unsigned int len) {
assert(audiosRender_);
std::vector<unsigned char> audio(len, 0);
memcpy(&audio[0], data, len);
AudioFrame frame = { audio, 0 };
return audiosRender_->Write(frame);
}
void __stdcall Uninitialize() {
assert(audiosRender_);
audiosRender_.reset();
}

21
AudioRender/AudioRender.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#if defined(WIN32)
#ifdef AUDIO_RENDER_LIB
#define AUDIO_RENDER_EXPORT __declspec( dllexport )
#else
#define AUDIO_RENDER_EXPORT __declspec( dllimport )
#endif
#endif // WIN32
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
AUDIO_RENDER_EXPORT bool __stdcall Initialize(const char* sender_name, const char* receiver_name);
AUDIO_RENDER_EXPORT bool __stdcall Write(const unsigned char* data, unsigned int len);
AUDIO_RENDER_EXPORT void __stdcall Uninitialize();
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{095fa653-16f9-4aae-87e9-3e467a5e8564}</ProjectGuid>
<RootNamespace>AudioRender</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;WIN32;AUDIO_RENDER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>D:\Project\AudioRender\AudioRender;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;WIN32;AUDIO_RENDER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AudioRender.h" />
<ClInclude Include="AudioRenderStd.h" />
<ClInclude Include="IAudioRender.h" />
<ClInclude Include="Windows\CoreAudioRender.h" />
<ClInclude Include="Windows\SectionLock.h" />
<ClInclude Include="Windows\WavAudioRender.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AudioRender.cpp" />
<ClCompile Include="AudioRenderStd.cpp" />
<ClCompile Include="Windows\CoreAudioRender.cpp" />
<ClCompile Include="Windows\SectionLock.cpp" />
<ClCompile Include="Windows\WavAudioRender.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="IAudioRender.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="Windows\CoreAudioRender.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="Windows\WavAudioRender.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="AudioRenderStd.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="Windows\SectionLock.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="AudioRender.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Windows\CoreAudioRender.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Windows\WavAudioRender.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="AudioRenderStd.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Windows\SectionLock.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="AudioRender.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@ -0,0 +1,7 @@
#include "AudioRenderStd.h"
#include "Windows/WavAudioRender.h"
IAudioRender* IAudioRender::Create() {
return new WavAudioRender;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "IAudioRender.h"
class AudioRenderStd : public IAudioRender {
public:
~AudioRenderStd() override = default;
uint64 GetClock() override {
return 0;
}
};

View File

@ -0,0 +1,30 @@
#pragma once
#include <vector>
using int8 = char;
using uint8 = unsigned char;
using int16 = short;
using uint16 = unsigned short;
using int32 = int;
using uint32 = unsigned int;
using int64 = long long;
using uint64 = unsigned long long;
struct AudioFrame {
std::vector<uint8> data_;
uint64 dts_{ 0 };
};
class IAudioRender {
public:
static IAudioRender* Create();
public:
virtual ~IAudioRender() = default;
virtual uint64 GetClock() = 0;
virtual bool Write(const AudioFrame& audioFrame) = 0;
};

View File

@ -0,0 +1 @@
#include "CoreAudioRender.h"

View File

@ -0,0 +1,7 @@
#pragma once
#include "IAudioRender.h"
class CoreAudioRender : public IAudioRender {
};

View File

@ -0,0 +1,22 @@
#include "Windows/SectionLock.h"
SectionLock::SectionLock() noexcept {
InitializeCriticalSection(&section_);
}
SectionLock::~SectionLock() {
DeleteCriticalSection(&section_);
}
void SectionLock::Lock() {
EnterCriticalSection(&section_);
}
bool SectionLock::TryLock() {
bool success = TryEnterCriticalSection(&section_);
return success;
}
void SectionLock::UnLock() {
LeaveCriticalSection(&section_);
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <Windows.h>
class SectionLock {
public:
explicit SectionLock() noexcept;
explicit SectionLock(const SectionLock& ) = delete;
SectionLock& operator= (const SectionLock&) = delete;
~SectionLock();
void Lock();
bool TryLock();
void UnLock();
private:
CRITICAL_SECTION section_;
};
template <class Lock>
class Locker {
public:
explicit Locker(Lock& lock) noexcept : lock_(lock) {
lock_.Lock();
}
explicit Locker(const Locker&) = delete;
Locker& operator= (const Locker&) = delete;
~Locker() {
lock_.UnLock();
}
private:
Lock& lock_;
};

View File

@ -0,0 +1,144 @@
#include "Windows/WavAudioRender.h"
#include <windows.h>
#include <mmsystem.h>
static WAVEHDR* AllocateBlocks(uint32 size, int32 count) {
uint32 totalBufferSize = (size + sizeof(WAVEHDR)) * count;
uint8* buffer{ nullptr };
if ((buffer = reinterpret_cast<uint8*>(HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
totalBufferSize
))) == NULL) {
ExitProcess(1);
}
WAVEHDR* blocks = reinterpret_cast<WAVEHDR*>(buffer);
buffer += sizeof(WAVEHDR) * count;
for (int32 index = 0; index < count; ++index) {
blocks[index].dwBufferLength = size;
blocks[index].lpData = (LPSTR)buffer;
blocks[index].dwFlags = 0;
buffer += size;
}
return blocks;
}
static void FreeBlocks(WAVEHDR* blockArray) {
HeapFree(GetProcessHeap(), 0, blockArray);
}
WavAudioRender::WavAudioRender() noexcept {
HWAVEOUT hWaveOut = nullptr;
waveBlocks_ = AllocateBlocks(BlockSize_, BlockCount_);
constexpr int32 rate = 16000;
constexpr int32 channel = 1;
constexpr int32 bitePerSample = 16;
WAVEFORMATEX waveform;
waveform.wFormatTag = WAVE_FORMAT_PCM;
waveform.nChannels = channel;
waveform.nSamplesPerSec = rate;
waveform.nAvgBytesPerSec = rate * channel * 2;
waveform.nBlockAlign = channel * 2;
waveform.wBitsPerSample = bitePerSample;
waveform.cbSize = 0;
MMRESULT hr = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform,
reinterpret_cast<DWORD_PTR>(WavAudioRender::waveOutProc),
reinterpret_cast<DWORD_PTR>(this), CALLBACK_FUNCTION);
if (MMSYSERR_NOERROR == hr) {
return;
}
hWavout_ = std::move(hWaveOut);
}
WavAudioRender::~WavAudioRender() {
if (nullptr == hWavout_) {
return;
}
waveOutReset(hWavout_);
for (int i = 0; i < BlockCount_; i++) {
if (waveBlocks_[i].dwFlags & WHDR_PREPARED) {
waveOutUnprepareHeader(hWavout_, &waveBlocks_[i], sizeof(WAVEHDR));
}
}
do {
MMRESULT ret = waveOutClose(hWavout_);
if (MMSYSERR_NOERROR == ret) {
break;
} else if (WAVERR_STILLPLAYING == ret) {
::Sleep(1);
} else if (MMSYSERR_NOMEM == ret) {
break;
} else {
break;
}
} while (true);
FreeBlocks(waveBlocks_);
}
bool WavAudioRender::Write(const AudioFrame& audioFrame) {
if (nullptr == hWavout_) {
return false;
}
WAVEHDR* current;
int32 remain;
current = &waveBlocks_[waveCurrentBlock_];
uint64 size = audioFrame.data_.size();
const uint8* data = audioFrame.data_.data();
while (size > 0) {
if (current->dwFlags & WHDR_PREPARED) {
waveOutUnprepareHeader(hWavout_, current, sizeof(WAVEHDR));
}
if (size < (int)(BlockSize_ - current->dwUser)) {
memcpy(current->lpData + current->dwUser, data, size);
current->dwUser += size;
break;
}
remain = BlockSize_ - static_cast<int32>(current->dwUser);
memcpy(current->lpData + current->dwUser, data, remain);
size -= remain;
data += remain;
current->dwBufferLength = BlockSize_;
waveOutPrepareHeader(hWavout_, current, sizeof(WAVEHDR));
waveOutWrite(hWavout_, current, sizeof(WAVEHDR));
{
Locker<SectionLock> locker(lock_);
--freeBlockCounter_;
}
while (!freeBlockCounter_) {
Sleep(1);
}
++waveCurrentBlock_;
waveCurrentBlock_ %= BlockCount_;
current = &waveBlocks_[waveCurrentBlock_];
current->dwUser = 0;
}
return true;
}
void CALLBACK WavAudioRender::waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
WavAudioRender* self = reinterpret_cast<WavAudioRender*>(dwInstance);
if (uMsg != WOM_DONE)
return;
self->FreeBlock();
}
void WavAudioRender::FreeBlock() {
Locker<SectionLock> locker(lock_);
++freeBlockCounter_;
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "AudioRenderStd.h"
#include "Windows/SectionLock.h"
class WavAudioRender : public AudioRenderStd {
public:
explicit WavAudioRender() noexcept;
~WavAudioRender() override;
bool Write(const AudioFrame& audioFrame) override;
private:
static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2);
void FreeBlock();
private:
int64_t audioPts_{ 0 };
static constexpr int BlockSize_{ 6400 };
static constexpr int BlockCount_{ 10 };
SectionLock lock_;
uint32 freeBlockCounter_{ BlockCount_ };
uint32 waveCurrentBlock_{ 0 };
WAVEHDR* waveBlocks_{ nullptr };
HWAVEOUT hWavout_{ nullptr };
};