diff --git a/CMakeLists.txt b/CMakeLists.txt index b492285d68d1671b21dc99879390d9f4fe3e4682..2ddeeec2ba2b71d297d0d120a23cb914db9d3ee4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,12 +135,12 @@ if(MSVC) "${CMAKE_CURRENT_SOURCE_DIR}/src/jamidht;" "${CMAKE_CURRENT_SOURCE_DIR}/src/security;" "${CMAKE_CURRENT_SOURCE_DIR}/src/sip;" - "${CMAKE_CURRENT_SOURCE_DIR}/compat/msvc;" "${CMAKE_CURRENT_SOURCE_DIR}/src/upnp;" "${CMAKE_CURRENT_SOURCE_DIR}/src/upnp/igd;" "${CMAKE_CURRENT_SOURCE_DIR}/src/upnp/protocol;" "${CMAKE_CURRENT_SOURCE_DIR}/src/upnp/mapping;" "${CMAKE_CURRENT_SOURCE_DIR}/src/jamidht/eth;" + "${CMAKE_CURRENT_SOURCE_DIR}/compat/msvc;" "${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc;" "${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/include;" "${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/msgpack-c/include;" @@ -152,6 +152,7 @@ if(MSVC) "${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/include;" "${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/third_party;" "${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjmedia/include" + "${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/speexdsp/include;" ) endif() @@ -224,39 +225,40 @@ if(MSVC) # Dependencies ################################################################################ - set(libAdditionalDependencies "${CMAKE_STATIC_LINKER_FLAGS} /LTCG ws2_32.lib - advapi32.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avcodec.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avdevice.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avfilter.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avformat.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avutil.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swresample.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swscale.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libgnutls.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/lib_json.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libopendht.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/argon2/vs2015/Argon2Ref/vs2015/build/Argon2Ref.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/secp256k1.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/yaml-cpp/msvc/Release/libyaml-cppmd.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/portaudio.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libupnp.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/natpmp/msvc/Release/natpmp.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-core-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-simple-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua2-lib-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua-lib-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-ua-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjmedia/lib/pjmedia-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib-util/lib/pjlib-util-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib/lib/pjlib-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjnath/lib/pjnath-x86_64-x64-vc15-Release.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/fmt/msvc/Release/fmt.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/http_parser/x64/Release/http-parser.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/asio/asio/msvc/x64/Release/asio.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/libeay32.lib - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/ssleay32.lib - /ignore:4006 + set(libAdditionalDependencies "${CMAKE_STATIC_LINKER_FLAGS} /LTCG ws2_32.lib + advapi32.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avcodec.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avdevice.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avfilter.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avformat.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/avutil.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swresample.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/ffmpeg/Build/win32/x64/bin/swscale.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libgnutls.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/lib_json.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libopendht.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/argon2/vs2015/Argon2Ref/vs2015/build/Argon2Ref.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/secp256k1.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/yaml-cpp/msvc/Release/libyaml-cppmd.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/portaudio.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/msvc/lib/x64/libupnp.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/natpmp/msvc/Release/natpmp.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-core-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-simple-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua2-lib-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsua-lib-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjsip/lib/pjsip-ua-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjmedia/lib/pjmedia-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib-util/lib/pjlib-util-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjlib/lib/pjlib-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/pjproject/pjnath/lib/pjnath-x86_64-x64-vc15-Release.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/fmt/msvc/Release/fmt.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/http_parser/x64/Release/http-parser.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/asio/asio/msvc/x64/Release/asio.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/libeay32.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/openssl/out32dll/ssleay32.lib + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/build/speexdsp/lib/libspeexdsp.lib + /ignore:4006 " ) diff --git a/compat/msvc/package.json b/compat/msvc/package.json index 591abff160ffb376a0f701bd9346bb43e89dc4fa..0aea6554ee0ac515c93945d4f61138a2a01edf5c 100644 --- a/compat/msvc/package.json +++ b/compat/msvc/package.json @@ -8,9 +8,10 @@ "pjproject", "portaudio", "secp256k1", + "speexdsp", "upnp", "yaml-cpp" ], "configuration": "ReleaseLib_win32", "project_paths": ["ring-daemon.vcxproj"] -} \ No newline at end of file +} diff --git a/contrib/src/speexdsp/package.json b/contrib/src/speexdsp/package.json new file mode 100644 index 0000000000000000000000000000000000000000..95d427120ba40baebf00b5bb4621418d46a567c6 --- /dev/null +++ b/contrib/src/speexdsp/package.json @@ -0,0 +1,15 @@ +{ + "name": "speexdsp", + "version": "SpeexDSP-1.2.0", + "url": "https://github.com/xiph/speexdsp/archive/__VERSION__.tar.gz", + "deps": [], + "patches": ["speexdsp_vs_proj.patch"], + "win_patches": [], + "project_paths": ["win32/msvc/libspeexdsp/libspeexdsp.vcxproj"], + "with_env" : "", + "custom_scripts": { + "pre_build": [], + "build": [], + "post_build": [] + } +} \ No newline at end of file diff --git a/contrib/src/speexdsp/speexdsp_vs_proj.patch b/contrib/src/speexdsp/speexdsp_vs_proj.patch new file mode 100644 index 0000000000000000000000000000000000000000..8165ab5f66ab93f305a557a3206bb4c96ec11e59 --- /dev/null +++ b/contrib/src/speexdsp/speexdsp_vs_proj.patch @@ -0,0 +1,398 @@ +From ba88ffed7a018d37661c9574f98f4246cdf6031c Mon Sep 17 00:00:00 2001 +From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> +Date: Wed, 19 Feb 2020 16:14:02 -0500 +Subject: [PATCH] b + +--- + win32/msvc/libspeexdsp/libspeexdsp.vcxproj | 378 +++++++++++++++++++++++++++++ + 1 file changed, 378 insertions(+) + create mode 100644 win32/msvc/libspeexdsp/libspeexdsp.vcxproj + +diff --git a/win32/msvc/libspeexdsp/libspeexdsp.vcxproj b/win32/msvc/libspeexdsp/libspeexdsp.vcxproj +new file mode 100644 +index 0000000..071c9b3 +--- /dev/null ++++ b/win32/msvc/libspeexdsp/libspeexdsp.vcxproj +@@ -0,0 +1,378 @@ ++<?xml version="1.0" encoding="utf-8"?> ++<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> ++ <ItemGroup Label="ProjectConfigurations"> ++ <ProjectConfiguration Include="Debug|Win32"> ++ <Configuration>Debug</Configuration> ++ <Platform>Win32</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Debug|x64"> ++ <Configuration>Debug</Configuration> ++ <Platform>x64</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Release_Dynamic_SSE|Win32"> ++ <Configuration>Release_Dynamic_SSE</Configuration> ++ <Platform>Win32</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Release_Dynamic_SSE|x64"> ++ <Configuration>Release_Dynamic_SSE</Configuration> ++ <Platform>x64</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Release_Static_SSE|Win32"> ++ <Configuration>Release_Static_SSE</Configuration> ++ <Platform>Win32</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Release_Static_SSE|x64"> ++ <Configuration>Release_Static_SSE</Configuration> ++ <Platform>x64</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Release|Win32"> ++ <Configuration>Release</Configuration> ++ <Platform>Win32</Platform> ++ </ProjectConfiguration> ++ <ProjectConfiguration Include="Release|x64"> ++ <Configuration>Release</Configuration> ++ <Platform>x64</Platform> ++ </ProjectConfiguration> ++ </ItemGroup> ++ <PropertyGroup Label="Globals"> ++ <ProjectGuid>{03207781-0D1C-4DB3-A71D-45C608F28DBD}</ProjectGuid> ++ <Keyword>Win32Proj</Keyword> ++ </PropertyGroup> ++ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|Win32'" Label="Configuration"> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|x64'" Label="Configuration"> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|Win32'" Label="Configuration"> ++ <ConfigurationType>DynamicLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|x64'" Label="Configuration"> ++ <ConfigurationType>DynamicLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ <WholeProgramOptimization>true</WholeProgramOptimization> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> ++ <ConfigurationType>StaticLibrary</ConfigurationType> ++ <PlatformToolset>v141</PlatformToolset> ++ <CharacterSet>MultiByte</CharacterSet> ++ </PropertyGroup> ++ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> ++ <ImportGroup Label="ExtensionSettings"> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|Win32'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|x64'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|Win32'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|x64'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> ++ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> ++ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> ++ </ImportGroup> ++ <PropertyGroup Label="UserMacros" /> ++ <PropertyGroup> ++ <_ProjectFileVersion>15.0.28127.55</_ProjectFileVersion> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> ++ <OutDir>Debug\</OutDir> ++ <IntDir>Debug\</IntDir> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" /> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> ++ <OutDir>$(Configuration)\</OutDir> ++ <IntDir>$(Configuration)\</IntDir> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|Win32'"> ++ <OutDir>$(Configuration)\</OutDir> ++ <IntDir>$(Configuration)\</IntDir> ++ </PropertyGroup> ++ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|Win32'"> ++ <OutDir>$(Configuration)\</OutDir> ++ <IntDir>$(Configuration)\</IntDir> ++ </PropertyGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> ++ <ClCompile> ++ <Optimization>Disabled</Optimization> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <MinimalRebuild>true</MinimalRebuild> ++ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> ++ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> ++ <PrecompiledHeader /> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>EditAndContinue</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ </ClCompile> ++ <Lib> ++ <OutputFile>../../../lib/libspeexdsp.lib</OutputFile> ++ </Lib> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> ++ <ClCompile> ++ <Optimization>Disabled</Optimization> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> ++ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> ++ <PrecompiledHeader> ++ </PrecompiledHeader> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ </ClCompile> ++ <Lib> ++ <OutputFile>../../../lib/libspeexdsp.lib</OutputFile> ++ </Lib> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> ++ <ClCompile> ++ <Optimization>Full</Optimization> ++ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> ++ <IntrinsicFunctions>true</IntrinsicFunctions> ++ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <ExceptionHandling /> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <BufferSecurityCheck>false</BufferSecurityCheck> ++ <PrecompiledHeader /> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ <DisableSpecificWarnings>4244;4305;4311;4100;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings> ++ </ClCompile> ++ <Lib> ++ <OutputFile>../../../lib/libspeexdsp.lib</OutputFile> ++ </Lib> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> ++ <ClCompile> ++ <Optimization>Full</Optimization> ++ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> ++ <IntrinsicFunctions>true</IntrinsicFunctions> ++ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <ExceptionHandling> ++ </ExceptionHandling> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <BufferSecurityCheck>false</BufferSecurityCheck> ++ <PrecompiledHeader> ++ </PrecompiledHeader> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ <DisableSpecificWarnings>4244;4305;4311;4100;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings> ++ </ClCompile> ++ <Lib> ++ <OutputFile>../../../lib/libspeexdsp.lib</OutputFile> ++ </Lib> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|Win32'"> ++ <ClCompile> ++ <Optimization>Full</Optimization> ++ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> ++ <IntrinsicFunctions>true</IntrinsicFunctions> ++ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>USE_SSE;WIN32;NDEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <ExceptionHandling /> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <BufferSecurityCheck>false</BufferSecurityCheck> ++ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet> ++ <PrecompiledHeader /> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ <DisableSpecificWarnings>4244;4305;4311;4100;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings> ++ </ClCompile> ++ <Link> ++ <OutputFile>../../../bin/libspeexdsp.dll</OutputFile> ++ <ModuleDefinitionFile>..\..\libspeexdsp.def</ModuleDefinitionFile> ++ <SubSystem>Windows</SubSystem> ++ <OptimizeReferences>true</OptimizeReferences> ++ <EnableCOMDATFolding>true</EnableCOMDATFolding> ++ <RandomizedBaseAddress>false</RandomizedBaseAddress> ++ <DataExecutionPrevention /> ++ <ImportLibrary>../../../lib/libspeexdsp.lib</ImportLibrary> ++ <TargetMachine>MachineX86</TargetMachine> ++ </Link> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_Dynamic_SSE|x64'"> ++ <ClCompile> ++ <Optimization>Full</Optimization> ++ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> ++ <IntrinsicFunctions>true</IntrinsicFunctions> ++ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>USE_SSE;WIN32;NDEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <ExceptionHandling> ++ </ExceptionHandling> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <BufferSecurityCheck>false</BufferSecurityCheck> ++ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet> ++ <PrecompiledHeader> ++ </PrecompiledHeader> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ <DisableSpecificWarnings>4244;4305;4311;4100;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings> ++ </ClCompile> ++ <Link> ++ <OutputFile>../../../bin/libspeexdsp.dll</OutputFile> ++ <ModuleDefinitionFile>..\..\libspeexdsp.def</ModuleDefinitionFile> ++ <SubSystem>Windows</SubSystem> ++ <OptimizeReferences>true</OptimizeReferences> ++ <EnableCOMDATFolding>true</EnableCOMDATFolding> ++ <RandomizedBaseAddress>false</RandomizedBaseAddress> ++ <DataExecutionPrevention> ++ </DataExecutionPrevention> ++ <ImportLibrary>../../../lib/libspeexdsp.lib</ImportLibrary> ++ </Link> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|Win32'"> ++ <ClCompile> ++ <Optimization>Full</Optimization> ++ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> ++ <IntrinsicFunctions>true</IntrinsicFunctions> ++ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>USE_SSE;WIN32;NDEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <ExceptionHandling /> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <BufferSecurityCheck>false</BufferSecurityCheck> ++ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet> ++ <PrecompiledHeader /> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ <DisableSpecificWarnings>4244;4305;4311;4100;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings> ++ </ClCompile> ++ <Lib> ++ <OutputFile>../../../lib/libspeexdsp.lib</OutputFile> ++ </Lib> ++ </ItemDefinitionGroup> ++ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static_SSE|x64'"> ++ <ClCompile> ++ <Optimization>Full</Optimization> ++ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> ++ <IntrinsicFunctions>true</IntrinsicFunctions> ++ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> ++ <AdditionalIncludeDirectories>..\..\..\include;..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> ++ <PreprocessorDefinitions>USE_SSE;WIN32;NDEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> ++ <StringPooling>true</StringPooling> ++ <ExceptionHandling> ++ </ExceptionHandling> ++ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> ++ <BufferSecurityCheck>false</BufferSecurityCheck> ++ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet> ++ <PrecompiledHeader> ++ </PrecompiledHeader> ++ <WarningLevel>Level3</WarningLevel> ++ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> ++ <CompileAs>CompileAsC</CompileAs> ++ <DisableSpecificWarnings>4244;4305;4311;4100;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings> ++ </ClCompile> ++ <Lib> ++ <OutputFile>../../../lib/libspeexdsp.lib</OutputFile> ++ </Lib> ++ </ItemDefinitionGroup> ++ <ItemGroup> ++ <ClCompile Include="..\..\..\libspeexdsp\buffer.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\fftwrap.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\filterbank.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\jitter.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\kiss_fft.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\kiss_fftr.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\mdf.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\preprocess.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\resample.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\scal.c" /> ++ <ClCompile Include="..\..\..\libspeexdsp\smallft.c" /> ++ </ItemGroup> ++ <ItemGroup> ++ <ClInclude Include="..\..\..\include\speex\speex.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_bits.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_buffer.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_echo.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_jitter.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_preprocess.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_resampler.h" /> ++ <ClInclude Include="..\..\..\include\speex\speex_types.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\arch.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\fftwrap.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\filterbank.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\fixed_debug.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\fixed_generic.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\kiss_fft.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\kiss_fftr.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\math_approx.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\os_support.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\pseudofloat.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\smallft.h" /> ++ <ClInclude Include="..\..\..\libspeexdsp\_kiss_fft_guts.h" /> ++ <ClInclude Include="..\..\config.h" /> ++ </ItemGroup> ++ <ItemGroup> ++ <None Include="..\..\libspeexdsp.def" /> ++ </ItemGroup> ++ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> ++ <ImportGroup Label="ExtensionTargets"> ++ </ImportGroup> ++</Project> +\ No newline at end of file +-- +2.7.4 + diff --git a/src/client/videomanager.cpp b/src/client/videomanager.cpp index 2eec2b14a9d2d2306524e5d379da79b11e99389e..672283b8c1ec8992a5a80b17003f2694df1001c1 100644 --- a/src/client/videomanager.cpp +++ b/src/client/videomanager.cpp @@ -107,6 +107,22 @@ AudioFrame::setFormat(const jami::AudioFormat& format) d->format = format.sampleFormat; } +jami::AudioFormat +AudioFrame::getFormat() const +{ + return { + (unsigned)frame_->sample_rate, + (unsigned)frame_->channels, + (AVSampleFormat)frame_->format + }; +} + +size_t +AudioFrame::getFrameSize() const +{ + return frame_->nb_samples; +} + void AudioFrame::reserve(size_t nb_samples) { diff --git a/src/dring/videomanager_interface.h b/src/dring/videomanager_interface.h index aa37b776ad0b7dab9a26363bd68e1e37113d19ee..c9e35138f7ef50ef1b07387a1317f6854b523a90 100644 --- a/src/dring/videomanager_interface.h +++ b/src/dring/videomanager_interface.h @@ -107,6 +107,8 @@ public: ~AudioFrame() {}; void mix(const AudioFrame& o); float calcRMS() const; + jami::AudioFormat getFormat() const; + size_t getFrameSize() const; private: void setFormat(const jami::AudioFormat& format); diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp index ebef086b7b1694e4ba03164a9b21938a769ccaa9..72699878981f71f7582b531293e3df635136e3a5 100644 --- a/src/media/audio/alsa/alsalayer.cpp +++ b/src/media/audio/alsa/alsalayer.cpp @@ -99,7 +99,6 @@ AlsaLayer::AlsaLayer(const AudioPreference &pref) , is_playback_open_(false) , is_capture_open_(false) , audioThread_(nullptr) - , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) {} AlsaLayer::~AlsaLayer() @@ -702,10 +701,7 @@ void AlsaLayer::capture() const int framesPerBufferAlsa = 2048; toGetFrames = std::min(framesPerBufferAlsa, toGetFrames); if (auto r = read(toGetFrames)) { - if (isCaptureMuted_) - libav_utils::fillWithSilence(r->pointer()); - //dcblocker_.process(captureBuff_); - mainRingBuffer_->put(std::move(r)); + putRecorded(std::move(r)); } else JAMI_ERR("ALSA MIC : Couldn't read!"); } diff --git a/src/media/audio/alsa/alsalayer.h b/src/media/audio/alsa/alsalayer.h index 6837fe0505f5a5996c6354f77b106180653c2707..e28aaf2e51bbf2f6a22b16919a26c4fa6636eed9 100644 --- a/src/media/audio/alsa/alsalayer.h +++ b/src/media/audio/alsa/alsalayer.h @@ -250,7 +250,6 @@ class AlsaLayer : public AudioLayer { bool is_capture_open_; std::unique_ptr<AlsaThread> audioThread_; - std::shared_ptr<RingBuffer> mainRingBuffer_; }; } // namespace jami diff --git a/src/media/audio/audio_frame_resizer.cpp b/src/media/audio/audio_frame_resizer.cpp index 5e05749f11389b2905a74c7271bda22d20e6e389..43dfbf4e475e8cb62cc0e54002fdd7fb920a105f 100644 --- a/src/media/audio/audio_frame_resizer.cpp +++ b/src/media/audio/audio_frame_resizer.cpp @@ -123,7 +123,7 @@ AudioFrameResizer::dequeue() if (samples() < frameSize_) return {}; - auto frame = std::make_unique<AudioFrame>(format_, frameSize_); + auto frame = std::make_shared<AudioFrame>(format_, frameSize_); int ret; if ((ret = av_audio_fifo_read(queue_, reinterpret_cast<void**>(frame->pointer()->data), frameSize_)) < 0) { JAMI_ERR() << "Could not read samples from queue: " << libav_utils::getError(ret); diff --git a/src/media/audio/audio_input.cpp b/src/media/audio/audio_input.cpp index dfecac6cec8e92796c5567a299ca078ce59a5d55..1d07c5d51b32742afcc4b069681b871dadc1dc0d 100644 --- a/src/media/audio/audio_input.cpp +++ b/src/media/audio/audio_input.cpp @@ -323,7 +323,7 @@ AudioInput::createDecoder() } auto decoder = std::make_unique<MediaDecoder>([this](std::shared_ptr<MediaFrame>&& frame) { - fileBuf_->put(std::move(std::static_pointer_cast<AudioFrame>(frame))); + fileBuf_->put(std::static_pointer_cast<AudioFrame>(frame)); }); // NOTE don't emulate rate, file is read as frames are needed diff --git a/src/media/audio/audio_receive_thread.cpp b/src/media/audio/audio_receive_thread.cpp index 895978bf7bfcb105dea56c01f7379686c21a7d66..a5937217beac8c45f627d357a6e96b5b00d4f07f 100644 --- a/src/media/audio/audio_receive_thread.cpp +++ b/src/media/audio/audio_receive_thread.cpp @@ -59,7 +59,7 @@ AudioReceiveThread::setup() { audioDecoder_.reset(new MediaDecoder([this](std::shared_ptr<MediaFrame>&& frame) mutable { notify(frame); - ringbuffer_->put(std::move(std::static_pointer_cast<AudioFrame>(frame))); + ringbuffer_->put(std::static_pointer_cast<AudioFrame>(frame)); })); audioDecoder_->setInterruptCallback(interruptCb, this); diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp index 0cc5f2ec18e6a58676a01ad15ac2047b761b4452..80ddb2ef7c77ba7bfaf5d80b59335f35561f7d06 100644 --- a/src/media/audio/audiolayer.cpp +++ b/src/media/audio/audiolayer.cpp @@ -28,21 +28,88 @@ #include "tonecontrol.h" #include "client/ring_signal.h" +extern "C" { +#include <speex/speex_echo.h> +} + #include <ctime> #include <algorithm> namespace jami { +struct AudioLayer::EchoState +{ + EchoState(AudioFormat format, unsigned frameSize, unsigned tailLength) + : state(speex_echo_state_init_mc( + frameSize, frameSize * 16, + format.nb_channels, format.nb_channels), &speex_echo_state_destroy) + , playbackQueue(format, frameSize) + , recordQueue(format, frameSize) { + int sr = format.sample_rate; + speex_echo_ctl(state.get(), SPEEX_ECHO_SET_SAMPLING_RATE, &sr); + } + + void putRecorded(std::shared_ptr<AudioFrame>&& in) { + // JAMI_DBG("putRecorded %s %d", in->getFormat().toString().c_str(), in->getFrameSize()); + recordQueue.enqueue(std::move(in)); + } + + void putPlayback(const std::shared_ptr<AudioFrame>& in) { + // JAMI_DBG("putPlayback %s %d", in->getFormat().toString().c_str(), in->getFrameSize()); + auto c = in; + playbackQueue.enqueue(std::move(c)); + } + + std::shared_ptr<AudioFrame> getRecorded() { + if (playbackQueue.samples() < playbackQueue.frameSize() + or recordQueue.samples() < recordQueue.frameSize()) { + /* JAMI_DBG("getRecorded underflow %d / %d, %d / %d", + playbackQueue.samples(), playbackQueue.frameSize(), + recordQueue.samples(), recordQueue.frameSize()); */ + return {}; + } + if (recordQueue.samples() > 2 * recordQueue.frameSize() && playbackQueue.samples() == 0) { + JAMI_DBG("getRecorded PLAYBACK underflow"); + return recordQueue.dequeue(); + } + while (playbackQueue.samples() > 10 * playbackQueue.frameSize()) { + JAMI_DBG("getRecorded playback underflow"); + playbackQueue.dequeue(); + } + while (recordQueue.samples() > 4 * recordQueue.frameSize()) { + JAMI_DBG("getRecorded record underflow"); + recordQueue.dequeue(); + } + auto playback = playbackQueue.dequeue(); + auto record = recordQueue.dequeue(); + if (playback and record) { + auto ret = std::make_shared<AudioFrame>(record->getFormat(), record->getFrameSize()); + speex_echo_cancellation(state.get(), + (const int16_t*)record->pointer()->data[0], + (const int16_t*)playback->pointer()->data[0], + (int16_t*)ret->pointer()->data[0]); + return ret; + } + return {}; + } + +private: + using SpeexEchoStatePtr = std::unique_ptr<SpeexEchoState, void(*)(SpeexEchoState*)>; + SpeexEchoStatePtr state; + AudioFrameResizer playbackQueue; + AudioFrameResizer recordQueue; +}; + AudioLayer::AudioLayer(const AudioPreference &pref) : isCaptureMuted_(pref.getCaptureMuted()) , isPlaybackMuted_(pref.getPlaybackMuted()) , captureGain_(pref.getVolumemic()) , playbackGain_(pref.getVolumespkr()) + , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) , audioFormat_(Manager::instance().getRingBufferPool().getInternalAudioFormat()) , audioInputFormat_(Manager::instance().getRingBufferPool().getInternalAudioFormat()) , urgentRingBuffer_("urgentRingBuffer_id", SIZEBUF, audioFormat_) , resampler_(new Resampler) - , inputResampler_(new Resampler) , lastNotificationTime_() { urgentRingBuffer_.createReadOffset(RingBufferPool::DEFAULT_ID); @@ -51,11 +118,12 @@ AudioLayer::AudioLayer(const AudioPreference &pref) AudioLayer::~AudioLayer() {} -void AudioLayer::hardwareFormatAvailable(AudioFormat playback) +void AudioLayer::hardwareFormatAvailable(AudioFormat playback, size_t bufSize) { - JAMI_DBG("Hardware audio format available : %s", playback.toString().c_str()); + JAMI_DBG("Hardware audio format available : %s %zu", playback.toString().c_str(), bufSize); audioFormat_ = Manager::instance().hardwareAudioFormatChanged(playback); urgentRingBuffer_.setFormat(audioFormat_); + nativeFrameSize_ = bufSize; } void AudioLayer::hardwareInputFormatAvailable(AudioFormat capture) @@ -86,6 +154,37 @@ void AudioLayer::flush() urgentRingBuffer_.flushAll(); } +void AudioLayer::playbackChanged(bool started) +{ + playbackStarted_ = started; + checkAEC(); +} + +void AudioLayer::recordChanged(bool started) +{ + recordStarted_ = started; + checkAEC(); +} + +void AudioLayer::setHasNativeAEC(bool hasEAC) +{ + hasNativeAEC_ = hasEAC; + checkAEC(); +} + +void AudioLayer::checkAEC() +{ + bool shouldSoftAEC = not hasNativeAEC_ and playbackStarted_ and recordStarted_; + + if (not echoState_ and shouldSoftAEC) { + JAMI_WARN("Starting AEC"); + echoState_.reset(new EchoState(audioFormat_, nativeFrameSize_, audioFormat_.sample_rate / 4)); + } else if (echoState_ and not shouldSoftAEC) { + JAMI_WARN("Stopping AEC"); + echoState_.reset(); + } +} + void AudioLayer::putUrgent(AudioBuffer& buffer) { std::lock_guard<std::mutex> lock(mutex_); @@ -153,19 +252,44 @@ AudioLayer::getToPlay(AudioFormat format, size_t writableSamples) std::shared_ptr<AudioFrame> playbackBuf {}; while (!(playbackBuf = playbackQueue_->dequeue())) { + std::shared_ptr<AudioFrame> resampled; + if (auto urgentSamples = urgentRingBuffer_.get(RingBufferPool::DEFAULT_ID)) { bufferPool.discard(1, RingBufferPool::DEFAULT_ID); - playbackQueue_->enqueue(resampler_->resample(std::move(urgentSamples),format)); + resampled = resampler_->resample(std::move(urgentSamples),format); } else if (auto toneToPlay = Manager::instance().getTelephoneTone()) { - playbackQueue_->enqueue(resampler_->resample(toneToPlay->getNext(), format)); + resampled = resampler_->resample(toneToPlay->getNext(), format); } else if (auto buf = bufferPool.getData(RingBufferPool::DEFAULT_ID)) { - playbackQueue_->enqueue(resampler_->resample(std::move(buf), format)); + resampled = resampler_->resample(std::move(buf), format); } else { break; } + + if (resampled) { + if (echoState_) { + echoState_->putPlayback(resampled); + } + playbackQueue_->enqueue(std::move(resampled)); + } else + break; } return playbackBuf; } +void +AudioLayer::putRecorded(std::shared_ptr<AudioFrame>&& frame) +{ + //if (isCaptureMuted_) + // libav_utils::fillWithSilence(frame->pointer()); + + if (echoState_) { + echoState_->putRecorded(std::move(frame)); + while (auto rec = echoState_->getRecorded()) + mainRingBuffer_->put(std::move(rec)); + } else { + mainRingBuffer_->put(std::move(frame)); + } +} + } // namespace jami diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h index 039ee5e5a72394e963f28a6508fa9acb19a5ab04..00b8525a0317f2dc5211a78bcb68f5a57c60155b 100644 --- a/src/media/audio/audiolayer.h +++ b/src/media/audio/audiolayer.h @@ -33,6 +33,11 @@ #include <atomic> #include <condition_variable> +extern "C" { +struct SpeexEchoState_; +typedef struct SpeexEchoState_ SpeexEchoState; +} + /** * @file audiolayer.h * @brief Main sound class. Manages the data transfers between the application and the hardware. @@ -223,7 +228,7 @@ protected: /** * Callback to be called by derived classes when the audio output is opened. */ - void hardwareFormatAvailable(AudioFormat playback); + void hardwareFormatAvailable(AudioFormat playback, size_t bufSize = 0); /** * Set the input format on necessary objects. @@ -232,6 +237,10 @@ protected: void devicesChanged(); + void playbackChanged(bool started); + void recordChanged(bool started); + void setHasNativeAEC(bool hasEAC); + std::shared_ptr<AudioFrame> getToPlay(AudioFormat format, size_t writableSamples); std::shared_ptr<AudioFrame> getToRing(AudioFormat format, size_t writableSamples); @@ -242,6 +251,8 @@ protected: return ringBuff ? ringBuff : playBuff; } + void putRecorded(std::shared_ptr<AudioFrame>&& frame); + void flush(); /** @@ -259,6 +270,10 @@ protected: */ bool isRingtoneMuted_ {false}; + bool playbackStarted_ {false}; + bool recordStarted_ {false}; + bool hasNativeAEC_ {true}; + /** * Gain applied to mic signal */ @@ -272,10 +287,8 @@ protected: /** * Buffers for audio processing */ - AudioBuffer playbackBuffer_; - AudioBuffer playbackResampleBuffer_; + std::shared_ptr<RingBuffer> mainRingBuffer_; AudioBuffer ringtoneBuffer_; - AudioBuffer ringtoneResampleBuffer_; std::unique_ptr<AudioFrameResizer> playbackQueue_; /** @@ -294,6 +307,8 @@ protected: */ AudioFormat audioInputFormat_; + size_t nativeFrameSize_ {0}; + /** * Urgent ring buffer used for ringtones */ @@ -314,12 +329,11 @@ protected: */ std::unique_ptr<Resampler> resampler_; - /** - * Manage input sampling rate conversions - */ - std::unique_ptr<Resampler> inputResampler_; + struct EchoState; + std::unique_ptr<EchoState> echoState_; private: + void checkAEC(); /** * Time of the last incoming call notification diff --git a/src/media/audio/coreaudio/ios/corelayer.h b/src/media/audio/coreaudio/ios/corelayer.h index 90fccb49a67179f4821bd740d37067f548f4032a..55ac4fbfcac73aa5e5e95cb5e8ce84823784ee32 100644 --- a/src/media/audio/coreaudio/ios/corelayer.h +++ b/src/media/audio/coreaudio/ios/corelayer.h @@ -165,8 +165,6 @@ class CoreLayer : public AudioLayer { UInt32 inChannelsPerFrame_; Float64 outSampleRate_; UInt32 outChannelsPerFrame_; - - std::shared_ptr<RingBuffer> mainRingBuffer_; }; } // namespace jami diff --git a/src/media/audio/coreaudio/ios/corelayer.mm b/src/media/audio/coreaudio/ios/corelayer.mm index d547c3f87968661f73e0075f63cbe977571beba8..2188f27e64784935a904dfb81e1afe64ba2fcada 100644 --- a/src/media/audio/coreaudio/ios/corelayer.mm +++ b/src/media/audio/coreaudio/ios/corelayer.mm @@ -43,7 +43,6 @@ CoreLayer::CoreLayer(const AudioPreference &pref) , indexOut_(pref.getAlsaCardout()) , indexRing_(pref.getAlsaCardring()) , playbackBuff_(0, audioFormat_) - , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) {} CoreLayer::~CoreLayer() @@ -440,7 +439,7 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, auto format = audioInputFormat_; format.sampleFormat = AV_SAMPLE_FMT_FLTP; - auto inBuff = std::make_unique<AudioFrame>(format, inNumberFrames); + auto inBuff = std::make_shared<AudioFrame>(format, inNumberFrames); if (isCaptureMuted_) { libav_utils::fillWithSilence(inBuff->pointer()); } else { @@ -448,7 +447,7 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, for (unsigned i = 0; i < inChannelsPerFrame_; ++i) std::copy_n((Float32*)captureBuff_->mBuffers[i].mData, inNumberFrames, (Float32*)in.extended_data[i]); } - mainRingBuffer_->put(std::move(inBuff)); + putRecorded(std::move(inBuff)); } void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) diff --git a/src/media/audio/coreaudio/osx/corelayer.cpp b/src/media/audio/coreaudio/osx/corelayer.cpp index 853a648db740bb85a8dd8526fc1dff08fdfffb6e..72e8242b9f20ddd2f816189481ebbac2e2cc0c58 100644 --- a/src/media/audio/coreaudio/osx/corelayer.cpp +++ b/src/media/audio/coreaudio/osx/corelayer.cpp @@ -38,7 +38,6 @@ CoreLayer::CoreLayer(const AudioPreference &pref) , indexOut_(pref.getAlsaCardout()) , indexRing_(pref.getAlsaCardring()) , playbackBuff_(0, audioFormat_) - , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) {} CoreLayer::~CoreLayer() @@ -345,7 +344,7 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, auto format = audioInputFormat_; format.sampleFormat = AV_SAMPLE_FMT_FLTP; - auto inBuff = std::make_unique<AudioFrame>(format, inNumberFrames); + auto inBuff = std::make_shared<AudioFrame>(format, inNumberFrames); if (isCaptureMuted_) { libav_utils::fillWithSilence(inBuff->pointer()); } else { @@ -353,7 +352,7 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, for (unsigned i = 0; i < inChannelsPerFrame_; ++i) std::copy_n((Float32*)captureBuff_->mBuffers[i].mData, inNumberFrames, (Float32*)in.extended_data[i]); } - mainRingBuffer_->put(std::move(inBuff)); + putRecorded(std::move(inBuff)); } void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) diff --git a/src/media/audio/coreaudio/osx/corelayer.h b/src/media/audio/coreaudio/osx/corelayer.h index 9d447b2ec52ed8606172153e539fd69561075bcc..e7a827625f3ae0706486bb1ea1764a553944cefd 100644 --- a/src/media/audio/coreaudio/osx/corelayer.h +++ b/src/media/audio/coreaudio/osx/corelayer.h @@ -172,8 +172,6 @@ class CoreLayer : public AudioLayer { Float64 inSampleRate_; UInt32 inChannelsPerFrame_; - std::shared_ptr<RingBuffer> mainRingBuffer_; - std::vector<AudioDevice> getDeviceList(bool getCapture) const; }; diff --git a/src/media/audio/jack/jacklayer.cpp b/src/media/audio/jack/jacklayer.cpp index dc34dd3caeda3b938ea87a592139b4178907d1b8..3f175ba3862c02a3ac2e91ddf9e1eefb8dca9fa9 100644 --- a/src/media/audio/jack/jacklayer.cpp +++ b/src/media/audio/jack/jacklayer.cpp @@ -209,8 +209,7 @@ createPorts(jack_client_t *client, std::vector<jack_port_t *> &ports, JackLayer::JackLayer(const AudioPreference &p) : AudioLayer(p), captureClient_(nullptr), - playbackClient_(nullptr), - mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) + playbackClient_(nullptr) { playbackClient_ = jack_client_open(PACKAGE_NAME, (jack_options_t) (JackNullOption | JackNoStartServer), NULL); diff --git a/src/media/audio/jack/jacklayer.h b/src/media/audio/jack/jacklayer.h index dde32e50e444f4e4c5d4325829da2c299971765f..353ed2ecf6885bbca914b66dfc7226c95837b5ae 100644 --- a/src/media/audio/jack/jacklayer.h +++ b/src/media/audio/jack/jacklayer.h @@ -49,7 +49,6 @@ private: std::thread ringbuffer_thread_; std::mutex ringbuffer_thread_mutex_; std::condition_variable data_ready_; - std::shared_ptr<RingBuffer> mainRingBuffer_; static int process_capture(jack_nframes_t frames, void *arg); static int process_playback(jack_nframes_t frames, void *arg); diff --git a/src/media/audio/opensl/audio_player.cpp b/src/media/audio/opensl/audio_player.cpp index dfd7b3be5ef755484236d6e61ca97b46d55c1bc9..b80394e5f46abce46f23cdeddf4332c1e9ee5cb6 100644 --- a/src/media/audio/opensl/audio_player.cpp +++ b/src/media/audio/opensl/audio_player.cpp @@ -40,8 +40,6 @@ void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *ctx) { (static_cast<AudioPlayer *>(ctx))->processSLCallback(bq); } void AudioPlayer::processSLCallback(SLAndroidSimpleBufferQueueItf bq) { - std::lock_guard<std::mutex> lk(m_); - // retrieve the finished device buf and put onto the free queue // so recorder could re-use it sample_buf *buf; diff --git a/src/media/audio/opensl/audio_player.h b/src/media/audio/opensl/audio_player.h index 7fc470b8c67a9f5920cc14fe591313f09dce3f65..0e9383c8963053979fe2324f929511e220349963 100644 --- a/src/media/audio/opensl/audio_player.h +++ b/src/media/audio/opensl/audio_player.h @@ -58,7 +58,6 @@ public: void registerCallback(EngineCallback cb) {callback_ = cb;} size_t dbgGetDevBufCount(); - std::mutex m_; std::atomic_bool waiting_ {false}; }; diff --git a/src/media/audio/opensl/audio_recorder.cpp b/src/media/audio/opensl/audio_recorder.cpp index ff6e55d5f8cda0cc052e879ef80ec8a4e33b1969..699e1c60bc8989b7bc89ee326fd6ca9f6b6eb7ea 100644 --- a/src/media/audio/opensl/audio_recorder.cpp +++ b/src/media/audio/opensl/audio_recorder.cpp @@ -59,7 +59,7 @@ void AudioRecorder::processSLCallback(SLAndroidSimpleBufferQueueItf bq) { AudioRecorder::AudioRecorder(jami::AudioFormat sampleFormat, SLEngineItf slEngine) : sampleInfo_(sampleFormat) { - // configure audio source + // configure audio source/ SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, @@ -76,7 +76,13 @@ AudioRecorder::AudioRecorder(jami::AudioFormat sampleFormat, SLEngineItf slEngin // create audio recorder // (requires the RECORD_AUDIO permission) - const SLInterfaceID ids[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION}; + const SLInterfaceID ids[] = { + SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + SL_IID_ANDROIDCONFIGURATION, + SL_IID_ANDROIDACOUSTICECHOCANCELLATION, + SL_IID_ANDROIDAUTOMATICGAINCONTROL, + SL_IID_ANDROIDNOISESUPPRESSION + }; const SLboolean req[1] = {SL_BOOLEAN_TRUE}; SLresult result; result = (*slEngine)->CreateAudioRecorder(slEngine, @@ -91,11 +97,85 @@ AudioRecorder::AudioRecorder(jami::AudioFormat sampleFormat, SLEngineItf slEngin result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_ANDROIDCONFIGURATION, &recordConfig); result = (*recordConfig)->SetConfiguration(recordConfig, SL_ANDROID_KEY_RECORDING_PRESET, &streamType, sizeof(SLint32)); + bool aec{true}, agc(true), ns(true); + + result = (*recObjectItf_)->Realize(recObjectItf_, SL_BOOLEAN_FALSE); SLASSERT(result); result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_RECORD, &recItf_); SLASSERT(result); + + /* Check actual performance mode granted*/ + SLuint32 modeRetrieved = SL_ANDROID_PERFORMANCE_NONE; + SLuint32 modeSize = sizeof(SLuint32); + result = (*recordConfig)->GetConfiguration(recordConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, + &modeSize, (void*)&modeRetrieved); + SLASSERT(result); + JAMI_WARN("Actual performance mode is %u\n", modeRetrieved); + + /* Enable AEC if requested */ + if (aec) { + SLAndroidAcousticEchoCancellationItf aecItf; + result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_ANDROIDACOUSTICECHOCANCELLATION, (void*)&aecItf); + JAMI_WARN("AEC is %savailable\n", SL_RESULT_SUCCESS == result ? "" : "not "); + if (SL_RESULT_SUCCESS == result) { + SLboolean enabled; + result = (*aecItf)->IsEnabled(aecItf, &enabled); + SLASSERT(result); + JAMI_WARN("AEC was %s\n", enabled ? "enabled" : "not enabled"); + + result = (*aecItf)->SetEnabled(aecItf, true); + SLASSERT(result); + + result = (*aecItf)->IsEnabled(aecItf, &enabled); + SLASSERT(result); + JAMI_WARN("AEC is now %s\n", enabled ? "enabled" : "not enabled"); + + hasNativeAEC_ = enabled; + } + } + /* Enable AGC if requested */ + if (agc) { + SLAndroidAutomaticGainControlItf agcItf; + result = (*recObjectItf_)->GetInterface( + recObjectItf_, SL_IID_ANDROIDAUTOMATICGAINCONTROL, (void*)&agcItf); + JAMI_WARN("AGC is %savailable\n", SL_RESULT_SUCCESS == result ? "" : "not "); + if (SL_RESULT_SUCCESS == result) { + SLboolean enabled; + result = (*agcItf)->IsEnabled(agcItf, &enabled); + SLASSERT(result); + JAMI_WARN("AGC was %s\n", enabled ? "enabled" : "not enabled"); + + result = (*agcItf)->SetEnabled(agcItf, true); + SLASSERT(result); + + result = (*agcItf)->IsEnabled(agcItf, &enabled); + SLASSERT(result); + JAMI_WARN("AGC is now %s\n", enabled ? "enabled" : "not enabled"); + } + } + /* Enable NS if requested */ + if (ns) { + SLAndroidNoiseSuppressionItf nsItf; + result = (*recObjectItf_)->GetInterface( + recObjectItf_, SL_IID_ANDROIDNOISESUPPRESSION, (void*)&nsItf); + JAMI_WARN("NS is %savailable\n", SL_RESULT_SUCCESS == result ? "" : "not "); + if (SL_RESULT_SUCCESS == result) { + SLboolean enabled; + result = (*nsItf)->IsEnabled(nsItf, &enabled); + SLASSERT(result); + JAMI_WARN("NS was %s\n", enabled ? "enabled" : "not enabled"); + + result = (*nsItf)->SetEnabled(nsItf, true); + SLASSERT(result); + + result = (*nsItf)->IsEnabled(nsItf, &enabled); + SLASSERT(result); + JAMI_WARN("NS is now %s\n", enabled ? "enabled" : "not enabled"); + } + } + result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recBufQueueItf_); SLASSERT(result); diff --git a/src/media/audio/opensl/audio_recorder.h b/src/media/audio/opensl/audio_recorder.h index 85cf433f2d62b0a24b01e28a9209a3e1cc7369fc..7e86bf23c5a7fd4ee2f6e871b9ff8a831438a5e5 100644 --- a/src/media/audio/opensl/audio_recorder.h +++ b/src/media/audio/opensl/audio_recorder.h @@ -40,6 +40,7 @@ class AudioRecorder { uint32_t audioBufCount; EngineCallback callback_ {}; + bool hasNativeAEC_ {false}; public: explicit AudioRecorder(jami::AudioFormat, SLEngineItf engineEngine); @@ -52,6 +53,8 @@ public: void processSLCallback(SLAndroidSimpleBufferQueueItf bq); void registerCallback(EngineCallback cb) {callback_ = cb;} size_t dbgGetDevBufCount(); + + bool hasNativeAEC() const { return hasNativeAEC_; } }; } diff --git a/src/media/audio/opensl/opensllayer.cpp b/src/media/audio/opensl/opensllayer.cpp index 79ca4f56f5f37c31c202d5f62b2b76fb15412989..445b0603f53ac2eb3030b7345382b1e42db5697b 100644 --- a/src/media/audio/opensl/opensllayer.cpp +++ b/src/media/audio/opensl/opensllayer.cpp @@ -30,25 +30,19 @@ #include "logger.h" #include "array_size.h" +#include <SLES/OpenSLES_AndroidConfiguration.h> + #include <thread> #include <chrono> #include <cstdio> #include <cassert> #include <unistd.h> -#include "SLES/OpenSLES_AndroidConfiguration.h" - -/* available only from api 14 */ -#ifndef SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION -#define SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION ((SLuint32) 0x00000004) -#endif - namespace jami { // Constructor OpenSLLayer::OpenSLLayer(const AudioPreference &pref) - : AudioLayer(pref), - mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) + : AudioLayer(pref) {} // Destructor @@ -81,7 +75,7 @@ OpenSLLayer::startStream(AudioStreamType stream) emitSignal<DRing::ConfigurationSignal::GetHardwareAudioFormat>(&hw_infos); hardwareFormat_ = AudioFormat(hw_infos[0], 1); // Mono on Android hardwareBuffSize_ = hw_infos[1]; - hardwareFormatAvailable(hardwareFormat_); + hardwareFormatAvailable(hardwareFormat_, hardwareBuffSize_); startThread_ = std::thread([this](){ init(); @@ -216,8 +210,9 @@ OpenSLLayer::engineServicePlay(bool waiting) { break; } else freePlayBufQueue_.pop(); - } else + } else { break; + } } } @@ -284,6 +279,7 @@ OpenSLLayer::initAudioCapture() recorder_.reset(new opensl::AudioRecorder(hardwareFormat_, engineInterface_)); recorder_->setBufQueues(&freeRecBufQueue_, &recBufQueue_); recorder_->registerCallback(std::bind(&OpenSLLayer::engineServiceRec, this, _1)); + setHasNativeAEC(recorder_->hasNativeAEC()); } catch (const std::exception& e) { JAMI_ERR("Error initializing audio capture: %s", e.what()); } @@ -301,24 +297,26 @@ OpenSLLayer::startAudioPlayback() if (ringtone_) ringtone_->start(); playThread = std::thread([&]() { + playbackChanged(true); std::unique_lock<std::mutex> lck(playMtx); while (player_ || ringtone_) { playCv.wait_for(lck, std::chrono::seconds(1)); if (player_ && player_->waiting_) { - std::lock_guard<std::mutex> lk(player_->m_); + //std::lock_guard<std::mutex> lk(player_->m_); engineServicePlay(false); auto n = playBufQueue_.size(); if (n >= PLAY_KICKSTART_BUFFER_COUNT) player_->playAudioBuffers(n); } if (ringtone_ && ringtone_->waiting_) { - std::lock_guard<std::mutex> lk(ringtone_->m_); + //std::lock_guard<std::mutex> lk(ringtone_->m_); engineServiceRing(false); auto n = ringBufQueue_.size(); if (n >= PLAY_KICKSTART_BUFFER_COUNT) ringtone_->playAudioBuffers(n); } } + playbackChanged(false); }); JAMI_WARN("Audio playback started"); } @@ -332,6 +330,7 @@ OpenSLLayer::startAudioCapture() recorder_->start(); recThread = std::thread([&]() { + recordChanged(true); std::unique_lock<std::mutex> lck(recMtx); while (recorder_) { recCv.wait_for(lck, std::chrono::seconds(1)); @@ -342,18 +341,18 @@ OpenSLLayer::startAudioCapture() recBufQueue_.pop(); if (buf->size_ > 0) { auto nb_samples = buf->size_ / hardwareFormat_.getBytesPerFrame(); - auto out = std::make_unique<AudioFrame>(hardwareFormat_, nb_samples); + auto out = std::make_shared<AudioFrame>(hardwareFormat_, nb_samples); if (isCaptureMuted_) libav_utils::fillWithSilence(out->pointer()); else std::copy_n((const AudioSample*)buf->buf_, nb_samples, (AudioSample*)out->pointer()->data[0]); - // dcblocker_.process(buffer); - mainRingBuffer_->put(std::move(out)); + putRecorded(std::move(out)); } buf->size_ = 0; freeRecBufQueue_.push(buf); } } + recordChanged(false); }); JAMI_DBG("Audio capture started"); diff --git a/src/media/audio/opensl/opensllayer.h b/src/media/audio/opensl/opensllayer.h index 239537b4f7b56426e1c3542b0bdb20f8879ad896..cdd8dc27cfd849c2888762a7d818cb736d2511aa 100644 --- a/src/media/audio/opensl/opensllayer.h +++ b/src/media/audio/opensl/opensllayer.h @@ -18,8 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _OPENSL_LAYER_H -#define _OPENSL_LAYER_H +#pragma once #include <SLES/OpenSLES.h> #include <SLES/OpenSLES_Android.h> @@ -52,147 +51,144 @@ class RingBuffer; */ class OpenSLLayer : public AudioLayer { - public: - /** - * Constructor - */ - OpenSLLayer(const AudioPreference &pref); +public: + /** + * Constructor + */ + OpenSLLayer(const AudioPreference &pref); - /** - * Destructor - */ - ~OpenSLLayer(); + /** + * Destructor + */ + ~OpenSLLayer(); - /** - * Start the capture stream and prepare the playback stream. - * The playback starts accordingly to its threshold - */ - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); - - /** - * Stop the playback and capture streams. - * Drops the pending frames and put the capture and playback handles to PREPARED state - */ - virtual void stopStream(); + /** + * Start the capture stream and prepare the playback stream. + * The playback starts accordingly to its threshold + */ + virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); + + /** + * Stop the playback and capture streams. + * Drops the pending frames and put the capture and playback handles to PREPARED state + */ + virtual void stopStream(); - /** - * Scan the sound card available for capture on the system - * @return std::vector<std::string> The vector containing the string description of the card - */ - virtual std::vector<std::string> getCaptureDeviceList() const; + /** + * Scan the sound card available for capture on the system + * @return std::vector<std::string> The vector containing the string description of the card + */ + virtual std::vector<std::string> getCaptureDeviceList() const; - /** - * Scan the sound card available for capture on the system - * @return std::vector<std::string> The vector containing the string description of the card - */ - virtual std::vector<std::string> getPlaybackDeviceList() const; + /** + * Scan the sound card available for capture on the system + * @return std::vector<std::string> The vector containing the string description of the card + */ + virtual std::vector<std::string> getPlaybackDeviceList() const; - void init(); + void init(); - void initAudioEngine(); + void initAudioEngine(); - void shutdownAudioEngine(); + void shutdownAudioEngine(); - void initAudioPlayback(); + void initAudioPlayback(); - void initAudioCapture(); + void initAudioCapture(); - void startAudioPlayback(); + void startAudioPlayback(); - void startAudioCapture(); + void startAudioCapture(); - void stopAudioPlayback(); + void stopAudioPlayback(); - void stopAudioCapture(); + void stopAudioCapture(); - virtual int getAudioDeviceIndex(const std::string&, DeviceType) const { - return 0; - } + virtual int getAudioDeviceIndex(const std::string&, DeviceType) const { + return 0; + } - virtual std::string getAudioDeviceName(int, DeviceType) const { - return ""; - } + virtual std::string getAudioDeviceName(int, DeviceType) const { + return ""; + } - void engineServicePlay(bool waiting); - void engineServiceRing(bool waiting); - void engineServiceRec(bool waiting); + void engineServicePlay(bool waiting); + void engineServiceRing(bool waiting); + void engineServiceRec(bool waiting); - private: - /** - * Get the index of the audio card for capture - * @return int The index of the card used for capture - * 0 for the first available card on the system, 1 ... - */ - virtual int getIndexCapture() const { - return 0; - } +private: + /** + * Get the index of the audio card for capture + * @return int The index of the card used for capture + * 0 for the first available card on the system, 1 ... + */ + virtual int getIndexCapture() const { + return 0; + } - /** - * Get the index of the audio card for playback - * @return int The index of the card used for playback - * 0 for the first available card on the system, 1 ... - */ - virtual int getIndexPlayback() const { - return 0; - } + /** + * Get the index of the audio card for playback + * @return int The index of the card used for playback + * 0 for the first available card on the system, 1 ... + */ + virtual int getIndexPlayback() const { + return 0; + } - /** - * Get the index of the audio card for ringtone (could be differnet from playback) - * @return int The index of the card used for ringtone - * 0 for the first available card on the system, 1 ... - */ - virtual int getIndexRingtone() const { - return 0; - } + /** + * Get the index of the audio card for ringtone (could be differnet from playback) + * @return int The index of the card used for ringtone + * 0 for the first available card on the system, 1 ... + */ + virtual int getIndexRingtone() const { + return 0; + } - uint32_t dbgEngineGetBufCount(); + uint32_t dbgEngineGetBufCount(); - void dumpAvailableEngineInterfaces(); + void dumpAvailableEngineInterfaces(); - NON_COPYABLE(OpenSLLayer); + NON_COPYABLE(OpenSLLayer); - virtual void updatePreference(AudioPreference &pref, int index, DeviceType type); + virtual void updatePreference(AudioPreference &pref, int index, DeviceType type); - /** - * OpenSL standard object interface - */ - SLObjectItf engineObject_ {nullptr}; + /** + * OpenSL standard object interface + */ + SLObjectItf engineObject_ {nullptr}; - /** - * OpenSL sound engine interface - */ - SLEngineItf engineInterface_ {nullptr}; + /** + * OpenSL sound engine interface + */ + SLEngineItf engineInterface_ {nullptr}; - std::unique_ptr<opensl::AudioPlayer> player_ {}; - std::unique_ptr<opensl::AudioPlayer> ringtone_ {}; - std::unique_ptr<opensl::AudioRecorder> recorder_ {}; + std::unique_ptr<opensl::AudioPlayer> player_ {}; + std::unique_ptr<opensl::AudioPlayer> ringtone_ {}; + std::unique_ptr<opensl::AudioRecorder> recorder_ {}; - AudioQueue freePlayBufQueue_ {BUF_COUNT}; - AudioQueue playBufQueue_ {BUF_COUNT}; + AudioQueue freePlayBufQueue_ {BUF_COUNT}; + AudioQueue playBufQueue_ {BUF_COUNT}; - AudioQueue freeRingBufQueue_ {BUF_COUNT}; - AudioQueue ringBufQueue_ {BUF_COUNT}; + AudioQueue freeRingBufQueue_ {BUF_COUNT}; + AudioQueue ringBufQueue_ {BUF_COUNT}; - std::mutex playMtx {}; - std::condition_variable playCv {}; - std::thread playThread {}; + std::mutex playMtx {}; + std::condition_variable playCv {}; + std::thread playThread {}; - AudioQueue freeRecBufQueue_ {BUF_COUNT}; //Owner of the queue - AudioQueue recBufQueue_ {BUF_COUNT}; //Owner of the queue + AudioQueue freeRecBufQueue_ {BUF_COUNT}; //Owner of the queue + AudioQueue recBufQueue_ {BUF_COUNT}; //Owner of the queue - std::mutex recMtx {}; - std::condition_variable recCv {}; - std::thread recThread {}; + std::mutex recMtx {}; + std::condition_variable recCv {}; + std::thread recThread {}; - std::vector<sample_buf> bufs_ {}; + std::vector<sample_buf> bufs_ {}; - AudioFormat hardwareFormat_ {AudioFormat::MONO()}; - size_t hardwareBuffSize_ {BUFFER_SIZE}; + AudioFormat hardwareFormat_ {AudioFormat::MONO()}; + size_t hardwareBuffSize_ {BUFFER_SIZE}; - std::shared_ptr<RingBuffer> mainRingBuffer_; - std::thread startThread_; + std::thread startThread_; }; } - -#endif // _OPENSL_LAYER_H_ diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp index d567dad89ffac0156009923f28510c0d2556be7b..d36722d208ad8d541fcc84124d972ed12ddeaf3c 100644 --- a/src/media/audio/portaudio/portaudiolayer.cpp +++ b/src/media/audio/portaudio/portaudiolayer.cpp @@ -33,6 +33,8 @@ #include <cmath> namespace jami { + +struct AudioLayer::EchoState; enum Direction { Input = 0, Output = 1, IO = 2, End = 3 }; @@ -55,8 +57,6 @@ struct PortAudioLayer::PortAudioLayerImpl AudioBuffer playbackBuff_; - std::shared_ptr<RingBuffer> mainRingBuffer_; - std::array<PaStream*, static_cast<int>(Direction::End)> streams_; int paOutputCallback(PortAudioLayer& parent, @@ -226,7 +226,6 @@ PortAudioLayer::PortAudioLayerImpl::PortAudioLayerImpl(PortAudioLayer& parent, c , indexOut_ {pref.getAlsaCardout()} , indexRing_ {pref.getAlsaCardring()} , playbackBuff_ {0, parent.audioFormat_} - , mainRingBuffer_ {Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)} { init(parent); } @@ -562,13 +561,13 @@ PortAudioLayer::PortAudioLayerImpl::paInputCallback(PortAudioLayer& parent, return paContinue; } - auto inBuff = std::make_unique<AudioFrame>(parent.audioInputFormat_, framesPerBuffer); + auto inBuff = std::make_shared<AudioFrame>(parent.audioInputFormat_, framesPerBuffer); auto nFrames = framesPerBuffer * parent.audioInputFormat_.nb_channels; if (parent.isCaptureMuted_) libav_utils::fillWithSilence(inBuff->pointer()); else std::copy_n(inputBuffer, nFrames, (AudioSample*)inBuff->pointer()->extended_data[0]); - mainRingBuffer_->put(std::move(inBuff)); + parent.putRecorded(std::move(inBuff)); return paContinue; } diff --git a/src/media/audio/pulseaudio/pulselayer.cpp b/src/media/audio/pulseaudio/pulselayer.cpp index 90dea49b20ac34b20fd3492f03a957999789ee8a..780d6c7c1a68d80b7b3be3e6c29eb3dc42b9f20a 100644 --- a/src/media/audio/pulseaudio/pulselayer.cpp +++ b/src/media/audio/pulseaudio/pulselayer.cpp @@ -65,7 +65,6 @@ PulseLayer::PulseLayer(AudioPreference &pref) , ringtone_() , mainloop_(pa_threaded_mainloop_new(), pa_threaded_mainloop_free) , preference_(pref) - , mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) { if (!mainloop_) throw std::runtime_error("Couldn't create pulseaudio mainloop"); @@ -456,7 +455,7 @@ void PulseLayer::readFromMic() size_t sample_size = record_->frameSize(); const size_t samples = bytes / sample_size; - auto out = std::make_unique<AudioFrame>(record_->format(), samples); + auto out = std::make_shared<AudioFrame>(record_->format(), samples); if (isCaptureMuted_) libav_utils::fillWithSilence(out->pointer()); else @@ -465,8 +464,7 @@ void PulseLayer::readFromMic() if (pa_stream_drop(record_->stream()) < 0) JAMI_ERR("Capture stream drop failed: %s" , pa_strerror(pa_context_errno(context_))); - //dcblocker_.process(*out); - mainRingBuffer_->put(std::move(out)); + putRecorded(std::move(out)); } void PulseLayer::ringtoneToSpeaker() @@ -710,20 +708,20 @@ void PulseLayer::updatePreference(AudioPreference &preference, int index, Device const std::string devName(getAudioDeviceName(index, type)); switch (type) { - case DeviceType::PLAYBACK: - JAMI_DBG("setting %s for playback", devName.c_str()); - preference.setPulseDevicePlayback(devName); - break; + case DeviceType::PLAYBACK: + JAMI_DBG("setting %s for playback", devName.c_str()); + preference.setPulseDevicePlayback(devName); + break; - case DeviceType::CAPTURE: - JAMI_DBG("setting %s for capture", devName.c_str()); - preference.setPulseDeviceRecord(devName); - break; + case DeviceType::CAPTURE: + JAMI_DBG("setting %s for capture", devName.c_str()); + preference.setPulseDeviceRecord(devName); + break; - case DeviceType::RINGTONE: - JAMI_DBG("setting %s for ringer", devName.c_str()); - preference.setPulseDeviceRingtone(devName); - break; + case DeviceType::RINGTONE: + JAMI_DBG("setting %s for ringer", devName.c_str()); + preference.setPulseDeviceRingtone(devName); + break; } } diff --git a/src/media/audio/pulseaudio/pulselayer.h b/src/media/audio/pulseaudio/pulselayer.h index 12e5601a18d4a79e7b818836e3fe8ad737ccf7a2..30541bad631976c37bb78d3722fbfdc413b135b7 100644 --- a/src/media/audio/pulseaudio/pulselayer.h +++ b/src/media/audio/pulseaudio/pulselayer.h @@ -206,18 +206,6 @@ class PulseLayer : public AudioLayer { */ std::vector<PaDeviceInfos> sourceList_ {}; - /* - * Buffers used to avoid doing malloc/free in the audio thread - */ - AudioBuffer micBuffer_; - AudioBuffer micResampleBuffer_; - - AudioBuffer playbackBuffer_; - AudioBuffer playbackResampleBuffer_; - - AudioBuffer ringtoneBuffer_; - AudioBuffer ringtoneResampleBuffer_; - /** PulseAudio server defaults */ AudioFormat defaultAudioFormat_ {AudioFormat::MONO()}; std::string defaultSink_ {}; @@ -235,7 +223,6 @@ class PulseLayer : public AudioLayer { std::thread streamStarter_ {}; AudioPreference &preference_; - std::shared_ptr<RingBuffer> mainRingBuffer_; pa_operation* subscribeOp_ {nullptr}; friend class AudioLayerTest; diff --git a/src/media/audio/ringbuffer.h b/src/media/audio/ringbuffer.h index 46032e254336064c8ab4e7129ed6ae8fffd10950..938e9c5cd84a961ef57b6c2df868c3e533a0eddf 100644 --- a/src/media/audio/ringbuffer.h +++ b/src/media/audio/ringbuffer.h @@ -91,7 +91,7 @@ public: * @param buffer Data to copied * @param toCopy Number of bytes to copy */ - void put(std::shared_ptr<AudioFrame>&& data); + void put(std::shared_ptr<AudioFrame>&& data); /** * To get how much samples are available in the buffer to read in @@ -130,6 +130,10 @@ public: return putLength() == 0; } + inline void setFrameSize(int nb_samples) { + resizer_.setFrameSize(nb_samples); + } + /** * Blocks until min_data_length samples of data is available, or until deadline has passed. * diff --git a/src/media/audio/ringbufferpool.cpp b/src/media/audio/ringbufferpool.cpp index a89e55972b79ded2a1fe543bee1e23d653da4e02..71062223e9ff3f5cd4e625020417ec7e1aa9a2e8 100644 --- a/src/media/audio/ringbufferpool.cpp +++ b/src/media/audio/ringbufferpool.cpp @@ -271,7 +271,7 @@ RingBufferPool::getData(const std::string& call_id) if (bindings->size() == 1) return (*bindings->cbegin())->get(call_id); - auto mixBuffer = std::make_unique<AudioFrame>(internalAudioFormat_); + auto mixBuffer = std::make_shared<AudioFrame>(internalAudioFormat_); for (const auto& rbuf : *bindings) { if (auto b = rbuf->get(call_id)) { mixBuffer->mix(*b); @@ -326,7 +326,7 @@ RingBufferPool::getAvailableData(const std::string& call_id) if (availableFrames == 0) return {}; - auto buf = std::make_unique<AudioFrame>(internalAudioFormat_); + auto buf = std::make_shared<AudioFrame>(internalAudioFormat_); for (const auto &rbuf : *bindings) { if (auto b = rbuf->get(call_id)) buf->mix(*b);