51 Commits
v1.2 ... master

Author SHA1 Message Date
846fe90a28 doc: Add release notes for v2.1 2025-01-22 17:32:18 -05:00
8f445c36cc meson: Bump version to 2.1 2025-01-22 17:30:47 -05:00
a24b45cc19 patches: Track some MinGW fixups 2025-01-10 15:07:56 -05:00
a9f97c9fdd Some fixes for MinGW
* Rename Windows.h uses to windows.h
  * Comment out structured exception handling usage

Makes MinGW happier. Mostly the same as previous work by
Nicolas Dufresne <nicolas.dufresne@collabora.com>, with the exception
that we now don't try to invoke RaiseException which would fail in MinGW
as it raises a Windows structured exception.
2025-01-10 15:07:34 -05:00
f8a6ea0a9a meson: Add absl_numeric as a dep
Another implicit cascading dependency.
2025-01-10 12:49:22 -05:00
222790ad57 meson: Update abseil-cpp wrap for missing headers 2025-01-10 12:01:31 -05:00
1818e5eb50 patches: Track patch for Windows builds 2025-01-09 16:36:34 -05:00
c555fb6eaf meson: Fixes for MSVC build
winsock2.h must be included before windows.h or alternative
definitions of `struct sockaddr` are defined.

```
FAILED: webrtc/rtc_base/liblibbase.a.p/logging.cc.obj
"cl" "-Iwebrtc\rtc_base\liblibbase.a.p" "-Iwebrtc\rtc_base" "-I..\webrtc\rtc_base" "-Iwebrtc" "-I..\webrtc" "-Isubprojects\abseil-cpp-20230125.1" "-I..\subprojects\abseil-cpp-20230125.1" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W2" "/EHsc" "/std:c++17" "/permissive-" "/O2" "/Zi" "-DWEBRTC_LIBRARY_
IMPL" "-DWEBRTC_ENABLE_SYMBOL_EXPORT" "-DNDEBUG" "-DWEBRTC_WIN" "-D_WIN32" "-U__STRICT_ANSI__" "-D__STDC_FORMAT_MACROS=1" "-DNOMINMAX" "-DWEBRTC_ENABLE_AVX2" "/Fdwebrtc\rtc_base\liblibbase.a.p\logging.cc.pdb" /Fowebrtc/rtc_base/liblibbase.a.p/logging.cc.obj "/c" ../webrtc/rtc_base/logging.cc
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(103): warning C4005: 'AF_IPX': macro redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(457): note: see previous definition of 'AF_IPX'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(147): warning C4005: 'AF_MAX': macro redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(476): note: see previous definition of 'AF_MAX'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(187): warning C4005: 'SO_DONTLINGER': macro redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(399): note: see previous definition of 'SO_DONTLINGER'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(240): error C2011: 'sockaddr': 'struct' type redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(482): note: see declaration of 'sockaddr'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(442): error C2143: syntax error: missing '}' before 'constant'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(442): error C2059: syntax error: 'constant'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(496): error C2143: syntax error: missing ';' before '}'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(496): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(496): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
...
```
2025-01-09 16:35:01 -05:00
845e79a2a7 meson: Install some new headers
The main header has moved to api/audio/... and there are a bunch of new
dependent headers.
2025-01-09 15:53:16 -05:00
0743cb5ce5 doc: Document changes for 2.0 2025-01-08 11:58:17 -05:00
971f026d55 doc: Backfill 1.x releases 2025-01-08 11:51:04 -05:00
774ac54e71 meson: Only disable SIMD for non-SSE machines on x86
This ended up disabling SIMD everywhere except where SSE/AVX was
enabled.
2024-12-30 16:21:20 -05:00
54a632f018 meson: Convert the 'neon' option into a feature
Easier to express things, now that runtime is a no-op.
2024-12-30 16:21:08 -05:00
d63a2c9714 meson: pffft: Warn about not having runtime neon checks
The pffft.c file does not have runtime checks for NEON, and silently
falls back to disabling it when the neon option is 'runtime'. Print a
warning in this case.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:19:07 -05:00
73aed233b2 meson: Use neon_opt to control building neon files
Using the have_neon boolean to enable NEON code means we have to either
fully enable it or fully disable it. When using -Dneon=runtime, ideally
only the parts that support runtime checks would be built for NEON, and
those that don't would be built without NEON. Though, there are no
longer any runtime checks for NEON anywhere, so it's equivalent to 'no'
with a warning.

In general, we should use have_* variables to indicate compiler support,
and *_opt options to choose if and how we want to utilize that. Use
neon_opt to control NEON compilation and avoid modifying have_neon which
now would fully refer to compiler support.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:18:44 -05:00
2493b6e659 meson: Raise error for setting 'neon' when unsupported
We can set -Dneon=yes on x86, which will fail during build because the
x86 compiler doesn't understand the resulting `-mfpu=neon` flag. Make the
'neon' build option cause an error in the setup stage if we didn't
detect hardware support for NEON.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:18:00 -05:00
fc5a4946af meson: Set 'auto' as the default neon option value
The default for the neon build option is 'no', which disabled NEON code
for 32-bit ARM but enabled it for ARM64. Now that 'no' can disable NEON
code for ARM64, the default should be 'auto' which would enable it where
possible. Handle the 'auto' value, and set it as the default.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:17:32 -05:00
b7a194f824 meson: Check arm neon support before parsing neon option
The main if statment for the NEON option has been quite convoluted. The
previous commits reduced what it does to a simple case: check NEON
support and set have_neon on 32-bit ARM CPUs. Do that near the
architecture definitions.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:16:43 -05:00
6c914be933 meson: Make -Dneon=no disable neon-specific code
When the neon build option is set to 'no', we should disable optimized
implementations that use NEON. Change have_neon to false in that case,
so that we skip the flags and skip building NEON-specific files.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:16:43 -05:00
8b0255991e meson: Set WEBRTC_HAS_NEON macro after handling neon build option
The WEBRTC_HAS_NEON macro that enables using NEON implementations is
unconditionally set for arm64 and the 'neon' build option is ignored,
assuming we always want to use the NEON-specific implementations instead
of generic ones. This is an OK assumption to make because arm64 CPUs
always support NEON.

But the code handling the build option ended up quite convoluted. As
part of cleaning up, set the relevant cflags after we handle the build
option. This also means that we can make 'runtime' fall back to 'no',
and disable NEON-specific code with -Dneon=no.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:16:43 -05:00
b22ce018c8 meson: Drop obsolete WEBRTC_DETECT_NEON macro
Upstream has dropped runtime checks for NEON instructions around 2016,
and the WEBRTC_DETECT_NEON macro is removed along with it. Disable NEON
when building with -Dneon=runtime and omit a warning instead.

Link: https://webrtc.googlesource.com/src/+/e305d956c0717a28ca88cd8547e5b310dfa74594
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 14:16:43 -05:00
a1ccd6c700 Track patches to WebRTC code in patches/
This should make it easier to not lose track during the next bump.
2024-12-30 14:05:31 -05:00
297fd4f2ef AECM: MIPS: Use uintptr_t for pointer arithmetic
Trying to compile the MIPS-specific AECM audio processing file for
mips64el on Debian results in the following errors:

  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc: In function ‘int webrtc::WebRtcAecm_ProcessBlock(AecmCore*, const int16_t*, const int16_t*, const int16_t*, int16_t*)’:
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:955:30: error: cast from ‘int16_t*’ {aka ‘short int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision [-fpermissive]
    955 |   int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
        |                              ^~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:955:18: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
    955 |   int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
        |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:956:36: error: cast from ‘int32_t*’ {aka ‘int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision [-fpermissive]
    956 |   int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
        |                                    ^~~~~~~~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:956:24: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
    956 |   int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
        |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:957:40: error: cast from ‘int32_t*’ {aka ‘int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision [-fpermissive]
    957 |   ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
        |                                        ^~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:957:23: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
    957 |   ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
        |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:958:40: error: cast from ‘int32_t*’ {aka ‘int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision [-fpermissive]
    958 |   ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
        |                                        ^~~~~~~~~~~~~~~~~
  ../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:958:23: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
    958 |   ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
        |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Presumably, this file was written for 32-bit MIPS so the author used
uint32_t to do pointer arithmetic over these arrays. Fix the errors by
using uintptr_t to work with pointers.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 18:11:05 +00:00
ecb8817972 Remove some unused files 2024-12-30 12:48:46 -05:00
6119c05d7d meson: Drop WEBRTC_THREAD_RR
The define was dropped upstream a while back and is unused.
2024-12-30 12:20:27 -05:00
2a318149f8 Add support for BSD systems
webrtc/rtc_base/checks.cc:158:28: error: use of undeclared identifier 'LAST_SYSTEM_ERROR'
  158 |                file, line, LAST_SYSTEM_ERROR, message);
      |                            ^
webrtc/rtc_base/checks.cc:220:16: error: use of undeclared identifier 'LAST_SYSTEM_ERROR'
  220 |                LAST_SYSTEM_ERROR);
      |                ^
In file included from webrtc/rtc_base/platform_thread_types.cc:11:
webrtc/rtc_base/platform_thread_types.h:47:1: error: unknown type name 'PlatformThreadId'
   47 | PlatformThreadId CurrentThreadId();
      | ^
webrtc/rtc_base/platform_thread_types.h:52:1: error: unknown type name 'PlatformThreadRef'
   52 | PlatformThreadRef CurrentThreadRef();
      | ^
webrtc/rtc_base/platform_thread_types.h:55:29: error: unknown type name 'PlatformThreadRef'
   55 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b);
      |                             ^
webrtc/rtc_base/platform_thread_types.h:55:57: error: unknown type name 'PlatformThreadRef'
   55 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b);
      |                                                         ^
webrtc/rtc_base/platform_thread_types.cc:37:1: error: unknown type name 'PlatformThreadId'
   37 | PlatformThreadId CurrentThreadId() {
      | ^
webrtc/rtc_base/platform_thread_types.cc:58:1: error: unknown type name 'PlatformThreadRef'
   58 | PlatformThreadRef CurrentThreadRef() {
      | ^
webrtc/rtc_base/platform_thread_types.cc:68:29: error: unknown type name 'PlatformThreadRef'
   68 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
      |                             ^
webrtc/rtc_base/platform_thread_types.cc:68:57: error: unknown type name 'PlatformThreadRef'
   68 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
      |                                                         ^
In file included from webrtc/rtc_base/event_tracer.cc:30:
In file included from webrtc/api/sequence_checker.h:15:
In file included from webrtc/rtc_base/synchronization/sequence_checker_internal.h:18:
webrtc/rtc_base/synchronization/mutex.h:28:2: error: Unsupported platform.
   28 | #error Unsupported platform.
      |  ^
webrtc/rtc_base/synchronization/mutex.h:52:3: error: unknown type name 'MutexImpl'
   52 |   MutexImpl impl_;
      |   ^
2024-12-30 17:18:54 +00:00
4a17c682e9 common_audio: Add MIPS_DSP_R1_LE guard for vector scaling ops
The MIPS-specific source for vector scaling operations fails to build on
Debian's mips64el:

  [97/303] Compiling C object webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o
  FAILED: webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o
  cc [...] webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o.d -o webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o -c ../webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
  /tmp/cc7UGPkY.s: Assembler messages:
  /tmp/cc7UGPkY.s:57: Error: opcode not supported on this processor: mips64r2 (mips64r2) `extrv_r.w $3,$ac0,$8'
  ninja: build stopped: subcommand failed.

The EXTRV_R.W instruction it uses is part of DSP extensions for this
architecture. In signal_processing_library.h, this function's prototype
is guarded with #if defined(MIPS_DSP_R1_LE). Guard the implementation
like that as well to fix the error.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 12:06:56 -05:00
5252919799 meson: Avoid default AECM implementation on MIPS
Trying to link both aecm/aecm_core_mips.cc and aecm/aecm_core_c.cc into
the same library results in an error because they both try to implement
webrtc::WebRtcAecm_ProcessBlock():

  [306/306] Linking target webrtc/modules/audio_processing/libwebrtc-audio-processing-1.so.3
  FAILED: webrtc/modules/audio_processing/libwebrtc-audio-processing-1.so.3
  c++ @webrtc/modules/audio_processing/libwebrtc-audio-processing-1.so.3.rsp
  /usr/bin/ld: webrtc/modules/audio_processing/libwebrtc-audio-processing-1.so.3.p/aecm_aecm_core_mips.cc.o: in function `webrtc::WebRtcAecm_ProcessBlock(webrtc::AecmCore*, short const*, short const*, short const*, short*)':
  [...]/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:934: multiple definition of `webrtc::WebRtcAecm_ProcessBlock(webrtc::AecmCore*, short const*, short const*, short const*, short*)'; webrtc/modules/audio_processing/libwebrtc-audio-processing-1.so.3.p/aecm_aecm_core_c.cc.o:[...]/webrtc/modules/audio_processing/aecm/aecm_core_c.cc:377: first defined here
  collect2: error: ld returned 1 exit status
  ninja: build stopped: subcommand failed.

The MIPS-specific file is a replacement for the other, unlike the NEON
case. Don't add the default implementation unconditionally, add it only
for non-MIPS builds.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 12:06:55 -05:00
85556fd38b meson: Drop malformed WEBRTC_ARCH_MIPS_FAMILY cflags argument
The top-level meson.build file adds WEBRTC_ARCH_MIPS_FAMILY to
arch_cflags for mips architectures, which causes the following error:

  [1/306] Compiling C++ object webrtc/rtc_base/liblibbase.a.p/synchronization_yield.cc.o
  FAILED: webrtc/rtc_base/liblibbase.a.p/synchronization_yield.cc.o
  c++ [...] -DWEBRTC_THREAD_RR WEBRTC_ARCH_MIPS_FAMILY -MD [...] ../webrtc/rtc_base/synchronization/yield.cc
  c++: warning: WEBRTC_ARCH_MIPS_FAMILY: linker input file unused because linking not done
  c++: error: WEBRTC_ARCH_MIPS_FAMILY: linker input file not found: No such file or directory

It is supposed to be "-DWEBRTC_ARCH_MIPS_FAMILY". But, that macro is
already defined in arch.h when building for mips:

  [30/306] Compiling C++ object webrtc/system_wrappers/libsystem_wrappers.a.p/source_cpu_features.cc.o
  In file included from ../webrtc/system_wrappers/source/cpu_features.cc:13:
  ../webrtc/rtc_base/system/arch.h:47:9: warning: "WEBRTC_ARCH_MIPS_FAMILY" redefined
     47 | #define WEBRTC_ARCH_MIPS_FAMILY
        |         ^~~~~~~~~~~~~~~~~~~~~~~
  <command-line>: note: this is the location of the previous definition

Drop the broken, unnecessary argument from cflags.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-30 12:06:49 -05:00
da757ff09f Fix MIPS-specific source path
Link: https://sources.debian.org/patches/webrtc-audio-processing/1.0-0.2/fix-mips-source-path.patch
2024-12-30 12:06:46 -05:00
fed81a77c9 Allow disabling inline SSE
Should make building on i686 without SSE feasible.

Fixes: https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/issues/5
2024-12-26 17:35:08 -05:00
c144c53039 Drop WAV-related files
These are only used when WEBRTC_APM_DEBUG_DUMP=1, which we do not set.
Hopefully this makes building on big-endian machines possible.

Fixes: https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/issues/31
2024-12-26 13:07:40 -05:00
0d4c5f27b5 build: Bump version to 2.0 2024-12-26 12:55:16 -05:00
9b194c2d99 ci: Switch CI over to Fedora
Ubuntu/Debian absl are currently lagging. We should switch back to
Debian once recent abseil lands in unstable/testing.
2024-12-26 12:55:16 -05:00
d090f7a927 ci: Bump iOS version to 11.0
This is needed for std::optional to be usable (specifically for .value()
to be available).
2024-12-26 12:55:16 -05:00
ad563b095c Fix up XMM intrinsics usage on MSVC
Repplying 0a0050746b after M131 bump.
2024-12-26 12:55:16 -05:00
b5c48b97f6 Bump to WebRTC M131 release
Ongoing fixes and improvements, transient suppressor is gone. Also,
dropping isac because it doesn't seem to be useful, and is just build
system deadweight now.

Upstream references:

  Version: 131.0.6778.200
  WebRTC: 79aff54b0fa9238ce3518dd9eaf9610cd6f22e82
  Chromium: 2a19506ad24af755f2a215a4c61f775393e0db42
2024-12-26 12:55:16 -05:00
8bdb53d91c meson: Update abseil wrap to 20240722
We need something recent enough with the stringify API for the M131 bump.
2024-12-26 12:55:12 -05:00
ced0ff6765 ci: Fix up workflow rules for MR vs. branch pipelines 2024-12-26 09:27:14 -05:00
1ff1a0b860 Decode base64-encoded third-party files
Some files were committed into the repository as base64 encoded files.
Presumably, this is because the "text" download links on Google's
Gitiles web interface sends them as such. These can be found by running
`git grep "^[[:alnum:]]\{128,\}=*$"`. Decode them with `base64 -d`.

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
2024-12-24 19:42:56 -05:00
867e2d875b Add a trivial example to run AEC offline
Just allows for some sanity testing for now, will improve for
configurability and add some sample data in the future.
2024-12-24 18:57:37 -05:00
a729ccfe0f ci: Bump to Ubuntu 24.04 2024-12-24 18:57:37 -05:00
4c81b31652 ci: Bump Windows to cpp_std=c++20
Required for designated initializers.
2024-12-24 12:02:19 -05:00
0a0050746b Fix up XMM intrinsics usage on MSVC 2024-12-24 12:02:19 -05:00
06157f1659 build: Use Visual Studio-specific flags for AVX
Needed for now, but unstable-simd is likely a better fix for all our
SIMD building.
2024-12-24 12:02:19 -05:00
c6abf6cd3f Bump to WebRTC M120 release
Some API deprecation -- ExperimentalAgc and ExperimentalNs are gone.
We're continuing to carry iSAC even though it's gone upstream, but maybe
we'll want to drop that soon.
2024-12-24 11:05:39 -05:00
9a202fb8c2 file_wrapper.h: Fix build with GCC13
It is a missed instance of cdec109331 (!31).

Fixes #32
2024-04-04 18:32:39 -03:00
a949f1de2d build: Appease MSYS2 UCRT64 GCC 13
Undefining this macro makes GCC in standards C++ mode very unhappy:

In file included from D:/msys64/ucrt64/include/c++/13.2.0/bits/requires_hosted.h:31,
                 from D:/msys64/ucrt64/include/c++/13.2.0/string:38,
                 from ..\subprojects\webrtc-audio-processing\webrtc/rtc_base/system/file_wrapper.h:17,
                 from ../subprojects/webrtc-audio-processing/webrtc/rtc_base/system/file_wrapper.cc:11:
D:/msys64/ucrt64/include/c++/13.2.0/x86_64-w64-mingw32/bits/c++config.h:666:2: warning: #warning "__STRICT_ANSI__ seems to have been undefined; this is not supported" [-Wcpp]
  666 | #warning "__STRICT_ANSI__ seems to have been undefined; this is not supported"
      |  ^~~~~~~

See: https://github.com/fmtlib/fmt/issues/2059#issue-761209068

See: #32
2024-03-23 16:34:50 -03:00
f89958d824 Bring arch.h in line with upstream webrtc
Largely to bring in preprocessor support for additional architectures as
based on 6215ba804eb500f3e28b39088c73af3c4f4cd10a by
Timothy Gu <timothygu99@gmail.com>:

Add preprocessor support for additional architectures

- _M_ARM is used by Microsoft [1]
- __riscv and __riscv_xlen are defined by [2]
- __sparc and __sparc__ are documented at [3]
- __MIPSEB__, __PPC__, __PPC64__ are documented at [3] and used in
  Chromium's build/build_config.h [4]
  Note: Chromium assumes that all PowerPC architectures are 64-bit. This
  is in fact not true.

[1]: https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-160
[2]: feca479356 (cc-preprocessor-definitions)
[3]: https://sourceforge.net/p/predef/wiki/Architectures/
[4]: https://source.chromium.org/chromium/chromium/src/+/master:build/build_config.h;drc=e12bf2e5ff1eacb9aca3e9a26bdeebdbdad5965a
2023-11-29 16:59:12 +00:00
8e258a1933 build: Bump version to 1.3 2023-09-05 11:19:47 -04:00
0691ae20d8 meson: Fix generation of pkgconfig files
Too much information was specified manually. All this is deduced
automatically if you specify the library as the first positional
argument.

Only absl_base needs to be in Requires: because absl_optional's header
file is needed at build time.

Also add a check in the CI for the pc files being usable.
2023-09-05 01:50:51 +05:30
593 changed files with 24565 additions and 33624 deletions

View File

@ -10,6 +10,16 @@
# as part of the build stage as there doesn't seem to be significant value to # as part of the build stage as there doesn't seem to be significant value to
# splitting the stages at the moment. # splitting the stages at the moment.
# Create merge request pipelines for open merge requests, branch pipelines
# otherwise. This allows MRs for new users to run CI, and prevents duplicate
# pipelines for branches with open MRs.
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
stages: stages:
- container - container
- build - build
@ -19,8 +29,8 @@ variables:
# CI runs, for example when adding new packages to FDO_DISTRIBUTION_PACKAGES. # CI runs, for example when adding new packages to FDO_DISTRIBUTION_PACKAGES.
# The tag is an arbitrary string that identifies the exact container # The tag is an arbitrary string that identifies the exact container
# contents. # contents.
BASE_TAG: '2023-05-25.0' BASE_TAG: '2024-12-26.0'
FDO_DISTRIBUTION_VERSION: '22.10' FDO_DISTRIBUTION_VERSION: '41'
FDO_UPSTREAM_REPO: 'pulseaudio/webrtc-audio-processing' FDO_UPSTREAM_REPO: 'pulseaudio/webrtc-audio-processing'
include: include:
@ -30,10 +40,10 @@ include:
# failures, this might be one cause. # failures, this might be one cause.
- project: 'freedesktop/ci-templates' - project: 'freedesktop/ci-templates'
ref: 'master' ref: 'master'
file: '/templates/ubuntu.yml' file: '/templates/fedora.yml'
# Common container build template # Common container build template
.ubuntu-container-build: .fedora-container-build:
variables: variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
@ -41,23 +51,24 @@ include:
# Otherwise the changes won't have effect since an old container image will # Otherwise the changes won't have effect since an old container image will
# be used. # be used.
FDO_DISTRIBUTION_PACKAGES: >- FDO_DISTRIBUTION_PACKAGES: >-
ca-certificates
g++ g++
gcc gcc
git-core git-core
cmake cmake
libabsl-dev abseil-cpp-devel
meson meson
ninja-build ninja-build
pkg-config pkg-config
python3-setuptools python3-setuptools
# Used to extend both container and build jobs # Used to extend both container and build jobs
.ubuntu-x86_64: .fedora-x86_64:
variables: variables:
FDO_DISTRIBUTION_TAG: "x86_64-$BASE_TAG" FDO_DISTRIBUTION_TAG: "x86_64-$BASE_TAG"
# Used to extend both container and build jobs # Used to extend both container and build jobs
.ubuntu-aarch64: .fedora-aarch64:
tags: tags:
- aarch64 - aarch64
variables: variables:
@ -65,26 +76,29 @@ include:
build-container-x86_64: build-container-x86_64:
extends: extends:
- .fdo.container-build@ubuntu@x86_64 - .fdo.container-build@fedora@x86_64
- .ubuntu-container-build - .fedora-container-build
- .ubuntu-x86_64 - .fedora-x86_64
stage: container stage: container
build-container-aarch64: build-container-aarch64:
extends: extends:
- .fdo.container-build@ubuntu@aarch64 - .fdo.container-build@fedora@aarch64
- .ubuntu-container-build - .fedora-container-build
- .ubuntu-aarch64 - .fedora-aarch64
stage: container stage: container
# Common build template # Common build template
.build-distro-absl: .build-distro-absl:
stage: build stage: build
extends: extends:
- .fdo.distribution-image@ubuntu - .fdo.distribution-image@fedora
script: script:
- meson setup --wrap-mode=nofallback builddir - meson setup --wrap-mode=nofallback --prefix=/usr --libdir=lib builddir
- ninja -C builddir - ninja -C builddir
- DESTDIR=$PWD/_install ninja install -C builddir
# Test that the pc files are usable
- PKG_CONFIG_PATH=$PWD/_install/usr/lib/pkgconfig pkg-config --cflags --libs webrtc-audio-processing-2
artifacts: artifacts:
expire_in: '5 days' expire_in: '5 days'
when: 'always' when: 'always'
@ -94,10 +108,13 @@ build-container-aarch64:
.build-vendored-absl: .build-vendored-absl:
stage: build stage: build
extends: extends:
- .fdo.distribution-image@ubuntu - .fdo.distribution-image@fedora
script: script:
- meson setup --force-fallback-for=abseil-cpp builddir - meson setup --force-fallback-for=abseil-cpp --prefix=/usr --libdir=lib builddir
- ninja -C builddir - ninja -C builddir
- DESTDIR=$PWD/_install ninja install -C builddir
# Test that the pc files are usable
- PKG_CONFIG_LIBDIR=$PWD/_install/usr/lib/pkgconfig pkg-config --cflags --libs webrtc-audio-processing-2
artifacts: artifacts:
expire_in: '5 days' expire_in: '5 days'
when: 'always' when: 'always'
@ -107,22 +124,22 @@ build-container-aarch64:
build-distro-absl-x86_64: build-distro-absl-x86_64:
extends: extends:
- .build-distro-absl - .build-distro-absl
- .ubuntu-x86_64 - .fedora-x86_64
build-vendored-absl-x86_64: build-vendored-absl-x86_64:
extends: extends:
- .build-vendored-absl - .build-vendored-absl
- .ubuntu-x86_64 - .fedora-x86_64
build-distro-absl-aarch64: build-distro-absl-aarch64:
extends: extends:
- .build-distro-absl - .build-distro-absl
- .ubuntu-aarch64 - .fedora-aarch64
build-vendored-absl-aarch64: build-vendored-absl-aarch64:
extends: extends:
- .build-vendored-absl - .build-vendored-absl
- .ubuntu-aarch64 - .fedora-aarch64
# Update from: # Update from:
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-ci.yml # https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-ci.yml
@ -154,7 +171,7 @@ vs2019 amd64:
# Environment variables substitutions is done by PowerShell before calling # Environment variables substitutions is done by PowerShell before calling
# cmd.exe, that's why we use $env:FOO instead of %FOO% # cmd.exe, that's why we use $env:FOO instead of %FOO%
- cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=$env:ARCH -app_platform=$env:PLAT && - cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=$env:ARCH -app_platform=$env:PLAT &&
meson setup builddir && meson setup builddir -Dcpp_std=c++20 &&
meson compile --verbose -C builddir" meson compile --verbose -C builddir"
# Update from: # Update from:
@ -214,14 +231,14 @@ ios arm64:
endian = 'little' endian = 'little'
[properties] [properties]
c_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] c_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
objc_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] objc_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
cpp_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] cpp_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
objcpp_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] objcpp_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
c_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] c_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
objc_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] objc_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
cpp_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] cpp_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
objcpp_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=8.0'] objcpp_link_args = ['-arch', 'arm64', '--sysroot=$(xcrun --sdk iphoneos --show-sdk-path)', '-miphoneos-version-min=11.0']
[binaries] [binaries]
ar = '$(xcrun --find --sdk iphoneos ar)' ar = '$(xcrun --find --sdk iphoneos ar)'

70
NEWS
View File

@ -1,3 +1,73 @@
Release 2.1
-----------
Build-system fixups to install more headers, add a missing absl dependency, and
forward port some missing patches to fix Windows builds.
Release 2.0
-----------
Bump to code from WebRTC M131 version.
Changes include:
* Minor (breaking) API changes upstream
* Various improvements to the AEC implementation
* Transient suppression is removed
* ExperimentalAgc and ExperimentalNs are removed
* iSAC and the webrtc-audio-coding library were removed
* abseil-cpp dependency bumped to 20240722
* NEON runtime detection dropped following upstream
* Fixes for building on i686 and MIPS
* Support for BSDs is added
* Other build-system cleanups
* Patches to upstream are now also tracked in patches/
Release 1.3
-----------
Fix for generate pkg-config file.
Release 1.2
-----------
Improvements for building with abseil-cpp as a subproject, and pkg-config
improvements for abseil dependency detection.
Release 1.1
-----------
Build fixes for various platforms.
Release 1.0
-----------
This is an API breaking release (as a reminder, the AudioProcessing module does
not provide a stable public API, so we expose whatever API exists in the
upstream project).
In order to make package management easier with these inevitable breakages, the
package is now suffixed with a version (currently it is
webrtc-audio-processing-1). When the next API break happens, we will bump the
major version, allowing incompatible versions to coexist. This also means that
the previous version can also coexist with this one. Non-breaking changes will
see a minor version update only.
Changes:
* The code base is now updated to correspond to the version shipping with the
Chromium 88.0.4290.1 tag
* There are a very large number changes to the underlying AEC implementation
since the last update was a while ago. Most visibly the use of the AEC3
canceller by default, the deletion of the beamformer code
* The autotools build system is replaced by meson
* The pkg-config name is changed as described above
Release 0.3 Release 0.3
----------- -----------

8
examples/meson.build Normal file
View File

@ -0,0 +1,8 @@
top_incdir = include_directories('..')
executable('run-offline',
'run-offline.cpp',
install: false,
include_directories: top_incdir,
dependencies: [audio_processing_dep, absl_dep]
)

67
examples/run-offline.cpp Normal file
View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2024 Asymptotic Inc. All Rights Reserved.
* Author: Arun Raghavan <arun@asymptotic.io>
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/scoped_refptr.h"
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <webrtc/modules/audio_processing/include/audio_processing.h>
#define DEFAULT_BLOCK_MS 10
#define DEFAULT_RATE 32000
#define DEFAULT_CHANNELS 1
int main(int argc, char **argv) {
if (argc != 4) {
std::cerr << "Usage: " << argv[0] << " <play_file> <rec_file> <out_file>" << std::endl;
return EXIT_FAILURE;
}
std::ifstream play_file(argv[1], std::ios::binary);
std::ifstream rec_file(argv[2], std::ios::binary);
std::ofstream aec_file(argv[3], std::ios::binary);
rtc::scoped_refptr<webrtc::AudioProcessing> apm = webrtc::AudioProcessingBuilder().Create();
webrtc::AudioProcessing::Config config;
config.echo_canceller.enabled = true;
config.echo_canceller.mobile_mode = false;
config.gain_controller1.enabled = true;
config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog;
config.gain_controller2.enabled = true;
config.high_pass_filter.enabled = true;
apm->ApplyConfig(config);
webrtc::StreamConfig stream_config(DEFAULT_RATE, DEFAULT_CHANNELS);
while (!play_file.eof() && !rec_file.eof()) {
int16_t play_frame[DEFAULT_RATE * DEFAULT_BLOCK_MS / 1000 * DEFAULT_CHANNELS];
int16_t rec_frame[DEFAULT_RATE * DEFAULT_BLOCK_MS / 1000 * DEFAULT_CHANNELS];
play_file.read(reinterpret_cast<char *>(play_frame), sizeof(play_frame));
rec_file.read(reinterpret_cast<char *>(rec_frame), sizeof(rec_frame));
apm->ProcessReverseStream(play_frame, stream_config, stream_config, play_frame);
apm->ProcessStream(rec_frame, stream_config, stream_config, rec_frame);
aec_file.write(reinterpret_cast<char *>(rec_frame), sizeof(rec_frame));
}
play_file.close();
rec_file.close();
aec_file.close();
return EXIT_SUCCESS;
}

View File

@ -1,5 +1,5 @@
project('webrtc-audio-processing', 'c', 'cpp', project('webrtc-audio-processing', 'c', 'cpp',
version : '1.2', version : '2.1',
meson_version : '>= 0.63', meson_version : '>= 0.63',
default_options : [ 'warning_level=1', default_options : [ 'warning_level=1',
'buildtype=debugoptimized', 'buildtype=debugoptimized',
@ -19,14 +19,8 @@ minor_version = version_split[1]
apm_major_version = major_version apm_major_version = major_version
apm_minor_version = minor_version apm_minor_version = minor_version
apm_version = apm_major_version + '.' + apm_minor_version
apm_project_name = 'webrtc-audio-processing-' + apm_major_version apm_project_name = 'webrtc-audio-processing-' + apm_major_version
ac_major_version = major_version
ac_minor_version = minor_version
ac_version = ac_major_version + '.' + ac_minor_version
ac_project_name = 'webrtc-audio-coding-' + ac_major_version
include_subdir = apm_project_name include_subdir = apm_project_name
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
@ -55,9 +49,10 @@ have_win = false
# if pkg-config is not found, which is really the most reliable way of building # if pkg-config is not found, which is really the most reliable way of building
# abseil due to strict C++ standard match requirements. # abseil due to strict C++ standard match requirements.
absl_dep = [ absl_dep = [
dependency('absl_base', default_options: ['cpp_std=c++17']), dependency('absl_base', default_options: ['cpp_std=c++17'], version: '>=20240722'),
dependency('absl_flags'), dependency('absl_flags'),
dependency('absl_strings'), dependency('absl_strings'),
dependency('absl_numeric'),
dependency('absl_synchronization'), dependency('absl_synchronization'),
dependency('absl_bad_optional_access'), dependency('absl_bad_optional_access'),
] ]
@ -68,10 +63,14 @@ if absl_dep[0].type_name() == 'internal'
absl_subproj.get_variable('absl_base_headers'), absl_subproj.get_variable('absl_base_headers'),
absl_subproj.get_variable('absl_flags_headers'), absl_subproj.get_variable('absl_flags_headers'),
absl_subproj.get_variable('absl_strings_headers'), absl_subproj.get_variable('absl_strings_headers'),
absl_subproj.get_variable('absl_numeric_headers'),
absl_subproj.get_variable('absl_synchronization_headers'), absl_subproj.get_variable('absl_synchronization_headers'),
absl_subproj.get_variable('absl_types_headers'), absl_subproj.get_variable('absl_types_headers'),
] ]
install_headers(headers, preserve_path: true) install_headers(headers, preserve_path: true)
pc_requires = []
else
pc_requires = [absl_dep[0]]
endif endif
if ['darwin', 'ios'].contains(host_system) if ['darwin', 'ios'].contains(host_system)
@ -86,12 +85,17 @@ elif host_system == 'android'
os_deps += [dependency('gnustl', required : get_option('gnustl'))] os_deps += [dependency('gnustl', required : get_option('gnustl'))]
have_posix = true have_posix = true
elif host_system == 'linux' elif host_system == 'linux'
os_cflags += ['-DWEBRTC_LINUX', '-DWEBRTC_THREAD_RR'] os_cflags += ['-DWEBRTC_LINUX']
os_deps += [cc.find_library('rt', required : false)] os_deps += [cc.find_library('rt', required : false)]
os_deps += [dependency('threads')] os_deps += [dependency('threads')]
have_posix = true have_posix = true
elif (host_system == 'dragonfly' or host_system == 'freebsd' or
host_system == 'netbsd' or host_system == 'openbsd')
os_cflags += ['-DWEBRTC_BSD']
os_deps += [dependency('threads')]
have_posix = true
elif host_system == 'windows' elif host_system == 'windows'
platform_cflags += ['-DWEBRTC_WIN', '-D_WIN32', '-U__STRICT_ANSI__'] platform_cflags += ['-DWEBRTC_WIN', '-D_WIN32']
# this one is for MinGW to get format specifiers from inttypes.h in C++ # this one is for MinGW to get format specifiers from inttypes.h in C++
platform_cflags += ['-D__STDC_FORMAT_MACROS=1'] platform_cflags += ['-D__STDC_FORMAT_MACROS=1']
# Avoid min/max from windows.h which breaks std::min/max # Avoid min/max from windows.h which breaks std::min/max
@ -109,10 +113,12 @@ endif
arch_cflags = [] arch_cflags = []
have_arm = false have_arm = false
have_armv7 = false have_armv7 = false
have_arm64 = false
have_neon = false have_neon = false
have_mips = false have_mips = false
have_mips64 = false have_mips64 = false
have_x86 = false have_x86 = false
have_inline_sse = false
have_avx2 = false have_avx2 = false
if host_machine.cpu_family() == 'arm' if host_machine.cpu_family() == 'arm'
if cc.compiles('''#ifndef __ARM_ARCH_ISA_ARM if cc.compiles('''#ifndef __ARM_ARCH_ISA_ARM
@ -127,70 +133,77 @@ if host_machine.cpu_family() == 'arm'
have_armv7 = true have_armv7 = true
arch_cflags += ['-DWEBRTC_ARCH_ARM_V7'] arch_cflags += ['-DWEBRTC_ARCH_ARM_V7']
endif endif
if cc.compiles('#include <arm_neon.h>', args : '-mfpu=neon')
have_neon = true
endif
endif endif
if cc.compiles('''#ifndef __aarch64__ if host_machine.cpu_family() == 'aarch64'
#error no aarch64 arch have_arm64 = true
#endif''')
have_neon = true have_neon = true
arch_cflags += ['-DWEBRTC_ARCH_ARM64', '-DWEBRTC_HAS_NEON'] arch_cflags += ['-DWEBRTC_ARCH_ARM64']
endif endif
if ['mips', 'mips64'].contains(host_machine.cpu_family()) if ['mips', 'mips64'].contains(host_machine.cpu_family())
have_mips = true have_mips = true
arch_cflags += ['WEBRTC_ARCH_MIPS_FAMILY']
endif endif
if host_machine.cpu_family() == 'mips64' if host_machine.cpu_family() == 'mips64'
have_mips64 = true have_mips64 = true
endif endif
if ['x86', 'x86_64'].contains(host_machine.cpu_family()) if ['x86', 'x86_64'].contains(host_machine.cpu_family())
have_x86 = true have_x86 = true
# This is unconditionally enabled for now, actual usage is determined by # AVX2 support is unconditionally available, since all the code (compiled
# runtime CPU detection, so we're just assuming the compiler supports avx2 # with -mavx2) is in separate files from runtime detection (which should not
# be compiled with SIMD flags for cases where the CPU does not support it).
# Unfortunately, a bunch of SSE code is inline with the runtime detection,
# and we can't support that on systems that don't support SSE.
have_avx2 = true have_avx2 = true
arch_cflags += ['-DWEBRTC_ENABLE_AVX2'] arch_cflags += ['-DWEBRTC_ENABLE_AVX2']
if get_option('inline-sse')
have_inline_sse = true
else
have_inline_sse = false
arch_cflags += ['-DWAP_DISABLE_INLINE_SSE']
endif
endif endif
neon_opt = get_option('neon') neon_opt = get_option('neon').require(have_neon)
if neon_opt != 'no' and not have_neon
if neon_opt != 'runtime' if neon_opt.enabled()
if cc.compiles('#include <arm_neon.h>', args : '-mfpu=neon') arch_cflags += ['-DWEBRTC_HAS_NEON']
arch_cflags += ['-mfpu=neon', '-DWEBRTC_HAS_NEON'] if not have_arm64
have_neon = true arch_cflags += ['-mfpu=neon']
endif
else
arch_cflags += ['-DWEBRTC_DETECT_NEON', '-mfpu=neon']
have_neon = true
endif endif
endif endif
common_cflags = [ common_cflags = [
'-DWEBRTC_LIBRARY_IMPL', '-DWEBRTC_LIBRARY_IMPL',
'-DWEBRTC_ENABLE_SYMBOL_EXPORT', '-DWEBRTC_ENABLE_SYMBOL_EXPORT',
# avoid windows.h/winsock2.h conflicts
'-D_WINSOCKAPI_',
'-DNDEBUG' '-DNDEBUG'
] + platform_cflags + os_cflags + arch_cflags ] + platform_cflags + os_cflags + arch_cflags
common_cxxflags = common_cflags common_cxxflags = common_cflags
common_deps = os_deps + [absl_dep] common_deps = os_deps + [absl_dep]
webrtc_inc = include_directories('.') webrtc_inc = include_directories('.')
# FIXME: use the unstable-simd module instead
if cc.get_define('_MSC_VER') != ''
avx_flags = ['/arch:AVX2']
else
avx_flags = ['-mavx2', '-mfma']
endif
subdir('webrtc') subdir('webrtc')
pkgconfig = import('pkgconfig') pkgconfig = import('pkgconfig')
pkgconfig.generate( pkgconfig.generate(
name: apm_project_name, libwebrtc_audio_processing,
description: 'WebRTC Audio Processing library', description: 'WebRTC Audio Processing library',
version: apm_major_version + '.' + apm_minor_version, subdirs: include_subdir,
filebase: apm_project_name, requires: pc_requires,
subdirs: include_subdir, extra_cflags: [
extra_cflags: [ '-DWEBRTC_LIBRARY_IMPL',
'-DWEBRTC_LIBRARY_IMPL', ] + platform_cflags,
] + platform_cflags,
libraries: [
libwebrtc_audio_processing,
],
requires: [
# the audio processing header references absl's optional.h
'absl_base',
]
) )
audio_processing_dep = declare_dependency( audio_processing_dep = declare_dependency(
@ -201,21 +214,4 @@ audio_processing_dep = declare_dependency(
meson.override_dependency(apm_project_name, audio_processing_dep) meson.override_dependency(apm_project_name, audio_processing_dep)
pkgconfig.generate( subdir('examples')
name: ac_project_name,
description: 'WebRTC Audio Coding library',
version: ac_major_version + '.' + ac_minor_version,
filebase: ac_project_name,
subdirs: include_subdir,
extra_cflags: [
'-DWEBRTC_LIBRARY_IMPL',
] + platform_cflags,
libraries: libwebrtc_audio_coding,
)
audio_coding_dep = declare_dependency(
link_with: libwebrtc_audio_coding,
include_directories: [webrtc_inc]
)
meson.override_dependency(ac_project_name, audio_coding_dep)

View File

@ -1,6 +1,9 @@
option('gnustl', type: 'feature', option('gnustl', type: 'feature',
value: 'auto', value: 'auto',
description: 'Use gnustl for a c++ library implementation (only used on Android)') description: 'Use gnustl for a c++ library implementation (only used on Android)')
option('neon', type: 'combo', option('neon', type: 'feature',
choices: ['no', 'yes', 'auto', 'runtime'], value: 'auto',
description: '') description: 'Enable NEON optimisations')
option('inline-sse', type: 'boolean',
value: true,
description: 'Enable inline SSE/SSE2 optimisations (i.e. assume CPU supports SSE/SSE2)')

View File

@ -0,0 +1,68 @@
From 297fd4f2efc53b6d49433eaad91a8e09a0f9cbec Mon Sep 17 00:00:00 2001
From: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Date: Fri, 25 Oct 2024 00:40:59 +0300
Subject: [PATCH] AECM: MIPS: Use uintptr_t for pointer arithmetic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Trying to compile the MIPS-specific AECM audio processing file for
mips64el on Debian results in the following errors:
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc: In function int webrtc::WebRtcAecm_ProcessBlock(AecmCore*, const int16_t*, const int16_t*, const int16_t*, int16_t*):
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:955:30: error: cast from int16_t* {aka short int*} to uint32_t {aka unsigned int} loses precision [-fpermissive]
955 | int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:955:18: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
955 | int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:956:36: error: cast from int32_t* {aka int*} to uint32_t {aka unsigned int} loses precision [-fpermissive]
956 | int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:956:24: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
956 | int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:957:40: error: cast from int32_t* {aka int*} to uint32_t {aka unsigned int} loses precision [-fpermissive]
957 | ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:957:23: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
957 | ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:958:40: error: cast from int32_t* {aka int*} to uint32_t {aka unsigned int} loses precision [-fpermissive]
958 | ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~
../webrtc/modules/audio_processing/aecm/aecm_core_mips.cc:958:23: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
958 | ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Presumably, this file was written for 32-bit MIPS so the author used
uint32_t to do pointer arithmetic over these arrays. Fix the errors by
using uintptr_t to work with pointers.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
---
webrtc/modules/audio_processing/aecm/aecm_core_mips.cc | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc b/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc
index 16b03cf..07c785e 100644
--- a/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc
+++ b/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc
@@ -952,10 +952,10 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
int32_t dfw_buf[PART_LEN2 + 8];
int32_t efw_buf[PART_LEN2 + 8];
- int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
- int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
- ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
- ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
+ int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
+ int32_t* echoEst32 = (int32_t*)(((uintptr_t)echoEst32_buf + 31) & ~31);
+ ComplexInt16* dfw = (ComplexInt16*)(((uintptr_t)dfw_buf + 31) & ~31);
+ ComplexInt16* efw = (ComplexInt16*)(((uintptr_t)efw_buf + 31) & ~31);
int16_t hnl[PART_LEN1];
int16_t numPosCoef = 0;
--
2.47.1

View File

@ -0,0 +1,110 @@
From 2a318149f8d5094c82306b8091a7a8b5194bf9c1 Mon Sep 17 00:00:00 2001
From: Jan Beich <jbeich@FreeBSD.org>
Date: Tue, 7 Jan 2020 18:08:24 +0000
Subject: [PATCH] Add support for BSD systems
webrtc/rtc_base/checks.cc:158:28: error: use of undeclared identifier 'LAST_SYSTEM_ERROR'
158 | file, line, LAST_SYSTEM_ERROR, message);
| ^
webrtc/rtc_base/checks.cc:220:16: error: use of undeclared identifier 'LAST_SYSTEM_ERROR'
220 | LAST_SYSTEM_ERROR);
| ^
In file included from webrtc/rtc_base/platform_thread_types.cc:11:
webrtc/rtc_base/platform_thread_types.h:47:1: error: unknown type name 'PlatformThreadId'
47 | PlatformThreadId CurrentThreadId();
| ^
webrtc/rtc_base/platform_thread_types.h:52:1: error: unknown type name 'PlatformThreadRef'
52 | PlatformThreadRef CurrentThreadRef();
| ^
webrtc/rtc_base/platform_thread_types.h:55:29: error: unknown type name 'PlatformThreadRef'
55 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b);
| ^
webrtc/rtc_base/platform_thread_types.h:55:57: error: unknown type name 'PlatformThreadRef'
55 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b);
| ^
webrtc/rtc_base/platform_thread_types.cc:37:1: error: unknown type name 'PlatformThreadId'
37 | PlatformThreadId CurrentThreadId() {
| ^
webrtc/rtc_base/platform_thread_types.cc:58:1: error: unknown type name 'PlatformThreadRef'
58 | PlatformThreadRef CurrentThreadRef() {
| ^
webrtc/rtc_base/platform_thread_types.cc:68:29: error: unknown type name 'PlatformThreadRef'
68 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
| ^
webrtc/rtc_base/platform_thread_types.cc:68:57: error: unknown type name 'PlatformThreadRef'
68 | bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
| ^
In file included from webrtc/rtc_base/event_tracer.cc:30:
In file included from webrtc/api/sequence_checker.h:15:
In file included from webrtc/rtc_base/synchronization/sequence_checker_internal.h:18:
webrtc/rtc_base/synchronization/mutex.h:28:2: error: Unsupported platform.
28 | #error Unsupported platform.
| ^
webrtc/rtc_base/synchronization/mutex.h:52:3: error: unknown type name 'MutexImpl'
52 | MutexImpl impl_;
| ^
---
meson.build | 5 +++++
webrtc/rtc_base/platform_thread_types.cc | 16 ++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/meson.build b/meson.build
index 8d85d56..05a434a 100644
--- a/meson.build
+++ b/meson.build
@@ -87,6 +87,11 @@ elif host_system == 'linux'
os_deps += [cc.find_library('rt', required : false)]
os_deps += [dependency('threads')]
have_posix = true
+elif (host_system == 'dragonfly' or host_system == 'freebsd' or
+ host_system == 'netbsd' or host_system == 'openbsd')
+ os_cflags += ['-DWEBRTC_BSD', '-DWEBRTC_THREAD_RR']
+ os_deps += [dependency('threads')]
+ have_posix = true
elif host_system == 'windows'
platform_cflags += ['-DWEBRTC_WIN', '-D_WIN32']
# this one is for MinGW to get format specifiers from inttypes.h in C++
diff --git a/webrtc/rtc_base/platform_thread_types.cc b/webrtc/rtc_base/platform_thread_types.cc
index d64ea68..e98e8ec 100644
--- a/webrtc/rtc_base/platform_thread_types.cc
+++ b/webrtc/rtc_base/platform_thread_types.cc
@@ -15,6 +15,12 @@
#include <sys/syscall.h>
#endif
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) // WEBRTC_BSD
+#include <pthread_np.h>
+#elif defined(__NetBSD__) // WEBRTC_BSD
+#include <lwp.h>
+#endif
+
#if defined(WEBRTC_WIN)
#include "rtc_base/arraysize.h"
@@ -46,6 +52,12 @@ PlatformThreadId CurrentThreadId() {
return zx_thread_self();
#elif defined(WEBRTC_LINUX)
return syscall(__NR_gettid);
+#elif defined(__DragonFly__) || defined(__FreeBSD__) // WEBRTC_BSD
+ return pthread_getthreadid_np();
+#elif defined(__NetBSD__) // WEBRTC_BSD
+ return _lwp_self();
+#elif defined(__OpenBSD__) // WEBRTC_BSD
+ return getthrid();
#elif defined(__EMSCRIPTEN__)
return static_cast<PlatformThreadId>(pthread_self());
#else
@@ -116,6 +128,10 @@ void SetCurrentThreadName(const char* name) {
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name)); // NOLINT
#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
pthread_setname_np(name);
+#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) // WEBRTC_BSD
+ pthread_set_name_np(pthread_self(), name);
+#elif defined(__NetBSD__) // WEBRTC_BSD
+ pthread_setname_np(pthread_self(), "%s", (void*)name);
#elif defined(WEBRTC_FUCHSIA)
zx_status_t status = zx_object_set_property(zx_thread_self(), ZX_PROP_NAME,
name, strlen(name));
--
2.47.1

View File

@ -0,0 +1,336 @@
From fed81a77c9a9bc366556f732324cdc5f9e7b09e9 Mon Sep 17 00:00:00 2001
From: Arun Raghavan <arun@asymptotic.io>
Date: Thu, 26 Dec 2024 14:24:40 -0500
Subject: [PATCH] Allow disabling inline SSE
Should make building on i686 without SSE feasible.
Fixes: https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/issues/5
---
meson.build | 14 ++++++++++++--
meson_options.txt | 5 ++++-
.../audio_processing/aec3/adaptive_fir_filter.cc | 14 ++++++++++----
.../aec3/adaptive_fir_filter_erl.cc | 6 ++++--
webrtc/modules/audio_processing/aec3/fft_data.h | 4 +++-
.../audio_processing/aec3/matched_filter.cc | 6 ++++--
webrtc/modules/audio_processing/aec3/vector_math.h | 8 +++++---
.../audio_processing/agc2/rnn_vad/vector_math.h | 4 +++-
webrtc/third_party/pffft/meson.build | 2 +-
9 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/meson.build b/meson.build
index 811d795..ebf053a 100644
--- a/meson.build
+++ b/meson.build
@@ -110,6 +110,7 @@ have_neon = false
have_mips = false
have_mips64 = false
have_x86 = false
+have_inline_sse = false
have_avx2 = false
if host_machine.cpu_family() == 'arm'
if cc.compiles('''#ifndef __ARM_ARCH_ISA_ARM
@@ -140,10 +141,19 @@ if host_machine.cpu_family() == 'mips64'
endif
if ['x86', 'x86_64'].contains(host_machine.cpu_family())
have_x86 = true
- # This is unconditionally enabled for now, actual usage is determined by
- # runtime CPU detection, so we're just assuming the compiler supports avx2
+ # AVX2 support is unconditionally available, since all the code (compiled
+ # with -mavx2) is in separate files from runtime detection (which should not
+ # be compiled with SIMD flags for cases where the CPU does not support it).
+ # Unfortunately, a bunch of SSE code is inline with the runtime detection,
+ # and we can't support that on systems that don't support SSE.
have_avx2 = true
arch_cflags += ['-DWEBRTC_ENABLE_AVX2']
+ if get_option('inline-sse')
+ have_inline_sse = true
+ else
+ have_inline_sse = false
+ arch_cflags += ['-DWAP_DISABLE_INLINE_SSE']
+ endif
endif
neon_opt = get_option('neon')
diff --git a/meson_options.txt b/meson_options.txt
index c939fb9..d08f356 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -3,4 +3,7 @@ option('gnustl', type: 'feature',
description: 'Use gnustl for a c++ library implementation (only used on Android)')
option('neon', type: 'combo',
choices: ['no', 'yes', 'auto', 'runtime'],
- description: '')
+ description: 'Enable NEON optimisations')
+option('inline-sse', type: 'boolean',
+ value: true,
+ description: 'Enable inline SSE/SSE2 optimisations (i.e. assume CPU supports SSE/SSE2)')
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
index 917aa95..ded0511 100644
--- a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
@@ -16,7 +16,7 @@
#if defined(WEBRTC_HAS_NEON)
#include <arm_neon.h>
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
#include <emmintrin.h>
#endif
#include <math.h>
@@ -88,7 +88,7 @@ void ComputeFrequencyResponse_Neon(
}
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
// Computes and stores the frequency response of the filter.
void ComputeFrequencyResponse_Sse2(
size_t num_partitions,
@@ -212,7 +212,7 @@ void AdaptPartitions_Neon(const RenderBuffer& render_buffer,
}
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
// Adapts the filter partitions. (SSE2 variant)
void AdaptPartitions_Sse2(const RenderBuffer& render_buffer,
const FftData& G,
@@ -377,7 +377,7 @@ void ApplyFilter_Neon(const RenderBuffer& render_buffer,
}
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
// Produces the filter output (SSE2 variant).
void ApplyFilter_Sse2(const RenderBuffer& render_buffer,
size_t num_partitions,
@@ -557,9 +557,11 @@ void AdaptiveFirFilter::Filter(const RenderBuffer& render_buffer,
RTC_DCHECK(S);
switch (optimization_) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2:
aec3::ApplyFilter_Sse2(render_buffer, current_size_partitions_, H_, S);
break;
+#endif
case Aec3Optimization::kAvx2:
aec3::ApplyFilter_Avx2(render_buffer, current_size_partitions_, H_, S);
break;
@@ -601,9 +603,11 @@ void AdaptiveFirFilter::ComputeFrequencyResponse(
switch (optimization_) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2:
aec3::ComputeFrequencyResponse_Sse2(current_size_partitions_, H_, H2);
break;
+#endif
case Aec3Optimization::kAvx2:
aec3::ComputeFrequencyResponse_Avx2(current_size_partitions_, H_, H2);
break;
@@ -626,10 +630,12 @@ void AdaptiveFirFilter::AdaptAndUpdateSize(const RenderBuffer& render_buffer,
// Adapt the filter.
switch (optimization_) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2:
aec3::AdaptPartitions_Sse2(render_buffer, G, current_size_partitions_,
&H_);
break;
+#endif
case Aec3Optimization::kAvx2:
aec3::AdaptPartitions_Avx2(render_buffer, G, current_size_partitions_,
&H_);
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
index 45b8813..920d51c 100644
--- a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
@@ -16,7 +16,7 @@
#if defined(WEBRTC_HAS_NEON)
#include <arm_neon.h>
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
#include <emmintrin.h>
#endif
@@ -54,7 +54,7 @@ void ErlComputer_NEON(
}
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
// Computes and stores the echo return loss estimate of the filter, which is the
// sum of the partition frequency responses.
void ErlComputer_SSE2(
@@ -82,9 +82,11 @@ void ComputeErl(const Aec3Optimization& optimization,
// Update the frequency response and echo return loss for the filter.
switch (optimization) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2:
aec3::ErlComputer_SSE2(H2, erl);
break;
+#endif
case Aec3Optimization::kAvx2:
aec3::ErlComputer_AVX2(H2, erl);
break;
diff --git a/webrtc/modules/audio_processing/aec3/fft_data.h b/webrtc/modules/audio_processing/aec3/fft_data.h
index 9c25e78..892407d 100644
--- a/webrtc/modules/audio_processing/aec3/fft_data.h
+++ b/webrtc/modules/audio_processing/aec3/fft_data.h
@@ -14,7 +14,7 @@
// Defines WEBRTC_ARCH_X86_FAMILY, used below.
#include "rtc_base/system/arch.h"
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
#include <emmintrin.h>
#endif
#include <algorithm>
@@ -49,6 +49,7 @@ struct FftData {
RTC_DCHECK_EQ(kFftLengthBy2Plus1, power_spectrum.size());
switch (optimization) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2: {
constexpr int kNumFourBinBands = kFftLengthBy2 / 4;
constexpr int kLimit = kNumFourBinBands * 4;
@@ -63,6 +64,7 @@ struct FftData {
power_spectrum[kFftLengthBy2] = re[kFftLengthBy2] * re[kFftLengthBy2] +
im[kFftLengthBy2] * im[kFftLengthBy2];
} break;
+#endif
case Aec3Optimization::kAvx2:
SpectrumAVX2(power_spectrum);
break;
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter.cc b/webrtc/modules/audio_processing/aec3/matched_filter.cc
index 59a3b46..86f365a 100644
--- a/webrtc/modules/audio_processing/aec3/matched_filter.cc
+++ b/webrtc/modules/audio_processing/aec3/matched_filter.cc
@@ -15,7 +15,7 @@
#if defined(WEBRTC_HAS_NEON)
#include <arm_neon.h>
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
#include <emmintrin.h>
#endif
#include <algorithm>
@@ -286,7 +286,7 @@ void MatchedFilterCore_NEON(size_t x_start_index,
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
void MatchedFilterCore_AccumulatedError_SSE2(
size_t x_start_index,
@@ -695,12 +695,14 @@ void MatchedFilter::Update(const DownsampledRenderBuffer& render_buffer,
switch (optimization_) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2:
aec3::MatchedFilterCore_SSE2(
x_start_index, x2_sum_threshold, smoothing, render_buffer.buffer, y,
filters_[n], &filters_updated, &error_sum, compute_pre_echo,
instantaneous_accumulated_error_, scratch_memory_);
break;
+#endif
case Aec3Optimization::kAvx2:
aec3::MatchedFilterCore_AVX2(
x_start_index, x2_sum_threshold, smoothing, render_buffer.buffer, y,
diff --git a/webrtc/modules/audio_processing/aec3/vector_math.h b/webrtc/modules/audio_processing/aec3/vector_math.h
index e4d1381..1506a44 100644
--- a/webrtc/modules/audio_processing/aec3/vector_math.h
+++ b/webrtc/modules/audio_processing/aec3/vector_math.h
@@ -17,7 +17,7 @@
#if defined(WEBRTC_HAS_NEON)
#include <arm_neon.h>
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
#include <emmintrin.h>
#endif
#include <math.h>
@@ -43,7 +43,7 @@ class VectorMath {
void SqrtAVX2(rtc::ArrayView<float> x);
void Sqrt(rtc::ArrayView<float> x) {
switch (optimization_) {
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2: {
const int x_size = static_cast<int>(x.size());
const int vector_limit = x_size >> 2;
@@ -123,7 +123,7 @@ class VectorMath {
RTC_DCHECK_EQ(z.size(), x.size());
RTC_DCHECK_EQ(z.size(), y.size());
switch (optimization_) {
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2: {
const int x_size = static_cast<int>(x.size());
const int vector_limit = x_size >> 2;
@@ -174,6 +174,7 @@ class VectorMath {
RTC_DCHECK_EQ(z.size(), x.size());
switch (optimization_) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if !defined(WAP_DISABLE_INLINE_SSE)
case Aec3Optimization::kSse2: {
const int x_size = static_cast<int>(x.size());
const int vector_limit = x_size >> 2;
@@ -190,6 +191,7 @@ class VectorMath {
z[j] += x[j];
}
} break;
+#endif
case Aec3Optimization::kAvx2:
AccumulateAVX2(x, z);
break;
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/vector_math.h b/webrtc/modules/audio_processing/agc2/rnn_vad/vector_math.h
index 47f6811..f965086 100644
--- a/webrtc/modules/audio_processing/agc2/rnn_vad/vector_math.h
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/vector_math.h
@@ -17,7 +17,7 @@
#if defined(WEBRTC_HAS_NEON)
#include <arm_neon.h>
#endif
-#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(WAP_DISABLE_INLINE_SSE)
#include <emmintrin.h>
#endif
@@ -47,6 +47,7 @@ class VectorMath {
if (cpu_features_.avx2) {
return DotProductAvx2(x, y);
} else if (cpu_features_.sse2) {
+#if !defined(WAP_DISABLE_INLINE_SSE)
__m128 accumulator = _mm_setzero_ps();
constexpr int kBlockSizeLog2 = 2;
constexpr int kBlockSize = 1 << kBlockSizeLog2;
@@ -72,6 +73,7 @@ class VectorMath {
dot_product += x[i] * y[i];
}
return dot_product;
+#endif
}
#elif defined(WEBRTC_HAS_NEON) && defined(WEBRTC_ARCH_ARM64)
if (cpu_features_.neon) {
diff --git a/webrtc/third_party/pffft/meson.build b/webrtc/third_party/pffft/meson.build
index c1eb5c6..cf4c9c7 100644
--- a/webrtc/third_party/pffft/meson.build
+++ b/webrtc/third_party/pffft/meson.build
@@ -4,7 +4,7 @@ pffft_sources = [
pffft_cflags = [ '-D_GNU_SOURCE' ]
-if (have_arm and not have_neon) or (have_mips and host_machine.endian() == 'little') or have_mips64
+if not have_inline_sse or (have_arm and not have_neon) or (have_mips and host_machine.endian() == 'little') or have_mips64
pffft_cflags += [ '-DPFFFT_SIMD_DISABLE' ]
endif
--
2.47.1

View File

@ -0,0 +1,68 @@
From ad563b095cea13730ca95e77d50e352ea9e344a9 Mon Sep 17 00:00:00 2001
From: Arun Raghavan <arun@asymptotic.io>
Date: Fri, 15 Dec 2023 16:06:05 -0500
Subject: [PATCH] Fix up XMM intrinsics usage on MSVC
Repplying 0a0050746bc20ef970b9f260d485e4367c7ba854 after M131 bump.
---
.../aec3/matched_filter_avx2.cc | 30 ++++++++++++-------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc b/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc
index 8c2ffcb..65a1b76 100644
--- a/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc
+++ b/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc
@@ -13,6 +13,16 @@
#include "modules/audio_processing/aec3/matched_filter.h"
#include "rtc_base/checks.h"
+#ifdef _MSC_VER
+// Visual Studio
+#define LOOKUP_M128(v, i) v.m128_f32[i]
+#define LOOKUP_M256(v, i) v.m256_f32[i]
+#else
+// GCC/Clang
+#define LOOKUP_M128(v, i) v[i]
+#define LOOKUP_M256(v, i) v[i]
+#endif
+
namespace webrtc {
namespace aec3 {
@@ -81,14 +91,14 @@ void MatchedFilterCore_AccumulatedError_AVX2(
s_inst_256_8 = _mm256_mul_ps(h_k_8, x_k_8);
s_inst_hadd_256 = _mm256_hadd_ps(s_inst_256, s_inst_256_8);
s_inst_hadd_256 = _mm256_hadd_ps(s_inst_hadd_256, s_inst_hadd_256);
- s_acum += s_inst_hadd_256[0];
- e_128[0] = s_acum - y[i];
- s_acum += s_inst_hadd_256[4];
- e_128[1] = s_acum - y[i];
- s_acum += s_inst_hadd_256[1];
- e_128[2] = s_acum - y[i];
- s_acum += s_inst_hadd_256[5];
- e_128[3] = s_acum - y[i];
+ s_acum += LOOKUP_M256(s_inst_hadd_256, 0);
+ LOOKUP_M128(e_128, 0) = s_acum - y[i];
+ s_acum += LOOKUP_M256(s_inst_hadd_256,4);
+ LOOKUP_M128(e_128, 1) = s_acum - y[i];
+ s_acum += LOOKUP_M256(s_inst_hadd_256,1);
+ LOOKUP_M128(e_128, 2) = s_acum - y[i];
+ s_acum += LOOKUP_M256(s_inst_hadd_256,5);
+ LOOKUP_M128(e_128, 3) = s_acum - y[i];
__m128 accumulated_error = _mm_load_ps(a_p);
accumulated_error = _mm_fmadd_ps(e_128, e_128, accumulated_error);
@@ -209,8 +219,8 @@ void MatchedFilterCore_AVX2(size_t x_start_index,
x2_sum_256 = _mm256_add_ps(x2_sum_256, x2_sum_256_8);
s_256 = _mm256_add_ps(s_256, s_256_8);
__m128 sum = hsum_ab(x2_sum_256, s_256);
- x2_sum += sum[0];
- s += sum[1];
+ x2_sum += LOOKUP_M128(sum, 0);
+ s += LOOKUP_M128(sum, 1);
// Compute the matched filter error.
float e = y[i] - s;
--
2.47.1

View File

@ -0,0 +1,51 @@
From a9f97c9fdd490e35bd43d6463424eee5b44c4a7d Mon Sep 17 00:00:00 2001
From: Arun Raghavan <arun@asymptotic.io>
Date: Fri, 18 Jun 2021 18:40:32 -0400
Subject: [PATCH] Some fixes for MinGW
* Rename Windows.h uses to windows.h
* Comment out structured exception handling usage
Makes MinGW happier. Mostly the same as previous work by
Nicolas Dufresne <nicolas.dufresne@collabora.com>, with the exception
that we now don't try to invoke RaiseException which would fail in MinGW
as it raises a Windows structured exception.
---
webrtc/rtc_base/platform_thread_types.cc | 2 ++
webrtc/rtc_base/system/file_wrapper.cc | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/webrtc/rtc_base/platform_thread_types.cc b/webrtc/rtc_base/platform_thread_types.cc
index e98e8ec..1a24881 100644
--- a/webrtc/rtc_base/platform_thread_types.cc
+++ b/webrtc/rtc_base/platform_thread_types.cc
@@ -118,11 +118,13 @@ void SetCurrentThreadName(const char* name) {
#pragma warning(push)
#pragma warning(disable : 6320 6322)
+#ifndef __MINGW32__
__try {
::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR),
reinterpret_cast<ULONG_PTR*>(&threadname_info));
} __except (EXCEPTION_EXECUTE_HANDLER) { // NOLINT
}
+#endif
#pragma warning(pop)
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name)); // NOLINT
diff --git a/webrtc/rtc_base/system/file_wrapper.cc b/webrtc/rtc_base/system/file_wrapper.cc
index 12c27a5..3203bc6 100644
--- a/webrtc/rtc_base/system/file_wrapper.cc
+++ b/webrtc/rtc_base/system/file_wrapper.cc
@@ -22,7 +22,7 @@
#include "rtc_base/numerics/safe_conversions.h"
#ifdef _WIN32
-#include <Windows.h>
+#include <windows.h>
#else
#endif
--
2.47.1

View File

@ -0,0 +1,45 @@
From 4a17c682e9a173c27feec9e67fb8c4c36090b1a6 Mon Sep 17 00:00:00 2001
From: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Date: Fri, 25 Oct 2024 01:53:16 +0300
Subject: [PATCH] common_audio: Add MIPS_DSP_R1_LE guard for vector scaling ops
The MIPS-specific source for vector scaling operations fails to build on
Debian's mips64el:
[97/303] Compiling C object webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o
FAILED: webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o
cc [...] webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o.d -o webrtc/common_audio/libcommon_audio.a.p/signal_processing_vector_scaling_operations_mips.c.o -c ../webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
/tmp/cc7UGPkY.s: Assembler messages:
/tmp/cc7UGPkY.s:57: Error: opcode not supported on this processor: mips64r2 (mips64r2) `extrv_r.w $3,$ac0,$8'
ninja: build stopped: subcommand failed.
The EXTRV_R.W instruction it uses is part of DSP extensions for this
architecture. In signal_processing_library.h, this function's prototype
is guarded with #if defined(MIPS_DSP_R1_LE). Guard the implementation
like that as well to fix the error.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
---
.../signal_processing/vector_scaling_operations_mips.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c b/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
index ba2d26d..08ca293 100644
--- a/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
+++ b/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
@@ -16,6 +16,7 @@
#include "common_audio/signal_processing/include/signal_processing_library.h"
+#if defined(MIPS_DSP_R1_LE)
int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1,
int16_t in_vector1_scale,
const int16_t* in_vector2,
@@ -55,3 +56,4 @@ int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1,
}
return 0;
}
+#endif
--
2.47.1

View File

@ -0,0 +1,46 @@
From c555fb6eaf0568c2205bbd197ebbcc0e85714c77 Mon Sep 17 00:00:00 2001
From: Nirbheek Chauhan <nirbheek@centricular.com>
Date: Fri, 26 May 2023 02:20:56 +0530
Subject: [PATCH] meson: Fixes for MSVC build
winsock2.h must be included before windows.h or alternative
definitions of `struct sockaddr` are defined.
```
FAILED: webrtc/rtc_base/liblibbase.a.p/logging.cc.obj
"cl" "-Iwebrtc\rtc_base\liblibbase.a.p" "-Iwebrtc\rtc_base" "-I..\webrtc\rtc_base" "-Iwebrtc" "-I..\webrtc" "-Isubprojects\abseil-cpp-20230125.1" "-I..\subprojects\abseil-cpp-20230125.1" "/MD" "/nologo" "/showIncludes" "/utf-8" "/Zc:__cplusplus" "/W2" "/EHsc" "/std:c++17" "/permissive-" "/O2" "/Zi" "-DWEBRTC_LIBRARY_
IMPL" "-DWEBRTC_ENABLE_SYMBOL_EXPORT" "-DNDEBUG" "-DWEBRTC_WIN" "-D_WIN32" "-U__STRICT_ANSI__" "-D__STDC_FORMAT_MACROS=1" "-DNOMINMAX" "-DWEBRTC_ENABLE_AVX2" "/Fdwebrtc\rtc_base\liblibbase.a.p\logging.cc.pdb" /Fowebrtc/rtc_base/liblibbase.a.p/logging.cc.obj "/c" ../webrtc/rtc_base/logging.cc
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(103): warning C4005: 'AF_IPX': macro redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(457): note: see previous definition of 'AF_IPX'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(147): warning C4005: 'AF_MAX': macro redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(476): note: see previous definition of 'AF_MAX'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(187): warning C4005: 'SO_DONTLINGER': macro redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(399): note: see previous definition of 'SO_DONTLINGER'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(240): error C2011: 'sockaddr': 'struct' type redefinition
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um\winsock.h(482): note: see declaration of 'sockaddr'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(442): error C2143: syntax error: missing '}' before 'constant'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(442): error C2059: syntax error: 'constant'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(496): error C2143: syntax error: missing ';' before '}'
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(496): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared\ws2def.h(496): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
...
```
---
webrtc/rtc_base/logging.cc | 1 +
1 file changed, 1 insertion(+)
diff --git a/webrtc/rtc_base/logging.cc b/webrtc/rtc_base/logging.cc
index 61a3c66..825c686 100644
--- a/webrtc/rtc_base/logging.cc
+++ b/webrtc/rtc_base/logging.cc
@@ -15,6 +15,7 @@
#if RTC_LOG_ENABLED()
#if defined(WEBRTC_WIN)
+#include <winsock2.h>
#include <windows.h>
#if _MSC_VER < 1900
#define snprintf _snprintf
--
2.47.1

View File

@ -1,13 +1,13 @@
[wrap-file] [wrap-file]
directory = abseil-cpp-20230125.1 directory = abseil-cpp-20240722.0
source_url = https://github.com/abseil/abseil-cpp/archive/20230125.1.tar.gz source_url = https://github.com/abseil/abseil-cpp/releases/download/20240722.0/abseil-cpp-20240722.0.tar.gz
source_filename = abseil-cpp-20230125.1.tar.gz source_filename = abseil-cpp-20240722.0.tar.gz
source_hash = 81311c17599b3712069ded20cca09a62ab0bf2a89dfa16993786c8782b7ed145 source_hash = f50e5ac311a81382da7fa75b97310e4b9006474f9560ac46f54a9967f07d4ae3
patch_filename = abseil-cpp_20230125.1-4_patch.zip patch_filename = abseil-cpp_20240722.0-3_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/abseil-cpp_20230125.1-4/get_patch patch_url = https://wrapdb.mesonbuild.com/v2/abseil-cpp_20240722.0-3/get_patch
patch_hash = 112ee72052049d930396c2778fc1c6e184137905dd75d60a97dcfc386426610d patch_hash = 12dd8df1488a314c53e3751abd2750cf233b830651d168b6a9f15e7d0cf71f7b
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/abseil-cpp_20230125.1-4/abseil-cpp-20230125.1.tar.gz source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/abseil-cpp_20240722.0-3/abseil-cpp-20240722.0.tar.gz
wrapdb_version = 20230125.1-4 wrapdb_version = 20240722.0-3
[provide] [provide]
absl_base = absl_base_dep absl_base = absl_base_dep
@ -25,19 +25,26 @@ absl_strings = absl_strings_dep
absl_synchronization = absl_synchronization_dep absl_synchronization = absl_synchronization_dep
absl_time = absl_time_dep absl_time = absl_time_dep
absl_types = absl_types_dep absl_types = absl_types_dep
absl_algorithm_container = absl_base_dep
absl_any_invocable = absl_base_dep
absl_bad_any_cast_impl = absl_types_dep absl_bad_any_cast_impl = absl_types_dep
absl_bad_optional_access = absl_types_dep absl_bad_optional_access = absl_types_dep
absl_bad_variant_access = absl_types_dep absl_bad_variant_access = absl_types_dep
absl_bind_front = absl_base_dep
absl_city = absl_hash_dep absl_city = absl_hash_dep
absl_civil_time = absl_time_dep absl_civil_time = absl_time_dep
absl_cleanup = absl_base_dep
absl_cord = absl_strings_dep absl_cord = absl_strings_dep
absl_cord_internal = absl_strings_dep absl_cord_internal = absl_strings_dep
absl_cordz_functions = absl_strings_dep absl_cordz_functions = absl_strings_dep
absl_cordz_handle = absl_strings_dep absl_cordz_handle = absl_strings_dep
absl_cordz_info = absl_strings_dep absl_cordz_info = absl_strings_dep
absl_cordz_sample_token = absl_strings_dep absl_cordz_sample_token = absl_strings_dep
absl_core_headers = absl_base_dep
absl_crc32c = absl_crc_dep
absl_debugging_internal = absl_debugging_dep absl_debugging_internal = absl_debugging_dep
absl_demangle_internal = absl_debugging_dep absl_demangle_internal = absl_debugging_dep
absl_die_if_null = absl_log_dep
absl_examine_stack = absl_debugging_dep absl_examine_stack = absl_debugging_dep
absl_exponential_biased = absl_profiling_dep absl_exponential_biased = absl_profiling_dep
absl_failure_signal_handler = absl_debugging_dep absl_failure_signal_handler = absl_debugging_dep
@ -52,13 +59,23 @@ absl_flags_program_name = absl_flags_dep
absl_flags_reflection = absl_flags_dep absl_flags_reflection = absl_flags_dep
absl_flags_usage = absl_flags_dep absl_flags_usage = absl_flags_dep
absl_flags_usage_internal = absl_flags_dep absl_flags_usage_internal = absl_flags_dep
absl_flat_hash_map = absl_container_dep
absl_flat_hash_set = absl_container_dep
absl_function_ref = absl_base_dep
absl_graphcycles_internal = absl_synchronization_dep absl_graphcycles_internal = absl_synchronization_dep
absl_hashtablez_sampler = absl_container_dep absl_hashtablez_sampler = absl_container_dep
absl_inlined_vector = absl_container_dep
absl_int128 = absl_numeric_dep absl_int128 = absl_numeric_dep
absl_leak_check = absl_debugging_dep absl_leak_check = absl_debugging_dep
absl_log_initialize = absl_log_dep
absl_log_internal_check_op = absl_log_dep
absl_log_internal_message = absl_log_dep
absl_log_severity = absl_base_dep absl_log_severity = absl_base_dep
absl_low_level_hash = absl_hash_dep absl_low_level_hash = absl_hash_dep
absl_memory = absl_base_dep
absl_optional = absl_types_dep
absl_periodic_sampler = absl_profiling_dep absl_periodic_sampler = absl_profiling_dep
absl_random_bit_gen_ref = absl_random_dep
absl_random_distributions = absl_random_dep absl_random_distributions = absl_random_dep
absl_random_internal_distribution_test_util = absl_random_dep absl_random_internal_distribution_test_util = absl_random_dep
absl_random_internal_platform = absl_random_dep absl_random_internal_platform = absl_random_dep
@ -68,17 +85,24 @@ absl_random_internal_randen_hwaes = absl_random_dep
absl_random_internal_randen_hwaes_impl = absl_random_dep absl_random_internal_randen_hwaes_impl = absl_random_dep
absl_random_internal_randen_slow = absl_random_dep absl_random_internal_randen_slow = absl_random_dep
absl_random_internal_seed_material = absl_random_dep absl_random_internal_seed_material = absl_random_dep
absl_random_random = absl_random_dep
absl_random_seed_gen_exception = absl_random_dep absl_random_seed_gen_exception = absl_random_dep
absl_random_seed_sequences = absl_random_dep absl_random_seed_sequences = absl_random_dep
absl_raw_hash_set = absl_container_dep absl_raw_hash_set = absl_container_dep
absl_raw_logging_internal = absl_base_dep absl_raw_logging_internal = absl_base_dep
absl_scoped_set_env = absl_base_dep absl_scoped_set_env = absl_base_dep
absl_span = absl_types_dep
absl_spinlock_wait = absl_base_dep absl_spinlock_wait = absl_base_dep
absl_stacktrace = absl_debugging_dep absl_stacktrace = absl_debugging_dep
absl_statusor = absl_status_dep absl_statusor = absl_status_dep
absl_strerror = absl_base_dep absl_str_format = absl_strings_dep
absl_str_format_internal = absl_strings_dep absl_str_format_internal = absl_strings_dep
absl_strerror = absl_base_dep
absl_string_view = absl_strings_dep
absl_strings_internal = absl_strings_dep absl_strings_internal = absl_strings_dep
absl_symbolize = absl_debugging_dep absl_symbolize = absl_debugging_dep
absl_throw_delegate = absl_base_dep absl_throw_delegate = absl_base_dep
absl_time_zone = absl_time_dep absl_time_zone = absl_time_dep
absl_type_traits = absl_base_dep
absl_utility = absl_base_dep
absl_variant = absl_types_dep

View File

@ -12,6 +12,15 @@
# you add a new build file, there must be some path of dependencies from this # you add a new build file, there must be some path of dependencies from this
# file to your new one or GN won't know about it. # file to your new one or GN won't know about it.
# Use of visibility = clauses:
# The default visibility for all rtc_ targets is equivalent to "//*", or
# "all targets in webrtc can depend on this, nothing outside can".
#
# When overriding, the choices are:
# - visibility = [ "*" ] - public. Stuff outside webrtc can use this.
# - visibility = [ ":*" ] - directory private.
# As a general guideline, only targets in api/ should have public visibility.
import("//build/config/linux/pkg_config.gni") import("//build/config/linux/pkg_config.gni")
import("//build/config/sanitizers/sanitizers.gni") import("//build/config/sanitizers/sanitizers.gni")
import("webrtc.gni") import("webrtc.gni")
@ -21,6 +30,7 @@ if (rtc_enable_protobuf) {
if (is_android) { if (is_android) {
import("//build/config/android/config.gni") import("//build/config/android/config.gni")
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
import("//third_party/jni_zero/jni_zero.gni")
} }
if (!build_with_chromium) { if (!build_with_chromium) {
@ -38,7 +48,6 @@ if (!build_with_chromium) {
if (rtc_include_tests) { if (rtc_include_tests) {
deps += [ deps += [
":rtc_unittests", ":rtc_unittests",
":slow_tests",
":video_engine_tests", ":video_engine_tests",
":voip_unittests", ":voip_unittests",
":webrtc_nonparallel_tests", ":webrtc_nonparallel_tests",
@ -54,9 +63,14 @@ if (!build_with_chromium) {
"modules/remote_bitrate_estimator:rtp_to_text", "modules/remote_bitrate_estimator:rtp_to_text",
"modules/rtp_rtcp:test_packet_masks_metrics", "modules/rtp_rtcp:test_packet_masks_metrics",
"modules/video_capture:video_capture_internal_impl", "modules/video_capture:video_capture_internal_impl",
"modules/video_coding:video_codec_perf_tests",
"net/dcsctp:dcsctp_unittests",
"pc:peerconnection_unittests", "pc:peerconnection_unittests",
"pc:rtc_pc_unittests", "pc:rtc_pc_unittests",
"pc:slow_peer_connection_unittests",
"pc:svc_tests",
"rtc_tools:rtp_generator", "rtc_tools:rtp_generator",
"rtc_tools:video_encoder",
"rtc_tools:video_replay", "rtc_tools:video_replay",
"stats:rtc_stats_unittests", "stats:rtc_stats_unittests",
"system_wrappers:system_wrappers_unittests", "system_wrappers:system_wrappers_unittests",
@ -65,12 +79,22 @@ if (!build_with_chromium) {
"video:sv_loopback", "video:sv_loopback",
"video:video_loopback", "video:video_loopback",
] ]
if (use_libfuzzer) {
deps += [ "test/fuzzers" ]
}
if (!is_asan) { if (!is_asan) {
# Do not build :webrtc_lib_link_test because lld complains on some OS # Do not build :webrtc_lib_link_test because lld complains on some OS
# (e.g. when target_os = "mac") when is_asan=true. For more details, # (e.g. when target_os = "mac") when is_asan=true. For more details,
# see bugs.webrtc.org/11027#c5. # see bugs.webrtc.org/11027#c5.
deps += [ ":webrtc_lib_link_test" ] deps += [ ":webrtc_lib_link_test" ]
} }
if (is_ios) {
deps += [
"examples:apprtcmobile_tests",
"sdk:sdk_framework_unittests",
"sdk:sdk_unittests",
]
}
if (is_android) { if (is_android) {
deps += [ deps += [
"examples:android_examples_junit_tests", "examples:android_examples_junit_tests",
@ -82,11 +106,16 @@ if (!build_with_chromium) {
} }
if (rtc_enable_protobuf) { if (rtc_enable_protobuf) {
deps += [ deps += [
"audio:low_bandwidth_audio_test",
"logging:rtc_event_log_rtp_dump", "logging:rtc_event_log_rtp_dump",
"tools_webrtc/perf:webrtc_dashboard_upload", "tools_webrtc/perf:webrtc_dashboard_upload",
] ]
} }
if ((is_linux || is_chromeos) && rtc_use_pipewire) {
deps += [ "modules/desktop_capture:shared_screencast_stream_test" ]
}
}
if (target_os == "android") {
deps += [ "tools_webrtc:binary_version_check" ]
} }
} }
} }
@ -113,12 +142,19 @@ config("common_inherited_config") {
cflags = [] cflags = []
ldflags = [] ldflags = []
if (rtc_enable_symbol_export || is_component_build) { if (rtc_objc_prefix != "") {
defines = [ "WEBRTC_ENABLE_SYMBOL_EXPORT" ] defines += [ "RTC_OBJC_TYPE_PREFIX=${rtc_objc_prefix}" ]
} }
if (build_with_mozilla) { if (rtc_dlog_always_on) {
defines += [ "WEBRTC_MOZILLA_BUILD" ] defines += [ "DLOG_ALWAYS_ON" ]
}
if (rtc_enable_symbol_export || is_component_build) {
defines += [ "WEBRTC_ENABLE_SYMBOL_EXPORT" ]
}
if (rtc_enable_objc_symbol_export) {
defines += [ "WEBRTC_ENABLE_OBJC_SYMBOL_EXPORT" ]
} }
if (!rtc_builtin_ssl_root_certificates) { if (!rtc_builtin_ssl_root_certificates) {
@ -133,16 +169,22 @@ config("common_inherited_config") {
defines += [ "WEBRTC_ENABLE_AVX2" ] defines += [ "WEBRTC_ENABLE_AVX2" ]
} }
# Some tests need to declare their own trace event handlers. If this define is if (rtc_enable_win_wgc) {
# not set, the first time TRACE_EVENT_* is called it will store the return defines += [ "RTC_ENABLE_WIN_WGC" ]
# value for the current handler in an static variable, so that subsequent }
# changes to the handler for that TRACE_EVENT_* will be ignored.
# So when tests are included, we set this define, making it possible to use if (!rtc_use_perfetto) {
# different event handlers in different tests. # Some tests need to declare their own trace event handlers. If this define is
if (rtc_include_tests) { # not set, the first time TRACE_EVENT_* is called it will store the return
defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=1" ] # value for the current handler in an static variable, so that subsequent
} else { # changes to the handler for that TRACE_EVENT_* will be ignored.
defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0" ] # So when tests are included, we set this define, making it possible to use
# different event handlers in different tests.
if (rtc_include_tests) {
defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=1" ]
} else {
defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0" ]
}
} }
if (build_with_chromium) { if (build_with_chromium) {
defines += [ "WEBRTC_CHROMIUM_BUILD" ] defines += [ "WEBRTC_CHROMIUM_BUILD" ]
@ -210,14 +252,6 @@ config("common_inherited_config") {
} }
} }
# TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning
# as soon as WebRTC compiles without it.
config("no_exit_time_destructors") {
if (is_clang) {
cflags = [ "-Wno-exit-time-destructors" ]
}
}
# TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning # TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning
# as soon as WebRTC compiles without it. # as soon as WebRTC compiles without it.
config("no_global_constructors") { config("no_global_constructors") {
@ -236,6 +270,33 @@ config("rtc_prod_config") {
} }
} }
group("tracing") {
all_dependent_configs = [ "//third_party/perfetto/gn:public_config" ]
if (rtc_use_perfetto) {
if (build_with_chromium) {
public_deps = # no-presubmit-check TODO(webrtc:8603)
[ "//third_party/perfetto:libperfetto" ]
} else {
public_deps = [ # no-presubmit-check TODO(webrtc:8603)
":webrtc_libperfetto",
"//third_party/perfetto/include/perfetto/tracing",
]
}
} else {
public_deps = # no-presubmit-check TODO(webrtc:8603)
[ "//third_party/perfetto/include/perfetto/tracing" ]
}
}
if (rtc_use_perfetto) {
rtc_library("webrtc_libperfetto") {
deps = [
"//third_party/perfetto/src/tracing:client_api_without_backends",
"//third_party/perfetto/src/tracing:platform_impl",
]
}
}
config("common_config") { config("common_config") {
cflags = [] cflags = []
cflags_c = [] cflags_c = []
@ -249,6 +310,18 @@ config("common_config") {
defines += [ "WEBRTC_ENABLE_PROTOBUF=0" ] defines += [ "WEBRTC_ENABLE_PROTOBUF=0" ]
} }
if (rtc_strict_field_trials == "") {
defines += [ "WEBRTC_STRICT_FIELD_TRIALS=0" ]
} else if (rtc_strict_field_trials == "dcheck") {
defines += [ "WEBRTC_STRICT_FIELD_TRIALS=1" ]
} else if (rtc_strict_field_trials == "warn") {
defines += [ "WEBRTC_STRICT_FIELD_TRIALS=2" ]
} else {
assert(false,
"Unsupported value for rtc_strict_field_trials: " +
"$rtc_strict_field_trials")
}
if (rtc_include_internal_audio_device) { if (rtc_include_internal_audio_device) {
defines += [ "WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE" ] defines += [ "WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE" ]
} }
@ -257,8 +330,16 @@ config("common_config") {
defines += [ "RTC_ENABLE_VP9" ] defines += [ "RTC_ENABLE_VP9" ]
} }
if (rtc_use_h265) {
defines += [ "RTC_ENABLE_H265" ]
}
if (rtc_include_dav1d_in_internal_decoder_factory) {
defines += [ "RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY" ]
}
if (rtc_enable_sctp) { if (rtc_enable_sctp) {
defines += [ "HAVE_SCTP" ] defines += [ "WEBRTC_HAVE_SCTP" ]
} }
if (rtc_enable_external_auth) { if (rtc_enable_external_auth) {
@ -273,6 +354,10 @@ config("common_config") {
defines += [ "WEBRTC_ABSL_MUTEX" ] defines += [ "WEBRTC_ABSL_MUTEX" ]
} }
if (rtc_enable_libevent) {
defines += [ "WEBRTC_ENABLE_LIBEVENT" ]
}
if (rtc_disable_logging) { if (rtc_disable_logging) {
defines += [ "RTC_DISABLE_LOGGING" ] defines += [ "RTC_DISABLE_LOGGING" ]
} }
@ -285,15 +370,20 @@ config("common_config") {
defines += [ "RTC_DISABLE_METRICS" ] defines += [ "RTC_DISABLE_METRICS" ]
} }
if (rtc_exclude_transient_suppressor) {
defines += [ "WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR" ]
}
if (rtc_exclude_audio_processing_module) { if (rtc_exclude_audio_processing_module) {
defines += [ "WEBRTC_EXCLUDE_AUDIO_PROCESSING_MODULE" ] defines += [ "WEBRTC_EXCLUDE_AUDIO_PROCESSING_MODULE" ]
} }
cflags = [] if (is_clang) {
cflags += [
# TODO(webrtc:13219): Fix -Wshadow instances and enable.
"-Wno-shadow",
# See https://reviews.llvm.org/D56731 for details about this
# warning.
"-Wctad-maybe-unsupported",
]
}
if (build_with_chromium) { if (build_with_chromium) {
defines += [ defines += [
@ -331,20 +421,9 @@ config("common_config") {
if (is_clang) { if (is_clang) {
cflags += [ cflags += [
"-Wc++11-narrowing", "-Wc++11-narrowing",
"-Wimplicit-fallthrough",
"-Wthread-safety",
"-Winconsistent-missing-override",
"-Wundef", "-Wundef",
"-Wunused-lambda-capture",
] ]
# use_xcode_clang only refers to the iOS toolchain, host binaries use
# chromium's clang always.
if (!is_nacl &&
(!use_xcode_clang || current_toolchain == host_toolchain)) {
# Flags NaCl (Clang 3.7) and Xcode 7.3 (Clang clang-703.0.31) do not
# recognize.
cflags += [ "-Wunused-lambda-capture" ]
}
} }
if (is_win && !is_clang) { if (is_win && !is_clang) {
@ -404,7 +483,7 @@ config("common_config") {
] ]
} }
if (use_fuzzing_engine && optimize_for_fuzzing) { if (use_fuzzing_engine) {
# Used in Chromium's overrides to disable logging # Used in Chromium's overrides to disable logging
defines += [ "WEBRTC_UNSAFE_FUZZER_MODE" ] defines += [ "WEBRTC_UNSAFE_FUZZER_MODE" ]
} }
@ -415,13 +494,25 @@ config("common_config") {
"/U_UNICODE", "/U_UNICODE",
] ]
} }
if (rtc_use_perfetto) {
defines += [ "RTC_USE_PERFETTO" ]
}
} }
config("common_objc") { config("common_objc") {
frameworks = [ "Foundation.framework" ] frameworks = [ "Foundation.framework" ]
}
if (rtc_use_metal_rendering) { if (!rtc_build_ssl) {
defines = [ "RTC_SUPPORTS_METAL" ] config("external_ssl_library") {
if (rtc_ssl_root != "") {
include_dirs = [ rtc_ssl_root ]
}
libs = [
"crypto",
"ssl",
]
} }
} }
@ -441,13 +532,26 @@ if (!build_with_chromium) {
deps = [ deps = [
"api:create_peerconnection_factory", "api:create_peerconnection_factory",
"api:enable_media",
"api:libjingle_peerconnection_api", "api:libjingle_peerconnection_api",
"api:rtc_error", "api:rtc_error",
"api:transport_api", "api:transport_api",
"api/audio_codecs:opus_audio_decoder_factory",
"api/crypto", "api/crypto",
"api/rtc_event_log:rtc_event_log_factory", "api/rtc_event_log:rtc_event_log_factory",
"api/task_queue", "api/task_queue",
"api/task_queue:default_task_queue_factory", "api/task_queue:default_task_queue_factory",
"api/test/metrics",
"api/video_codecs:video_decoder_factory_template",
"api/video_codecs:video_decoder_factory_template_dav1d_adapter",
"api/video_codecs:video_decoder_factory_template_libvpx_vp8_adapter",
"api/video_codecs:video_decoder_factory_template_libvpx_vp9_adapter",
"api/video_codecs:video_decoder_factory_template_open_h264_adapter",
"api/video_codecs:video_encoder_factory_template",
"api/video_codecs:video_encoder_factory_template_libaom_av1_adapter",
"api/video_codecs:video_encoder_factory_template_libvpx_vp8_adapter",
"api/video_codecs:video_encoder_factory_template_libvpx_vp9_adapter",
"api/video_codecs:video_encoder_factory_template_open_h264_adapter",
"audio", "audio",
"call", "call",
"common_audio", "common_audio",
@ -458,10 +562,7 @@ if (!build_with_chromium) {
"modules/video_capture:video_capture_internal_impl", "modules/video_capture:video_capture_internal_impl",
"p2p:rtc_p2p", "p2p:rtc_p2p",
"pc:libjingle_peerconnection", "pc:libjingle_peerconnection",
"pc:peerconnection",
"pc:rtc_pc", "pc:rtc_pc",
"pc:rtc_pc_base",
"rtc_base",
"sdk", "sdk",
"video", "video",
] ]
@ -473,13 +574,6 @@ if (!build_with_chromium) {
] ]
} }
if (rtc_include_builtin_video_codecs) {
deps += [
"api/video_codecs:builtin_video_decoder_factory",
"api/video_codecs:builtin_video_encoder_factory",
]
}
if (build_with_mozilla) { if (build_with_mozilla) {
deps += [ deps += [
"api/video:video_frame", "api/video:video_frame",
@ -504,6 +598,10 @@ if (!build_with_chromium) {
rtc_executable("webrtc_lib_link_test") { rtc_executable("webrtc_lib_link_test") {
testonly = true testonly = true
# This target is used for checking to link, so do not check dependencies
# on gn check.
check_includes = false # no-presubmit-check TODO(bugs.webrtc.org/12785)
sources = [ "webrtc_lib_link_test.cc" ] sources = [ "webrtc_lib_link_test.cc" ]
deps = [ deps = [
# NOTE: Don't add deps here. If this test fails to link, it means you # NOTE: Don't add deps here. If this test fails to link, it means you
@ -523,7 +621,17 @@ if (use_libfuzzer || use_afl) {
} }
} }
if (rtc_include_tests) { if (rtc_include_tests && !build_with_chromium) {
rtc_unittests_resources = [ "resources/reference_video_640x360_30fps.y4m" ]
if (is_ios) {
bundle_data("rtc_unittests_bundle_data") {
testonly = true
sources = rtc_unittests_resources
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
}
}
rtc_test("rtc_unittests") { rtc_test("rtc_unittests") {
testonly = true testonly = true
@ -533,13 +641,20 @@ if (rtc_include_tests) {
"api/audio/test:audio_api_unittests", "api/audio/test:audio_api_unittests",
"api/audio_codecs/test:audio_codecs_api_unittests", "api/audio_codecs/test:audio_codecs_api_unittests",
"api/numerics:numerics_unittests", "api/numerics:numerics_unittests",
"api/task_queue:pending_task_safety_flag_unittests",
"api/test/metrics:metrics_unittests",
"api/transport:stun_unittest", "api/transport:stun_unittest",
"api/video/test:rtc_api_video_unittests", "api/video/test:rtc_api_video_unittests",
"api/video_codecs:libaom_av1_encoder_factory_test",
"api/video_codecs:simple_encoder_wrapper_unittests",
"api/video_codecs/test:video_codecs_api_unittests", "api/video_codecs/test:video_codecs_api_unittests",
"api/voip:compile_all_headers",
"call:fake_network_pipe_unittests", "call:fake_network_pipe_unittests",
"p2p:libstunprober_unittests", "p2p:libstunprober_unittests",
"p2p:rtc_p2p_unittests", "p2p:rtc_p2p_unittests",
"rtc_base:robo_caller_unittests", "rtc_base:async_dns_resolver_unittests",
"rtc_base:async_packet_socket_unittest",
"rtc_base:callback_list_unittests",
"rtc_base:rtc_base_approved_unittests", "rtc_base:rtc_base_approved_unittests",
"rtc_base:rtc_base_unittests", "rtc_base:rtc_base_unittests",
"rtc_base:rtc_json_unittests", "rtc_base:rtc_json_unittests",
@ -547,20 +662,30 @@ if (rtc_include_tests) {
"rtc_base:rtc_operations_chain_unittests", "rtc_base:rtc_operations_chain_unittests",
"rtc_base:rtc_task_queue_unittests", "rtc_base:rtc_task_queue_unittests",
"rtc_base:sigslot_unittest", "rtc_base:sigslot_unittest",
"rtc_base:task_queue_stdlib_unittest",
"rtc_base:untyped_function_unittest", "rtc_base:untyped_function_unittest",
"rtc_base:weak_ptr_unittests", "rtc_base:weak_ptr_unittests",
"rtc_base/experiments:experiments_unittests", "rtc_base/experiments:experiments_unittests",
"rtc_base/synchronization:sequence_checker_unittests", "rtc_base/system:file_wrapper_unittests",
"rtc_base/task_utils:pending_task_safety_flag_unittests", "rtc_base/task_utils:repeating_task_unittests",
"rtc_base/task_utils:to_queued_task_unittests", "rtc_base/units:units_unittests",
"sdk:sdk_tests", "sdk:sdk_tests",
"test:rtp_test_utils", "test:rtp_test_utils",
"test:test_main", "test:test_main",
"test/network:network_emulation_unittests", "test/network:network_emulation_unittests",
] ]
data = rtc_unittests_resources
if (rtc_enable_protobuf) { if (rtc_enable_protobuf) {
deps += [ "logging:rtc_event_log_tests" ] deps += [
"api/test/network_emulation:network_config_schedule_proto",
"logging:rtc_event_log_tests",
]
}
if (is_ios) {
deps += [ ":rtc_unittests_bundle_data" ]
} }
if (is_android) { if (is_android) {
@ -574,31 +699,18 @@ if (rtc_include_tests) {
] ]
shard_timeout = 900 shard_timeout = 900
} }
}
if (is_ios || is_mac) { if (rtc_enable_google_benchmarks) {
deps += [ "sdk:rtc_unittests_objc" ] rtc_test("benchmarks") {
testonly = true
deps = [
"rtc_base/synchronization:mutex_benchmark",
"test:benchmark_main",
]
} }
} }
rtc_test("benchmarks") {
testonly = true
deps = [
"rtc_base/synchronization:mutex_benchmark",
"test:benchmark_main",
]
}
# This runs tests that must run in real time and therefore can take some
# time to execute. They are in a separate executable to avoid making the
# regular unittest suite too slow to run frequently.
rtc_test("slow_tests") {
testonly = true
deps = [
"rtc_base/task_utils:repeating_task_unittests",
"test:test_main",
]
}
# TODO(pbos): Rename test suite, this is no longer "just" for video targets. # TODO(pbos): Rename test suite, this is no longer "just" for video targets.
video_engine_tests_resources = [ video_engine_tests_resources = [
"resources/foreman_cif_short.yuv", "resources/foreman_cif_short.yuv",
@ -630,7 +742,12 @@ if (rtc_include_tests) {
] ]
data = video_engine_tests_resources data = video_engine_tests_resources
if (is_android) { if (is_android) {
deps += [ "//testing/android/native_test:native_test_native_code" ] use_default_launcher = false
deps += [
"//build/android/gtest_apk:native_test_instrumentation_test_runner_java",
"//testing/android/native_test:native_test_java",
"//testing/android/native_test:native_test_support",
]
shard_timeout = 900 shard_timeout = 900
} }
if (is_ios) { if (is_ios) {
@ -663,7 +780,6 @@ if (rtc_include_tests) {
rtc_test("webrtc_perf_tests") { rtc_test("webrtc_perf_tests") {
testonly = true testonly = true
deps = [ deps = [
"audio:audio_perf_tests",
"call:call_perf_tests", "call:call_perf_tests",
"modules/audio_coding:audio_coding_perf_tests", "modules/audio_coding:audio_coding_perf_tests",
"modules/audio_processing:audio_processing_perf_tests", "modules/audio_processing:audio_processing_perf_tests",
@ -675,7 +791,12 @@ if (rtc_include_tests) {
data = webrtc_perf_tests_resources data = webrtc_perf_tests_resources
if (is_android) { if (is_android) {
deps += [ "//testing/android/native_test:native_test_native_code" ] use_default_launcher = false
deps += [
"//build/android/gtest_apk:native_test_instrumentation_test_runner_java",
"//testing/android/native_test:native_test_java",
"//testing/android/native_test:native_test_support",
]
shard_timeout = 4500 shard_timeout = 4500
} }
if (is_ios) { if (is_ios) {
@ -695,6 +816,7 @@ if (rtc_include_tests) {
rtc_test("voip_unittests") { rtc_test("voip_unittests") {
testonly = true testonly = true
deps = [ deps = [
"api/voip:compile_all_headers",
"api/voip:voip_engine_factory_unittests", "api/voip:voip_engine_factory_unittests",
"audio/voip/test:audio_channel_unittests", "audio/voip/test:audio_channel_unittests",
"audio/voip/test:audio_egress_unittests", "audio/voip/test:audio_egress_unittests",
@ -705,6 +827,23 @@ if (rtc_include_tests) {
} }
} }
# Build target for standalone dcsctp
rtc_static_library("dcsctp") {
# Only the root target should depend on this.
visibility = [ "//:default" ]
sources = []
complete_static_lib = true
suppressed_configs += [ "//build/config/compiler:thin_archive" ]
defines = []
deps = [
"net/dcsctp/public:factory",
"net/dcsctp/public:socket",
"net/dcsctp/public:types",
"net/dcsctp/socket:dcsctp_socket",
"net/dcsctp/timer:task_queue_timeout",
]
}
# ---- Poisons ---- # ---- Poisons ----
# #
# Here is one empty dummy target for each poison type (needed because # Here is one empty dummy target for each poison type (needed because
@ -717,10 +856,10 @@ if (rtc_include_tests) {
group("poison_audio_codecs") { group("poison_audio_codecs") {
} }
group("poison_default_task_queue") { group("poison_default_echo_detector") {
} }
group("poison_rtc_json") { group("poison_environment_construction") {
} }
group("poison_software_video_codecs") { group("poison_software_video_codecs") {

View File

@ -13,6 +13,8 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstddef>
#include <iterator>
#include <type_traits> #include <type_traits>
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
@ -83,7 +85,7 @@ namespace rtc {
// a pointer if fix-sized) and trivially copyable, so it's probably cheaper to // a pointer if fix-sized) and trivially copyable, so it's probably cheaper to
// pass it by value than by const reference. // pass it by value than by const reference.
namespace impl { namespace array_view_internal {
// Magic constant for indicating that the size of an ArrayView is variable // Magic constant for indicating that the size of an ArrayView is variable
// instead of fixed. // instead of fixed.
@ -124,7 +126,7 @@ class ArrayViewBase<T, 0> {
// Specialized base class for ArrayViews of variable size. // Specialized base class for ArrayViews of variable size.
template <typename T> template <typename T>
class ArrayViewBase<T, impl::kArrayViewVarSize> { class ArrayViewBase<T, array_view_internal::kArrayViewVarSize> {
public: public:
ArrayViewBase(T* data, size_t size) ArrayViewBase(T* data, size_t size)
: data_(size == 0 ? nullptr : data), size_(size) {} : data_(size == 0 ? nullptr : data), size_(size) {}
@ -141,18 +143,23 @@ class ArrayViewBase<T, impl::kArrayViewVarSize> {
size_t size_; size_t size_;
}; };
} // namespace impl } // namespace array_view_internal
template <typename T, std::ptrdiff_t Size = impl::kArrayViewVarSize> template <typename T,
class ArrayView final : public impl::ArrayViewBase<T, Size> { std::ptrdiff_t Size = array_view_internal::kArrayViewVarSize>
class ArrayView final : public array_view_internal::ArrayViewBase<T, Size> {
public: public:
using value_type = T; using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using const_iterator = const T*; using const_iterator = const T*;
// Construct an ArrayView from a pointer and a length. // Construct an ArrayView from a pointer and a length.
template <typename U> template <typename U>
ArrayView(U* data, size_t size) ArrayView(U* data, size_t size)
: impl::ArrayViewBase<T, Size>::ArrayViewBase(data, size) { : array_view_internal::ArrayViewBase<T, Size>::ArrayViewBase(data, size) {
RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data()); RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data());
RTC_DCHECK_EQ(size, this->size()); RTC_DCHECK_EQ(size, this->size());
RTC_DCHECK_EQ(!this->data(), RTC_DCHECK_EQ(!this->data(),
@ -166,7 +173,8 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
: ArrayView() {} : ArrayView() {}
ArrayView(std::nullptr_t, size_t size) ArrayView(std::nullptr_t, size_t size)
: ArrayView(static_cast<T*>(nullptr), size) { : ArrayView(static_cast<T*>(nullptr), size) {
static_assert(Size == 0 || Size == impl::kArrayViewVarSize, ""); static_assert(Size == 0 || Size == array_view_internal::kArrayViewVarSize,
"");
RTC_DCHECK_EQ(0, size); RTC_DCHECK_EQ(0, size);
} }
@ -174,7 +182,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
template <typename U, size_t N> template <typename U, size_t N>
ArrayView(U (&array)[N]) // NOLINT ArrayView(U (&array)[N]) // NOLINT
: ArrayView(array, N) { : ArrayView(array, N) {
static_assert(Size == N || Size == impl::kArrayViewVarSize, static_assert(Size == N || Size == array_view_internal::kArrayViewVarSize,
"Array size must match ArrayView size"); "Array size must match ArrayView size");
} }
@ -207,7 +215,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
// N> when M != N. // N> when M != N.
template < template <
typename U, typename U,
typename std::enable_if<Size != impl::kArrayViewVarSize && typename std::enable_if<Size != array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr> HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) { : ArrayView(u.data(), u.size()) {
@ -215,7 +223,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
} }
template < template <
typename U, typename U,
typename std::enable_if<Size != impl::kArrayViewVarSize && typename std::enable_if<Size != array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr> HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(const U& u) // NOLINT(runtime/explicit) ArrayView(const U& u) // NOLINT(runtime/explicit)
: ArrayView(u.data(), u.size()) { : ArrayView(u.data(), u.size()) {
@ -235,13 +243,13 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
// const rtc::Buffer to ArrayView<const uint8_t>. // const rtc::Buffer to ArrayView<const uint8_t>.
template < template <
typename U, typename U,
typename std::enable_if<Size == impl::kArrayViewVarSize && typename std::enable_if<Size == array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr> HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) {} : ArrayView(u.data(), u.size()) {}
template < template <
typename U, typename U,
typename std::enable_if<Size == impl::kArrayViewVarSize && typename std::enable_if<Size == array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr> HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(const U& u) // NOLINT(runtime/explicit) ArrayView(const U& u) // NOLINT(runtime/explicit)
: ArrayView(u.data(), u.size()) {} : ArrayView(u.data(), u.size()) {}
@ -258,6 +266,18 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
T* end() const { return this->data() + this->size(); } T* end() const { return this->data() + this->size(); }
const T* cbegin() const { return this->data(); } const T* cbegin() const { return this->data(); }
const T* cend() const { return this->data() + this->size(); } const T* cend() const { return this->data() + this->size(); }
std::reverse_iterator<T*> rbegin() const {
return std::make_reverse_iterator(end());
}
std::reverse_iterator<T*> rend() const {
return std::make_reverse_iterator(begin());
}
std::reverse_iterator<const T*> crbegin() const {
return std::make_reverse_iterator(cend());
}
std::reverse_iterator<const T*> crend() const {
return std::make_reverse_iterator(cbegin());
}
ArrayView<T> subview(size_t offset, size_t size) const { ArrayView<T> subview(size_t offset, size_t size) const {
return offset < this->size() return offset < this->size()

View File

@ -11,9 +11,14 @@
#include "api/audio/audio_frame.h" #include "api/audio/audio_frame.h"
#include <string.h> #include <string.h>
#include <algorithm>
#include <utility>
#include <cstdint>
#include <optional>
#include "api/array_view.h"
#include "api/audio/audio_view.h"
#include "api/audio/channel_layout.h"
#include "api/rtp_packet_infos.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/time_utils.h" #include "rtc_base/time_utils.h"
@ -24,26 +29,18 @@ AudioFrame::AudioFrame() {
static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes"); static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes");
} }
void swap(AudioFrame& a, AudioFrame& b) { AudioFrame::AudioFrame(int sample_rate_hz,
using std::swap; size_t num_channels,
swap(a.timestamp_, b.timestamp_); ChannelLayout layout /*= CHANNEL_LAYOUT_UNSUPPORTED*/)
swap(a.elapsed_time_ms_, b.elapsed_time_ms_); : samples_per_channel_(SampleRateToDefaultChannelSize(sample_rate_hz)),
swap(a.ntp_time_ms_, b.ntp_time_ms_); sample_rate_hz_(sample_rate_hz),
swap(a.samples_per_channel_, b.samples_per_channel_); num_channels_(num_channels),
swap(a.sample_rate_hz_, b.sample_rate_hz_); channel_layout_(layout == CHANNEL_LAYOUT_UNSUPPORTED
swap(a.num_channels_, b.num_channels_); ? GuessChannelLayout(num_channels)
swap(a.channel_layout_, b.channel_layout_); : layout) {
swap(a.speech_type_, b.speech_type_); RTC_DCHECK_LE(num_channels_, kMaxConcurrentChannels);
swap(a.vad_activity_, b.vad_activity_); RTC_DCHECK_GT(sample_rate_hz_, 0);
swap(a.profile_timestamp_ms_, b.profile_timestamp_ms_); RTC_DCHECK_GT(samples_per_channel_, 0u);
swap(a.packet_infos_, b.packet_infos_);
const size_t length_a = a.samples_per_channel_ * a.num_channels_;
const size_t length_b = b.samples_per_channel_ * b.num_channels_;
RTC_DCHECK_LE(length_a, AudioFrame::kMaxDataSizeSamples);
RTC_DCHECK_LE(length_b, AudioFrame::kMaxDataSizeSamples);
std::swap_ranges(a.data_, a.data_ + std::max(length_a, length_b), b.data_);
swap(a.muted_, b.muted_);
swap(a.absolute_capture_timestamp_ms_, b.absolute_capture_timestamp_ms_);
} }
void AudioFrame::Reset() { void AudioFrame::Reset() {
@ -52,7 +49,7 @@ void AudioFrame::Reset() {
} }
void AudioFrame::ResetWithoutMuting() { void AudioFrame::ResetWithoutMuting() {
// TODO(wu): Zero is a valid value for |timestamp_|. We should initialize // TODO(wu): Zero is a valid value for `timestamp_`. We should initialize
// to an invalid value, or add a new member to indicate invalidity. // to an invalid value, or add a new member to indicate invalidity.
timestamp_ = 0; timestamp_ = 0;
elapsed_time_ms_ = -1; elapsed_time_ms_ = -1;
@ -65,7 +62,7 @@ void AudioFrame::ResetWithoutMuting() {
vad_activity_ = kVadUnknown; vad_activity_ = kVadUnknown;
profile_timestamp_ms_ = 0; profile_timestamp_ms_ = 0;
packet_infos_ = RtpPacketInfos(); packet_infos_ = RtpPacketInfos();
absolute_capture_timestamp_ms_ = absl::nullopt; absolute_capture_timestamp_ms_ = std::nullopt;
} }
void AudioFrame::UpdateFrame(uint32_t timestamp, void AudioFrame::UpdateFrame(uint32_t timestamp,
@ -75,6 +72,7 @@ void AudioFrame::UpdateFrame(uint32_t timestamp,
SpeechType speech_type, SpeechType speech_type,
VADActivity vad_activity, VADActivity vad_activity,
size_t num_channels) { size_t num_channels) {
RTC_CHECK_LE(num_channels, kMaxConcurrentChannels);
timestamp_ = timestamp; timestamp_ = timestamp;
samples_per_channel_ = samples_per_channel; samples_per_channel_ = samples_per_channel;
sample_rate_hz_ = sample_rate_hz; sample_rate_hz_ = sample_rate_hz;
@ -87,9 +85,9 @@ void AudioFrame::UpdateFrame(uint32_t timestamp,
} }
const size_t length = samples_per_channel * num_channels; const size_t length = samples_per_channel * num_channels;
RTC_CHECK_LE(length, kMaxDataSizeSamples); RTC_CHECK_LE(length, data_.size());
if (data != nullptr) { if (data != nullptr) {
memcpy(data_, data, sizeof(int16_t) * length); memcpy(data_.data(), data, sizeof(int16_t) * length);
muted_ = false; muted_ = false;
} else { } else {
muted_ = true; muted_ = true;
@ -100,6 +98,16 @@ void AudioFrame::CopyFrom(const AudioFrame& src) {
if (this == &src) if (this == &src)
return; return;
if (muted_ && !src.muted()) {
// TODO: bugs.webrtc.org/5647 - Since the default value for `muted_` is
// false and `data_` may still be uninitialized (because we don't initialize
// data_ as part of construction), we clear the full buffer here before
// copying over new values. If we don't, msan might complain in some tests.
// Consider locking down construction, avoiding the default constructor and
// prefering construction that initializes all state.
ClearSamples(data_);
}
timestamp_ = src.timestamp_; timestamp_ = src.timestamp_;
elapsed_time_ms_ = src.elapsed_time_ms_; elapsed_time_ms_ = src.elapsed_time_ms_;
ntp_time_ms_ = src.ntp_time_ms_; ntp_time_ms_ = src.ntp_time_ms_;
@ -113,11 +121,10 @@ void AudioFrame::CopyFrom(const AudioFrame& src) {
channel_layout_ = src.channel_layout_; channel_layout_ = src.channel_layout_;
absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms(); absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms();
const size_t length = samples_per_channel_ * num_channels_; auto data = src.data_view();
RTC_CHECK_LE(length, kMaxDataSizeSamples); RTC_CHECK_LE(data.size(), data_.size());
if (!src.muted()) { if (!muted_ && !data.empty()) {
memcpy(data_, src.data(), sizeof(int16_t) * length); memcpy(&data_[0], &data[0], sizeof(int16_t) * data.size());
muted_ = false;
} }
} }
@ -134,17 +141,56 @@ int64_t AudioFrame::ElapsedProfileTimeMs() const {
} }
const int16_t* AudioFrame::data() const { const int16_t* AudioFrame::data() const {
return muted_ ? empty_data() : data_; return muted_ ? zeroed_data().begin() : data_.data();
}
InterleavedView<const int16_t> AudioFrame::data_view() const {
// If you get a nullptr from `data_view()`, it's likely because the
// samples_per_channel_ and/or num_channels_ members haven't been properly
// set. Since `data_view()` returns an InterleavedView<> (which internally
// uses rtc::ArrayView<>), we inherit the behavior in InterleavedView when the
// view size is 0 that ArrayView<>::data() returns nullptr. So, even when an
// AudioFrame is muted and we want to return `zeroed_data()`, if
// samples_per_channel_ or num_channels_ is 0, the view will point to
// nullptr.
return InterleavedView<const int16_t>(muted_ ? &zeroed_data()[0] : &data_[0],
samples_per_channel_, num_channels_);
} }
// TODO(henrik.lundin) Can we skip zeroing the buffer?
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=5647.
int16_t* AudioFrame::mutable_data() { int16_t* AudioFrame::mutable_data() {
// TODO: bugs.webrtc.org/5647 - Can we skip zeroing the buffer?
// Consider instead if we should rather zero the buffer when `muted_` is set
// to `true`.
if (muted_) { if (muted_) {
memset(data_, 0, kMaxDataSizeBytes); ClearSamples(data_);
muted_ = false; muted_ = false;
} }
return data_; return &data_[0];
}
InterleavedView<int16_t> AudioFrame::mutable_data(size_t samples_per_channel,
size_t num_channels) {
const size_t total_samples = samples_per_channel * num_channels;
RTC_CHECK_LE(total_samples, data_.size());
RTC_CHECK_LE(num_channels, kMaxConcurrentChannels);
// Sanity check for valid argument values during development.
// If `samples_per_channel` is < `num_channels` but larger than 0,
// then chances are the order of arguments is incorrect.
RTC_DCHECK((samples_per_channel == 0 && num_channels == 0) ||
num_channels <= samples_per_channel)
<< "samples_per_channel=" << samples_per_channel
<< "num_channels=" << num_channels;
// TODO: bugs.webrtc.org/5647 - Can we skip zeroing the buffer?
// Consider instead if we should rather zero the whole buffer when `muted_` is
// set to `true`.
if (muted_) {
ClearSamples(data_, total_samples);
muted_ = false;
}
samples_per_channel_ = samples_per_channel;
num_channels_ = num_channels;
return InterleavedView<int16_t>(&data_[0], samples_per_channel, num_channels);
} }
void AudioFrame::Mute() { void AudioFrame::Mute() {
@ -155,10 +201,35 @@ bool AudioFrame::muted() const {
return muted_; return muted_;
} }
void AudioFrame::SetLayoutAndNumChannels(ChannelLayout layout,
size_t num_channels) {
channel_layout_ = layout;
num_channels_ = num_channels;
#if RTC_DCHECK_IS_ON
// Do a sanity check that the layout and num_channels match.
// If this lookup yield 0u, then the layout is likely CHANNEL_LAYOUT_DISCRETE.
auto expected_num_channels = ChannelLayoutToChannelCount(layout);
if (expected_num_channels) { // If expected_num_channels is 0
RTC_DCHECK_EQ(expected_num_channels, num_channels_);
}
#endif
RTC_CHECK_LE(samples_per_channel_ * num_channels_, data_.size());
}
void AudioFrame::SetSampleRateAndChannelSize(int sample_rate) {
sample_rate_hz_ = sample_rate;
// We could call `AudioProcessing::GetFrameSize()` here, but that requires
// adding a dependency on the ":audio_processing" build target, which can
// complicate the dependency tree. Some refactoring is probably in order to
// get some consistency around this since there are many places across the
// code that assume this default buffer size.
samples_per_channel_ = SampleRateToDefaultChannelSize(sample_rate_hz_);
}
// static // static
const int16_t* AudioFrame::empty_data() { rtc::ArrayView<const int16_t> AudioFrame::zeroed_data() {
static int16_t* null_data = new int16_t[kMaxDataSizeSamples](); static int16_t* null_data = new int16_t[kMaxDataSizeSamples]();
return &null_data[0]; return rtc::ArrayView<const int16_t>(null_data, kMaxDataSizeSamples);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -14,14 +14,34 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <utility> #include <array>
#include <optional>
#include "api/array_view.h"
#include "api/audio/audio_view.h"
#include "api/audio/channel_layout.h" #include "api/audio/channel_layout.h"
#include "api/rtp_packet_infos.h" #include "api/rtp_packet_infos.h"
#include "rtc_base/constructor_magic.h" #include "rtc_base/checks.h"
namespace webrtc { namespace webrtc {
// Default webrtc buffer size in milliseconds.
constexpr size_t kDefaultAudioBufferLengthMs = 10u;
// Default total number of audio buffers per second based on the default length.
constexpr size_t kDefaultAudioBuffersPerSec =
1000u / kDefaultAudioBufferLengthMs;
// Returns the number of samples a buffer needs to hold for ~10ms of a single
// audio channel at a given sample rate.
// See also `AudioProcessing::GetFrameSize()`.
inline size_t SampleRateToDefaultChannelSize(size_t sample_rate) {
// Basic sanity check. 192kHz is the highest supported input sample rate.
RTC_DCHECK_LE(sample_rate, 192000);
return sample_rate / kDefaultAudioBuffersPerSec;
}
/////////////////////////////////////////////////////////////////////
/* This class holds up to 120 ms of super-wideband (32 kHz) stereo audio. It /* This class holds up to 120 ms of super-wideband (32 kHz) stereo audio. It
* allows for adding and subtracting frames while keeping track of the resulting * allows for adding and subtracting frames while keeping track of the resulting
* states. * states.
@ -60,7 +80,17 @@ class AudioFrame {
AudioFrame(); AudioFrame();
friend void swap(AudioFrame& a, AudioFrame& b); // Construct an audio frame with frame length properties and channel
// information. `samples_per_channel()` will be initialized to a 10ms buffer
// size and if `layout` is not specified (default value of
// CHANNEL_LAYOUT_UNSUPPORTED is set), then the channel layout is derived
// (guessed) from `num_channels`.
AudioFrame(int sample_rate_hz,
size_t num_channels,
ChannelLayout layout = CHANNEL_LAYOUT_UNSUPPORTED);
AudioFrame(const AudioFrame&) = delete;
AudioFrame& operator=(const AudioFrame&) = delete;
// Resets all members to their default state. // Resets all members to their default state.
void Reset(); void Reset();
@ -70,6 +100,7 @@ class AudioFrame {
// ResetWithoutMuting() to skip this wasteful zeroing. // ResetWithoutMuting() to skip this wasteful zeroing.
void ResetWithoutMuting(); void ResetWithoutMuting();
// TODO: b/335805780 - Accept InterleavedView.
void UpdateFrame(uint32_t timestamp, void UpdateFrame(uint32_t timestamp,
const int16_t* data, const int16_t* data,
size_t samples_per_channel, size_t samples_per_channel,
@ -92,20 +123,40 @@ class AudioFrame {
int64_t ElapsedProfileTimeMs() const; int64_t ElapsedProfileTimeMs() const;
// data() returns a zeroed static buffer if the frame is muted. // data() returns a zeroed static buffer if the frame is muted.
// mutable_frame() always returns a non-static buffer; the first call to // TODO: b/335805780 - Return InterleavedView.
// mutable_frame() zeros the non-static buffer and marks the frame unmuted.
const int16_t* data() const; const int16_t* data() const;
// Returns a read-only view of all the valid samples held by the AudioFrame.
// For a muted AudioFrame, the samples will all be 0.
InterleavedView<const int16_t> data_view() const;
// mutable_frame() always returns a non-static buffer; the first call to
// mutable_frame() zeros the buffer and marks the frame as unmuted.
// TODO: b/335805780 - Return an InterleavedView.
int16_t* mutable_data(); int16_t* mutable_data();
// Grants write access to the audio buffer. The size of the returned writable
// view is determined by the `samples_per_channel` and `num_channels`
// dimensions which the function checks for correctness and stores in the
// internal member variables; `samples_per_channel()` and `num_channels()`
// respectively.
// If the state is currently muted, the returned view will be zeroed out.
InterleavedView<int16_t> mutable_data(size_t samples_per_channel,
size_t num_channels);
// Prefer to mute frames using AudioFrameOperations::Mute. // Prefer to mute frames using AudioFrameOperations::Mute.
void Mute(); void Mute();
// Frame is muted by default. // Frame is muted by default.
bool muted() const; bool muted() const;
size_t max_16bit_samples() const { return kMaxDataSizeSamples; } size_t max_16bit_samples() const { return data_.size(); }
size_t samples_per_channel() const { return samples_per_channel_; } size_t samples_per_channel() const { return samples_per_channel_; }
size_t num_channels() const { return num_channels_; } size_t num_channels() const { return num_channels_; }
ChannelLayout channel_layout() const { return channel_layout_; } ChannelLayout channel_layout() const { return channel_layout_; }
// Sets the `channel_layout` property as well as `num_channels`.
void SetLayoutAndNumChannels(ChannelLayout layout, size_t num_channels);
int sample_rate_hz() const { return sample_rate_hz_; } int sample_rate_hz() const { return sample_rate_hz_; }
void set_absolute_capture_timestamp_ms( void set_absolute_capture_timestamp_ms(
@ -113,10 +164,14 @@ class AudioFrame {
absolute_capture_timestamp_ms_ = absolute_capture_time_stamp_ms; absolute_capture_timestamp_ms_ = absolute_capture_time_stamp_ms;
} }
absl::optional<int64_t> absolute_capture_timestamp_ms() const { std::optional<int64_t> absolute_capture_timestamp_ms() const {
return absolute_capture_timestamp_ms_; return absolute_capture_timestamp_ms_;
} }
// Sets the sample_rate_hz and samples_per_channel properties based on a
// given sample rate and calculates a default 10ms samples_per_channel value.
void SetSampleRateAndChannelSize(int sample_rate);
// RTP timestamp of the first sample in the AudioFrame. // RTP timestamp of the first sample in the AudioFrame.
uint32_t timestamp_ = 0; uint32_t timestamp_ = 0;
// Time since the first frame in milliseconds. // Time since the first frame in milliseconds.
@ -128,18 +183,17 @@ class AudioFrame {
size_t samples_per_channel_ = 0; size_t samples_per_channel_ = 0;
int sample_rate_hz_ = 0; int sample_rate_hz_ = 0;
size_t num_channels_ = 0; size_t num_channels_ = 0;
ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
SpeechType speech_type_ = kUndefined; SpeechType speech_type_ = kUndefined;
VADActivity vad_activity_ = kVadUnknown; VADActivity vad_activity_ = kVadUnknown;
// Monotonically increasing timestamp intended for profiling of audio frames. // Monotonically increasing timestamp intended for profiling of audio frames.
// Typically used for measuring elapsed time between two different points in // Typically used for measuring elapsed time between two different points in
// the audio path. No lock is used to save resources and we are thread safe // the audio path. No lock is used to save resources and we are thread safe
// by design. // by design.
// TODO(nisse@webrtc.org): consider using absl::optional. // TODO(nisse@webrtc.org): consider using std::optional.
int64_t profile_timestamp_ms_ = 0; int64_t profile_timestamp_ms_ = 0;
// Information about packets used to assemble this audio frame. This is needed // Information about packets used to assemble this audio frame. This is needed
// by |SourceTracker| when the frame is delivered to the RTCRtpReceiver's // by `SourceTracker` when the frame is delivered to the RTCRtpReceiver's
// MediaStreamTrack, in order to implement getContributingSources(). See: // MediaStreamTrack, in order to implement getContributingSources(). See:
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getcontributingsources // https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getcontributingsources
// //
@ -149,27 +203,26 @@ class AudioFrame {
// sync buffer is the small sample-holding buffer located after the audio // sync buffer is the small sample-holding buffer located after the audio
// decoder and before where samples are assembled into output frames. // decoder and before where samples are assembled into output frames.
// //
// |RtpPacketInfos| may also be empty if the audio samples did not come from // `RtpPacketInfos` may also be empty if the audio samples did not come from
// RTP packets. E.g. if the audio were locally generated by packet loss // RTP packets. E.g. if the audio were locally generated by packet loss
// concealment, comfort noise generation, etc. // concealment, comfort noise generation, etc.
RtpPacketInfos packet_infos_; RtpPacketInfos packet_infos_;
private: private:
// A permanently zeroed out buffer to represent muted frames. This is a // A permanently zeroed out buffer to represent muted frames. This is a
// header-only class, so the only way to avoid creating a separate empty // header-only class, so the only way to avoid creating a separate zeroed
// buffer per translation unit is to wrap a static in an inline function. // buffer per translation unit is to wrap a static in an inline function.
static const int16_t* empty_data(); static rtc::ArrayView<const int16_t> zeroed_data();
int16_t data_[kMaxDataSizeSamples]; std::array<int16_t, kMaxDataSizeSamples> data_;
bool muted_ = true; bool muted_ = true;
ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
// Absolute capture timestamp when this audio frame was originally captured. // Absolute capture timestamp when this audio frame was originally captured.
// This is only valid for audio frames captured on this machine. The absolute // This is only valid for audio frames captured on this machine. The absolute
// capture timestamp of a received frame is found in |packet_infos_|. // capture timestamp of a received frame is found in `packet_infos_`.
// This timestamp MUST be based on the same clock as rtc::TimeMillis(). // This timestamp MUST be based on the same clock as rtc::TimeMillis().
absl::optional<int64_t> absolute_capture_timestamp_ms_; std::optional<int64_t> absolute_capture_timestamp_ms_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/audio/audio_processing.h"
#include <string>
#include "rtc_base/checks.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
namespace {
using Agc1Config = AudioProcessing::Config::GainController1;
using Agc2Config = AudioProcessing::Config::GainController2;
std::string NoiseSuppressionLevelToString(
const AudioProcessing::Config::NoiseSuppression::Level& level) {
switch (level) {
case AudioProcessing::Config::NoiseSuppression::Level::kLow:
return "Low";
case AudioProcessing::Config::NoiseSuppression::Level::kModerate:
return "Moderate";
case AudioProcessing::Config::NoiseSuppression::Level::kHigh:
return "High";
case AudioProcessing::Config::NoiseSuppression::Level::kVeryHigh:
return "VeryHigh";
}
RTC_CHECK_NOTREACHED();
}
std::string GainController1ModeToString(const Agc1Config::Mode& mode) {
switch (mode) {
case Agc1Config::Mode::kAdaptiveAnalog:
return "AdaptiveAnalog";
case Agc1Config::Mode::kAdaptiveDigital:
return "AdaptiveDigital";
case Agc1Config::Mode::kFixedDigital:
return "FixedDigital";
}
RTC_CHECK_NOTREACHED();
}
} // namespace
constexpr int AudioProcessing::kNativeSampleRatesHz[];
void CustomProcessing::SetRuntimeSetting(
AudioProcessing::RuntimeSetting setting) {}
bool Agc1Config::operator==(const Agc1Config& rhs) const {
const auto& analog_lhs = analog_gain_controller;
const auto& analog_rhs = rhs.analog_gain_controller;
return enabled == rhs.enabled && mode == rhs.mode &&
target_level_dbfs == rhs.target_level_dbfs &&
compression_gain_db == rhs.compression_gain_db &&
enable_limiter == rhs.enable_limiter &&
analog_lhs.enabled == analog_rhs.enabled &&
analog_lhs.startup_min_volume == analog_rhs.startup_min_volume &&
analog_lhs.clipped_level_min == analog_rhs.clipped_level_min &&
analog_lhs.enable_digital_adaptive ==
analog_rhs.enable_digital_adaptive &&
analog_lhs.clipped_level_step == analog_rhs.clipped_level_step &&
analog_lhs.clipped_ratio_threshold ==
analog_rhs.clipped_ratio_threshold &&
analog_lhs.clipped_wait_frames == analog_rhs.clipped_wait_frames &&
analog_lhs.clipping_predictor.mode ==
analog_rhs.clipping_predictor.mode &&
analog_lhs.clipping_predictor.window_length ==
analog_rhs.clipping_predictor.window_length &&
analog_lhs.clipping_predictor.reference_window_length ==
analog_rhs.clipping_predictor.reference_window_length &&
analog_lhs.clipping_predictor.reference_window_delay ==
analog_rhs.clipping_predictor.reference_window_delay &&
analog_lhs.clipping_predictor.clipping_threshold ==
analog_rhs.clipping_predictor.clipping_threshold &&
analog_lhs.clipping_predictor.crest_factor_margin ==
analog_rhs.clipping_predictor.crest_factor_margin &&
analog_lhs.clipping_predictor.use_predicted_step ==
analog_rhs.clipping_predictor.use_predicted_step;
}
bool Agc2Config::AdaptiveDigital::operator==(
const Agc2Config::AdaptiveDigital& rhs) const {
return enabled == rhs.enabled && headroom_db == rhs.headroom_db &&
max_gain_db == rhs.max_gain_db &&
initial_gain_db == rhs.initial_gain_db &&
max_gain_change_db_per_second == rhs.max_gain_change_db_per_second &&
max_output_noise_level_dbfs == rhs.max_output_noise_level_dbfs;
}
bool Agc2Config::InputVolumeController::operator==(
const Agc2Config::InputVolumeController& rhs) const {
return enabled == rhs.enabled;
}
bool Agc2Config::operator==(const Agc2Config& rhs) const {
return enabled == rhs.enabled &&
fixed_digital.gain_db == rhs.fixed_digital.gain_db &&
adaptive_digital == rhs.adaptive_digital &&
input_volume_controller == rhs.input_volume_controller;
}
bool AudioProcessing::Config::CaptureLevelAdjustment::operator==(
const AudioProcessing::Config::CaptureLevelAdjustment& rhs) const {
return enabled == rhs.enabled && pre_gain_factor == rhs.pre_gain_factor &&
post_gain_factor == rhs.post_gain_factor &&
analog_mic_gain_emulation == rhs.analog_mic_gain_emulation;
}
bool AudioProcessing::Config::CaptureLevelAdjustment::AnalogMicGainEmulation::
operator==(const AudioProcessing::Config::CaptureLevelAdjustment::
AnalogMicGainEmulation& rhs) const {
return enabled == rhs.enabled && initial_level == rhs.initial_level;
}
std::string AudioProcessing::Config::ToString() const {
char buf[2048];
rtc::SimpleStringBuilder builder(buf);
builder << "AudioProcessing::Config{ "
"pipeline: { "
"maximum_internal_processing_rate: "
<< pipeline.maximum_internal_processing_rate
<< ", multi_channel_render: " << pipeline.multi_channel_render
<< ", multi_channel_capture: " << pipeline.multi_channel_capture
<< " }, pre_amplifier: { enabled: " << pre_amplifier.enabled
<< ", fixed_gain_factor: " << pre_amplifier.fixed_gain_factor
<< " },capture_level_adjustment: { enabled: "
<< capture_level_adjustment.enabled
<< ", pre_gain_factor: " << capture_level_adjustment.pre_gain_factor
<< ", post_gain_factor: " << capture_level_adjustment.post_gain_factor
<< ", analog_mic_gain_emulation: { enabled: "
<< capture_level_adjustment.analog_mic_gain_emulation.enabled
<< ", initial_level: "
<< capture_level_adjustment.analog_mic_gain_emulation.initial_level
<< " }}, high_pass_filter: { enabled: " << high_pass_filter.enabled
<< " }, echo_canceller: { enabled: " << echo_canceller.enabled
<< ", mobile_mode: " << echo_canceller.mobile_mode
<< ", enforce_high_pass_filtering: "
<< echo_canceller.enforce_high_pass_filtering
<< " }, noise_suppression: { enabled: " << noise_suppression.enabled
<< ", level: "
<< NoiseSuppressionLevelToString(noise_suppression.level)
<< " }, transient_suppression: { enabled: "
<< transient_suppression.enabled
<< " }, gain_controller1: { enabled: " << gain_controller1.enabled
<< ", mode: " << GainController1ModeToString(gain_controller1.mode)
<< ", target_level_dbfs: " << gain_controller1.target_level_dbfs
<< ", compression_gain_db: " << gain_controller1.compression_gain_db
<< ", enable_limiter: " << gain_controller1.enable_limiter
<< ", analog_gain_controller { enabled: "
<< gain_controller1.analog_gain_controller.enabled
<< ", startup_min_volume: "
<< gain_controller1.analog_gain_controller.startup_min_volume
<< ", clipped_level_min: "
<< gain_controller1.analog_gain_controller.clipped_level_min
<< ", enable_digital_adaptive: "
<< gain_controller1.analog_gain_controller.enable_digital_adaptive
<< ", clipped_level_step: "
<< gain_controller1.analog_gain_controller.clipped_level_step
<< ", clipped_ratio_threshold: "
<< gain_controller1.analog_gain_controller.clipped_ratio_threshold
<< ", clipped_wait_frames: "
<< gain_controller1.analog_gain_controller.clipped_wait_frames
<< ", clipping_predictor: { enabled: "
<< gain_controller1.analog_gain_controller.clipping_predictor.enabled
<< ", mode: "
<< gain_controller1.analog_gain_controller.clipping_predictor.mode
<< ", window_length: "
<< gain_controller1.analog_gain_controller.clipping_predictor
.window_length
<< ", reference_window_length: "
<< gain_controller1.analog_gain_controller.clipping_predictor
.reference_window_length
<< ", reference_window_delay: "
<< gain_controller1.analog_gain_controller.clipping_predictor
.reference_window_delay
<< ", clipping_threshold: "
<< gain_controller1.analog_gain_controller.clipping_predictor
.clipping_threshold
<< ", crest_factor_margin: "
<< gain_controller1.analog_gain_controller.clipping_predictor
.crest_factor_margin
<< ", use_predicted_step: "
<< gain_controller1.analog_gain_controller.clipping_predictor
.use_predicted_step
<< " }}}, gain_controller2: { enabled: " << gain_controller2.enabled
<< ", fixed_digital: { gain_db: "
<< gain_controller2.fixed_digital.gain_db
<< " }, adaptive_digital: { enabled: "
<< gain_controller2.adaptive_digital.enabled
<< ", headroom_db: " << gain_controller2.adaptive_digital.headroom_db
<< ", max_gain_db: " << gain_controller2.adaptive_digital.max_gain_db
<< ", initial_gain_db: "
<< gain_controller2.adaptive_digital.initial_gain_db
<< ", max_gain_change_db_per_second: "
<< gain_controller2.adaptive_digital.max_gain_change_db_per_second
<< ", max_output_noise_level_dbfs: "
<< gain_controller2.adaptive_digital.max_output_noise_level_dbfs
<< " }, input_volume_control : { enabled "
<< gain_controller2.input_volume_controller.enabled << "}}";
return builder.str();
}
} // namespace webrtc

View File

@ -0,0 +1,944 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_AUDIO_AUDIO_PROCESSING_H_
#define API_AUDIO_AUDIO_PROCESSING_H_
// MSVC++ requires this to be set before any other includes to get M_PI.
#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include <stddef.h> // size_t
#include <stdio.h> // FILE
#include <string.h>
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/base/nullability.h"
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "api/audio/audio_processing_statistics.h"
#include "api/audio/echo_control.h"
#include "api/ref_count.h"
#include "api/scoped_refptr.h"
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
class AecDump;
class AudioBuffer;
class StreamConfig;
class ProcessingConfig;
class EchoDetector;
// The Audio Processing Module (APM) provides a collection of voice processing
// components designed for real-time communications software.
//
// APM operates on two audio streams on a frame-by-frame basis. Frames of the
// primary stream, on which all processing is applied, are passed to
// `ProcessStream()`. Frames of the reverse direction stream are passed to
// `ProcessReverseStream()`. On the client-side, this will typically be the
// near-end (capture) and far-end (render) streams, respectively. APM should be
// placed in the signal chain as close to the audio hardware abstraction layer
// (HAL) as possible.
//
// On the server-side, the reverse stream will normally not be used, with
// processing occurring on each incoming stream.
//
// Component interfaces follow a similar pattern and are accessed through
// corresponding getters in APM. All components are disabled at create-time,
// with default settings that are recommended for most situations. New settings
// can be applied without enabling a component. Enabling a component triggers
// memory allocation and initialization to allow it to start processing the
// streams.
//
// Thread safety is provided with the following assumptions to reduce locking
// overhead:
// 1. The stream getters and setters are called from the same thread as
// ProcessStream(). More precisely, stream functions are never called
// concurrently with ProcessStream().
// 2. Parameter getters are never called concurrently with the corresponding
// setter.
//
// APM accepts only linear PCM audio data in chunks of ~10 ms (see
// AudioProcessing::GetFrameSize() for details) and sample rates ranging from
// 8000 Hz to 384000 Hz. The int16 interfaces use interleaved data, while the
// float interfaces use deinterleaved data.
//
// Usage example, omitting error checking:
// rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
//
// AudioProcessing::Config config;
// config.echo_canceller.enabled = true;
// config.echo_canceller.mobile_mode = false;
//
// config.gain_controller1.enabled = true;
// config.gain_controller1.mode =
// AudioProcessing::Config::GainController1::kAdaptiveAnalog;
// config.gain_controller1.analog_level_minimum = 0;
// config.gain_controller1.analog_level_maximum = 255;
//
// config.gain_controller2.enabled = true;
//
// config.high_pass_filter.enabled = true;
//
// apm->ApplyConfig(config)
//
// // Start a voice call...
//
// // ... Render frame arrives bound for the audio HAL ...
// apm->ProcessReverseStream(render_frame);
//
// // ... Capture frame arrives from the audio HAL ...
// // Call required set_stream_ functions.
// apm->set_stream_delay_ms(delay_ms);
// apm->set_stream_analog_level(analog_level);
//
// apm->ProcessStream(capture_frame);
//
// // Call required stream_ functions.
// analog_level = apm->recommended_stream_analog_level();
// has_voice = apm->stream_has_voice();
//
// // Repeat render and capture processing for the duration of the call...
// // Start a new call...
// apm->Initialize();
//
// // Close the application...
// apm.reset();
//
class RTC_EXPORT AudioProcessing : public RefCountInterface {
public:
// The struct below constitutes the new parameter scheme for the audio
// processing. It is being introduced gradually and until it is fully
// introduced, it is prone to change.
// TODO(peah): Remove this comment once the new config scheme is fully rolled
// out.
//
// The parameters and behavior of the audio processing module are controlled
// by changing the default values in the AudioProcessing::Config struct.
// The config is applied by passing the struct to the ApplyConfig method.
//
// This config is intended to be used during setup, and to enable/disable
// top-level processing effects. Use during processing may cause undesired
// submodule resets, affecting the audio quality. Use the RuntimeSetting
// construct for runtime configuration.
struct RTC_EXPORT Config {
// Sets the properties of the audio processing pipeline.
struct RTC_EXPORT Pipeline {
// Ways to downmix a multi-channel track to mono.
enum class DownmixMethod {
kAverageChannels, // Average across channels.
kUseFirstChannel // Use the first channel.
};
// Maximum allowed processing rate used internally. May only be set to
// 32000 or 48000 and any differing values will be treated as 48000.
int maximum_internal_processing_rate = 48000;
// Allow multi-channel processing of render audio.
bool multi_channel_render = false;
// Allow multi-channel processing of capture audio when AEC3 is active
// or a custom AEC is injected..
bool multi_channel_capture = false;
// Indicates how to downmix multi-channel capture audio to mono (when
// needed).
DownmixMethod capture_downmix_method = DownmixMethod::kAverageChannels;
} pipeline;
// Enabled the pre-amplifier. It amplifies the capture signal
// before any other processing is done.
// TODO(webrtc:5298): Deprecate and use the pre-gain functionality in
// capture_level_adjustment instead.
struct PreAmplifier {
bool enabled = false;
float fixed_gain_factor = 1.0f;
} pre_amplifier;
// Functionality for general level adjustment in the capture pipeline. This
// should not be used together with the legacy PreAmplifier functionality.
struct CaptureLevelAdjustment {
bool operator==(const CaptureLevelAdjustment& rhs) const;
bool operator!=(const CaptureLevelAdjustment& rhs) const {
return !(*this == rhs);
}
bool enabled = false;
// The `pre_gain_factor` scales the signal before any processing is done.
float pre_gain_factor = 1.0f;
// The `post_gain_factor` scales the signal after all processing is done.
float post_gain_factor = 1.0f;
struct AnalogMicGainEmulation {
bool operator==(const AnalogMicGainEmulation& rhs) const;
bool operator!=(const AnalogMicGainEmulation& rhs) const {
return !(*this == rhs);
}
bool enabled = false;
// Initial analog gain level to use for the emulated analog gain. Must
// be in the range [0...255].
int initial_level = 255;
} analog_mic_gain_emulation;
} capture_level_adjustment;
struct HighPassFilter {
bool enabled = false;
bool apply_in_full_band = true;
} high_pass_filter;
struct EchoCanceller {
bool enabled = false;
bool mobile_mode = false;
bool export_linear_aec_output = false;
// Enforce the highpass filter to be on (has no effect for the mobile
// mode).
bool enforce_high_pass_filtering = true;
} echo_canceller;
// Enables background noise suppression.
struct NoiseSuppression {
bool enabled = false;
enum Level { kLow, kModerate, kHigh, kVeryHigh };
Level level = kModerate;
bool analyze_linear_aec_output_when_available = false;
} noise_suppression;
// TODO(bugs.webrtc.org/357281131): Deprecated. Stop using and remove.
// Enables transient suppression.
struct TransientSuppression {
bool enabled = false;
} transient_suppression;
// Enables automatic gain control (AGC) functionality.
// The automatic gain control (AGC) component brings the signal to an
// appropriate range. This is done by applying a digital gain directly and,
// in the analog mode, prescribing an analog gain to be applied at the audio
// HAL.
// Recommended to be enabled on the client-side.
struct RTC_EXPORT GainController1 {
bool operator==(const GainController1& rhs) const;
bool operator!=(const GainController1& rhs) const {
return !(*this == rhs);
}
bool enabled = false;
enum Mode {
// Adaptive mode intended for use if an analog volume control is
// available on the capture device. It will require the user to provide
// coupling between the OS mixer controls and AGC through the
// stream_analog_level() functions.
// It consists of an analog gain prescription for the audio device and a
// digital compression stage.
kAdaptiveAnalog,
// Adaptive mode intended for situations in which an analog volume
// control is unavailable. It operates in a similar fashion to the
// adaptive analog mode, but with scaling instead applied in the digital
// domain. As with the analog mode, it additionally uses a digital
// compression stage.
kAdaptiveDigital,
// Fixed mode which enables only the digital compression stage also used
// by the two adaptive modes.
// It is distinguished from the adaptive modes by considering only a
// short time-window of the input signal. It applies a fixed gain
// through most of the input level range, and compresses (gradually
// reduces gain with increasing level) the input signal at higher
// levels. This mode is preferred on embedded devices where the capture
// signal level is predictable, so that a known gain can be applied.
kFixedDigital
};
Mode mode = kAdaptiveAnalog;
// Sets the target peak level (or envelope) of the AGC in dBFs (decibels
// from digital full-scale). The convention is to use positive values. For
// instance, passing in a value of 3 corresponds to -3 dBFs, or a target
// level 3 dB below full-scale. Limited to [0, 31].
int target_level_dbfs = 3;
// Sets the maximum gain the digital compression stage may apply, in dB. A
// higher number corresponds to greater compression, while a value of 0
// will leave the signal uncompressed. Limited to [0, 90].
// For updates after APM setup, use a RuntimeSetting instead.
int compression_gain_db = 9;
// When enabled, the compression stage will hard limit the signal to the
// target level. Otherwise, the signal will be compressed but not limited
// above the target level.
bool enable_limiter = true;
// Enables the analog gain controller functionality.
struct AnalogGainController {
bool enabled = true;
// TODO(bugs.webrtc.org/7494): Deprecated. Stop using and remove.
int startup_min_volume = 0;
// Lowest analog microphone level that will be applied in response to
// clipping.
int clipped_level_min = 70;
// If true, an adaptive digital gain is applied.
bool enable_digital_adaptive = true;
// Amount the microphone level is lowered with every clipping event.
// Limited to (0, 255].
int clipped_level_step = 15;
// Proportion of clipped samples required to declare a clipping event.
// Limited to (0.f, 1.f).
float clipped_ratio_threshold = 0.1f;
// Time in frames to wait after a clipping event before checking again.
// Limited to values higher than 0.
int clipped_wait_frames = 300;
// Enables clipping prediction functionality.
struct ClippingPredictor {
bool enabled = false;
enum Mode {
// Clipping event prediction mode with fixed step estimation.
kClippingEventPrediction,
// Clipped peak estimation mode with adaptive step estimation.
kAdaptiveStepClippingPeakPrediction,
// Clipped peak estimation mode with fixed step estimation.
kFixedStepClippingPeakPrediction,
};
Mode mode = kClippingEventPrediction;
// Number of frames in the sliding analysis window.
int window_length = 5;
// Number of frames in the sliding reference window.
int reference_window_length = 5;
// Reference window delay (unit: number of frames).
int reference_window_delay = 5;
// Clipping prediction threshold (dBFS).
float clipping_threshold = -1.0f;
// Crest factor drop threshold (dB).
float crest_factor_margin = 3.0f;
// If true, the recommended clipped level step is used to modify the
// analog gain. Otherwise, the predictor runs without affecting the
// analog gain.
bool use_predicted_step = true;
} clipping_predictor;
} analog_gain_controller;
} gain_controller1;
// Parameters for AGC2, an Automatic Gain Control (AGC) sub-module which
// replaces the AGC sub-module parametrized by `gain_controller1`.
// AGC2 brings the captured audio signal to the desired level by combining
// three different controllers (namely, input volume controller, adapative
// digital controller and fixed digital controller) and a limiter.
// TODO(bugs.webrtc.org:7494): Name `GainController` when AGC1 removed.
struct RTC_EXPORT GainController2 {
bool operator==(const GainController2& rhs) const;
bool operator!=(const GainController2& rhs) const {
return !(*this == rhs);
}
// AGC2 must be created if and only if `enabled` is true.
bool enabled = false;
// Parameters for the input volume controller, which adjusts the input
// volume applied when the audio is captured (e.g., microphone volume on
// a soundcard, input volume on HAL).
struct InputVolumeController {
bool operator==(const InputVolumeController& rhs) const;
bool operator!=(const InputVolumeController& rhs) const {
return !(*this == rhs);
}
bool enabled = false;
} input_volume_controller;
// Parameters for the adaptive digital controller, which adjusts and
// applies a digital gain after echo cancellation and after noise
// suppression.
struct RTC_EXPORT AdaptiveDigital {
bool operator==(const AdaptiveDigital& rhs) const;
bool operator!=(const AdaptiveDigital& rhs) const {
return !(*this == rhs);
}
bool enabled = false;
float headroom_db = 5.0f;
float max_gain_db = 50.0f;
float initial_gain_db = 15.0f;
float max_gain_change_db_per_second = 6.0f;
float max_output_noise_level_dbfs = -50.0f;
} adaptive_digital;
// Parameters for the fixed digital controller, which applies a fixed
// digital gain after the adaptive digital controller and before the
// limiter.
struct FixedDigital {
// By setting `gain_db` to a value greater than zero, the limiter can be
// turned into a compressor that first applies a fixed gain.
float gain_db = 0.0f;
} fixed_digital;
} gain_controller2;
std::string ToString() const;
};
// Specifies the properties of a setting to be passed to AudioProcessing at
// runtime.
class RuntimeSetting {
public:
enum class Type {
kNotSpecified,
kCapturePreGain,
kCaptureCompressionGain,
kCaptureFixedPostGain,
kPlayoutVolumeChange,
kCustomRenderProcessingRuntimeSetting,
kPlayoutAudioDeviceChange,
kCapturePostGain,
kCaptureOutputUsed
};
// Play-out audio device properties.
struct PlayoutAudioDeviceInfo {
int id; // Identifies the audio device.
int max_volume; // Maximum play-out volume.
};
RuntimeSetting() : type_(Type::kNotSpecified), value_(0.0f) {}
~RuntimeSetting() = default;
static RuntimeSetting CreateCapturePreGain(float gain) {
return {Type::kCapturePreGain, gain};
}
static RuntimeSetting CreateCapturePostGain(float gain) {
return {Type::kCapturePostGain, gain};
}
// Corresponds to Config::GainController1::compression_gain_db, but for
// runtime configuration.
static RuntimeSetting CreateCompressionGainDb(int gain_db) {
RTC_DCHECK_GE(gain_db, 0);
RTC_DCHECK_LE(gain_db, 90);
return {Type::kCaptureCompressionGain, static_cast<float>(gain_db)};
}
// Corresponds to Config::GainController2::fixed_digital::gain_db, but for
// runtime configuration.
static RuntimeSetting CreateCaptureFixedPostGain(float gain_db) {
RTC_DCHECK_GE(gain_db, 0.0f);
RTC_DCHECK_LE(gain_db, 90.0f);
return {Type::kCaptureFixedPostGain, gain_db};
}
// Creates a runtime setting to notify play-out (aka render) audio device
// changes.
static RuntimeSetting CreatePlayoutAudioDeviceChange(
PlayoutAudioDeviceInfo audio_device) {
return {Type::kPlayoutAudioDeviceChange, audio_device};
}
// Creates a runtime setting to notify play-out (aka render) volume changes.
// `volume` is the unnormalized volume, the maximum of which
static RuntimeSetting CreatePlayoutVolumeChange(int volume) {
return {Type::kPlayoutVolumeChange, volume};
}
static RuntimeSetting CreateCustomRenderSetting(float payload) {
return {Type::kCustomRenderProcessingRuntimeSetting, payload};
}
static RuntimeSetting CreateCaptureOutputUsedSetting(
bool capture_output_used) {
return {Type::kCaptureOutputUsed, capture_output_used};
}
Type type() const { return type_; }
// Getters do not return a value but instead modify the argument to protect
// from implicit casting.
void GetFloat(float* value) const {
RTC_DCHECK(value);
*value = value_.float_value;
}
void GetInt(int* value) const {
RTC_DCHECK(value);
*value = value_.int_value;
}
void GetBool(bool* value) const {
RTC_DCHECK(value);
*value = value_.bool_value;
}
void GetPlayoutAudioDeviceInfo(PlayoutAudioDeviceInfo* value) const {
RTC_DCHECK(value);
*value = value_.playout_audio_device_info;
}
private:
RuntimeSetting(Type id, float value) : type_(id), value_(value) {}
RuntimeSetting(Type id, int value) : type_(id), value_(value) {}
RuntimeSetting(Type id, PlayoutAudioDeviceInfo value)
: type_(id), value_(value) {}
Type type_;
union U {
U() {}
U(int value) : int_value(value) {}
U(float value) : float_value(value) {}
U(PlayoutAudioDeviceInfo value) : playout_audio_device_info(value) {}
float float_value;
int int_value;
bool bool_value;
PlayoutAudioDeviceInfo playout_audio_device_info;
} value_;
};
~AudioProcessing() override {}
// Initializes internal states, while retaining all user settings. This
// should be called before beginning to process a new audio stream. However,
// it is not necessary to call before processing the first stream after
// creation.
//
// It is also not necessary to call if the audio parameters (sample
// rate and number of channels) have changed. Passing updated parameters
// directly to `ProcessStream()` and `ProcessReverseStream()` is permissible.
// If the parameters are known at init-time though, they may be provided.
// TODO(webrtc:5298): Change to return void.
virtual int Initialize() = 0;
// The int16 interfaces require:
// - only `NativeRate`s be used
// - that the input, output and reverse rates must match
// - that `processing_config.output_stream()` matches
// `processing_config.input_stream()`.
//
// The float interfaces accept arbitrary rates and support differing input and
// output layouts, but the output must have either one channel or the same
// number of channels as the input.
virtual int Initialize(const ProcessingConfig& processing_config) = 0;
// TODO(peah): This method is a temporary solution used to take control
// over the parameters in the audio processing module and is likely to change.
virtual void ApplyConfig(const Config& config) = 0;
// TODO(ajm): Only intended for internal use. Make private and friend the
// necessary classes?
virtual int proc_sample_rate_hz() const = 0;
virtual int proc_split_sample_rate_hz() const = 0;
virtual size_t num_input_channels() const = 0;
virtual size_t num_proc_channels() const = 0;
virtual size_t num_output_channels() const = 0;
virtual size_t num_reverse_channels() const = 0;
// Set to true when the output of AudioProcessing will be muted or in some
// other way not used. Ideally, the captured audio would still be processed,
// but some components may change behavior based on this information.
// Default false. This method takes a lock. To achieve this in a lock-less
// manner the PostRuntimeSetting can instead be used.
virtual void set_output_will_be_muted(bool muted) = 0;
// Enqueues a runtime setting.
virtual void SetRuntimeSetting(RuntimeSetting setting) = 0;
// Enqueues a runtime setting. Returns a bool indicating whether the
// enqueueing was successfull.
virtual bool PostRuntimeSetting(RuntimeSetting setting) = 0;
// Accepts and produces a ~10 ms frame of interleaved 16 bit integer audio as
// specified in `input_config` and `output_config`. `src` and `dest` may use
// the same memory, if desired.
virtual int ProcessStream(const int16_t* const src,
const StreamConfig& input_config,
const StreamConfig& output_config,
int16_t* const dest) = 0;
// Accepts deinterleaved float audio with the range [-1, 1]. Each element of
// `src` points to a channel buffer, arranged according to `input_stream`. At
// output, the channels will be arranged according to `output_stream` in
// `dest`.
//
// The output must have one channel or as many channels as the input. `src`
// and `dest` may use the same memory, if desired.
virtual int ProcessStream(const float* const* src,
const StreamConfig& input_config,
const StreamConfig& output_config,
float* const* dest) = 0;
// Accepts and produces a ~10 ms frame of interleaved 16 bit integer audio for
// the reverse direction audio stream as specified in `input_config` and
// `output_config`. `src` and `dest` may use the same memory, if desired.
virtual int ProcessReverseStream(const int16_t* const src,
const StreamConfig& input_config,
const StreamConfig& output_config,
int16_t* const dest) = 0;
// Accepts deinterleaved float audio with the range [-1, 1]. Each element of
// `data` points to a channel buffer, arranged according to `reverse_config`.
virtual int ProcessReverseStream(const float* const* src,
const StreamConfig& input_config,
const StreamConfig& output_config,
float* const* dest) = 0;
// Accepts deinterleaved float audio with the range [-1, 1]. Each element
// of `data` points to a channel buffer, arranged according to
// `reverse_config`.
virtual int AnalyzeReverseStream(const float* const* data,
const StreamConfig& reverse_config) = 0;
// Returns the most recently produced ~10 ms of the linear AEC output at a
// rate of 16 kHz. If there is more than one capture channel, a mono
// representation of the input is returned. Returns true/false to indicate
// whether an output returned.
virtual bool GetLinearAecOutput(
rtc::ArrayView<std::array<float, 160>> linear_output) const = 0;
// This must be called prior to ProcessStream() if and only if adaptive analog
// gain control is enabled, to pass the current analog level from the audio
// HAL. Must be within the range [0, 255].
virtual void set_stream_analog_level(int level) = 0;
// When an analog mode is set, this should be called after
// `set_stream_analog_level()` and `ProcessStream()` to obtain the recommended
// new analog level for the audio HAL. It is the user's responsibility to
// apply this level.
virtual int recommended_stream_analog_level() const = 0;
// This must be called if and only if echo processing is enabled.
//
// Sets the `delay` in ms between ProcessReverseStream() receiving a far-end
// frame and ProcessStream() receiving a near-end frame containing the
// corresponding echo. On the client-side this can be expressed as
// delay = (t_render - t_analyze) + (t_process - t_capture)
// where,
// - t_analyze is the time a frame is passed to ProcessReverseStream() and
// t_render is the time the first sample of the same frame is rendered by
// the audio hardware.
// - t_capture is the time the first sample of a frame is captured by the
// audio hardware and t_process is the time the same frame is passed to
// ProcessStream().
virtual int set_stream_delay_ms(int delay) = 0;
virtual int stream_delay_ms() const = 0;
// Call to signal that a key press occurred (true) or did not occur (false)
// with this chunk of audio.
virtual void set_stream_key_pressed(bool key_pressed) = 0;
// Creates and attaches an webrtc::AecDump for recording debugging
// information.
// The `worker_queue` may not be null and must outlive the created
// AecDump instance. |max_log_size_bytes == -1| means the log size
// will be unlimited. `handle` may not be null. The AecDump takes
// responsibility for `handle` and closes it in the destructor. A
// return value of true indicates that the file has been
// sucessfully opened, while a value of false indicates that
// opening the file failed.
virtual bool CreateAndAttachAecDump(
absl::string_view file_name,
int64_t max_log_size_bytes,
absl::Nonnull<TaskQueueBase*> worker_queue) = 0;
virtual bool CreateAndAttachAecDump(
absl::Nonnull<FILE*> handle,
int64_t max_log_size_bytes,
absl::Nonnull<TaskQueueBase*> worker_queue) = 0;
// TODO(webrtc:5298) Deprecated variant.
// Attaches provided webrtc::AecDump for recording debugging
// information. Log file and maximum file size logic is supposed to
// be handled by implementing instance of AecDump. Calling this
// method when another AecDump is attached resets the active AecDump
// with a new one. This causes the d-tor of the earlier AecDump to
// be called. The d-tor call may block until all pending logging
// tasks are completed.
virtual void AttachAecDump(std::unique_ptr<AecDump> aec_dump) = 0;
// If no AecDump is attached, this has no effect. If an AecDump is
// attached, it's destructor is called. The d-tor may block until
// all pending logging tasks are completed.
virtual void DetachAecDump() = 0;
// Get audio processing statistics.
virtual AudioProcessingStats GetStatistics() = 0;
// TODO(webrtc:5298) Deprecated variant. The `has_remote_tracks` argument
// should be set if there are active remote tracks (this would usually be true
// during a call). If there are no remote tracks some of the stats will not be
// set by AudioProcessing, because they only make sense if there is at least
// one remote track.
virtual AudioProcessingStats GetStatistics(bool has_remote_tracks) = 0;
// Returns the last applied configuration.
virtual AudioProcessing::Config GetConfig() const = 0;
enum Error {
// Fatal errors.
kNoError = 0,
kUnspecifiedError = -1,
kCreationFailedError = -2,
kUnsupportedComponentError = -3,
kUnsupportedFunctionError = -4,
kNullPointerError = -5,
kBadParameterError = -6,
kBadSampleRateError = -7,
kBadDataLengthError = -8,
kBadNumberChannelsError = -9,
kFileError = -10,
kStreamParameterNotSetError = -11,
kNotEnabledError = -12,
// Warnings are non-fatal.
// This results when a set_stream_ parameter is out of range. Processing
// will continue, but the parameter may have been truncated.
kBadStreamParameterWarning = -13
};
// Native rates supported by the integer interfaces.
enum NativeRate {
kSampleRate8kHz = 8000,
kSampleRate16kHz = 16000,
kSampleRate32kHz = 32000,
kSampleRate48kHz = 48000
};
// TODO(kwiberg): We currently need to support a compiler (Visual C++) that
// complains if we don't explicitly state the size of the array here. Remove
// the size when that's no longer the case.
static constexpr int kNativeSampleRatesHz[4] = {
kSampleRate8kHz, kSampleRate16kHz, kSampleRate32kHz, kSampleRate48kHz};
static constexpr size_t kNumNativeSampleRates =
arraysize(kNativeSampleRatesHz);
static constexpr int kMaxNativeSampleRateHz =
kNativeSampleRatesHz[kNumNativeSampleRates - 1];
// APM processes audio in chunks of about 10 ms. See GetFrameSize() for
// details.
static constexpr int kChunkSizeMs = 10;
// Returns floor(sample_rate_hz/100): the number of samples per channel used
// as input and output to the audio processing module in calls to
// ProcessStream, ProcessReverseStream, AnalyzeReverseStream, and
// GetLinearAecOutput.
//
// This is exactly 10 ms for sample rates divisible by 100. For example:
// - 48000 Hz (480 samples per channel),
// - 44100 Hz (441 samples per channel),
// - 16000 Hz (160 samples per channel).
//
// Sample rates not divisible by 100 are received/produced in frames of
// approximately 10 ms. For example:
// - 22050 Hz (220 samples per channel, or ~9.98 ms per frame),
// - 11025 Hz (110 samples per channel, or ~9.98 ms per frame).
// These nondivisible sample rates yield lower audio quality compared to
// multiples of 100. Internal resampling to 10 ms frames causes a simulated
// clock drift effect which impacts the performance of (for example) echo
// cancellation.
static int GetFrameSize(int sample_rate_hz) { return sample_rate_hz / 100; }
};
// Experimental interface for a custom analysis submodule.
class CustomAudioAnalyzer {
public:
// (Re-) Initializes the submodule.
virtual void Initialize(int sample_rate_hz, int num_channels) = 0;
// Analyzes the given capture or render signal.
virtual void Analyze(const AudioBuffer* audio) = 0;
// Returns a string representation of the module state.
virtual std::string ToString() const = 0;
virtual ~CustomAudioAnalyzer() {}
};
// Interface for a custom processing submodule.
class CustomProcessing {
public:
// (Re-)Initializes the submodule.
virtual void Initialize(int sample_rate_hz, int num_channels) = 0;
// Processes the given capture or render signal.
virtual void Process(AudioBuffer* audio) = 0;
// Returns a string representation of the module state.
virtual std::string ToString() const = 0;
// Handles RuntimeSettings. TODO(webrtc:9262): make pure virtual
// after updating dependencies.
virtual void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting);
virtual ~CustomProcessing() {}
};
class RTC_EXPORT AudioProcessingBuilder {
public:
AudioProcessingBuilder();
AudioProcessingBuilder(const AudioProcessingBuilder&) = delete;
AudioProcessingBuilder& operator=(const AudioProcessingBuilder&) = delete;
~AudioProcessingBuilder();
// Sets the APM configuration.
AudioProcessingBuilder& SetConfig(const AudioProcessing::Config& config) {
config_ = config;
return *this;
}
// Sets the echo controller factory to inject when APM is created.
AudioProcessingBuilder& SetEchoControlFactory(
std::unique_ptr<EchoControlFactory> echo_control_factory) {
echo_control_factory_ = std::move(echo_control_factory);
return *this;
}
// Sets the capture post-processing sub-module to inject when APM is created.
AudioProcessingBuilder& SetCapturePostProcessing(
std::unique_ptr<CustomProcessing> capture_post_processing) {
capture_post_processing_ = std::move(capture_post_processing);
return *this;
}
// Sets the render pre-processing sub-module to inject when APM is created.
AudioProcessingBuilder& SetRenderPreProcessing(
std::unique_ptr<CustomProcessing> render_pre_processing) {
render_pre_processing_ = std::move(render_pre_processing);
return *this;
}
// Sets the echo detector to inject when APM is created.
AudioProcessingBuilder& SetEchoDetector(
rtc::scoped_refptr<EchoDetector> echo_detector) {
echo_detector_ = std::move(echo_detector);
return *this;
}
// Sets the capture analyzer sub-module to inject when APM is created.
AudioProcessingBuilder& SetCaptureAnalyzer(
std::unique_ptr<CustomAudioAnalyzer> capture_analyzer) {
capture_analyzer_ = std::move(capture_analyzer);
return *this;
}
// Creates an APM instance with the specified config or the default one if
// unspecified. Injects the specified components transferring the ownership
// to the newly created APM instance - i.e., except for the config, the
// builder is reset to its initial state.
rtc::scoped_refptr<AudioProcessing> Create();
private:
AudioProcessing::Config config_;
std::unique_ptr<EchoControlFactory> echo_control_factory_;
std::unique_ptr<CustomProcessing> capture_post_processing_;
std::unique_ptr<CustomProcessing> render_pre_processing_;
rtc::scoped_refptr<EchoDetector> echo_detector_;
std::unique_ptr<CustomAudioAnalyzer> capture_analyzer_;
};
class StreamConfig {
public:
// sample_rate_hz: The sampling rate of the stream.
// num_channels: The number of audio channels in the stream.
StreamConfig(int sample_rate_hz = 0,
size_t num_channels = 0) // NOLINT(runtime/explicit)
: sample_rate_hz_(sample_rate_hz),
num_channels_(num_channels),
num_frames_(calculate_frames(sample_rate_hz)) {}
void set_sample_rate_hz(int value) {
sample_rate_hz_ = value;
num_frames_ = calculate_frames(value);
}
void set_num_channels(size_t value) { num_channels_ = value; }
int sample_rate_hz() const { return sample_rate_hz_; }
// The number of channels in the stream.
size_t num_channels() const { return num_channels_; }
size_t num_frames() const { return num_frames_; }
size_t num_samples() const { return num_channels_ * num_frames_; }
bool operator==(const StreamConfig& other) const {
return sample_rate_hz_ == other.sample_rate_hz_ &&
num_channels_ == other.num_channels_;
}
bool operator!=(const StreamConfig& other) const { return !(*this == other); }
private:
static size_t calculate_frames(int sample_rate_hz) {
return static_cast<size_t>(AudioProcessing::GetFrameSize(sample_rate_hz));
}
int sample_rate_hz_;
size_t num_channels_;
size_t num_frames_;
};
class ProcessingConfig {
public:
enum StreamName {
kInputStream,
kOutputStream,
kReverseInputStream,
kReverseOutputStream,
kNumStreamNames,
};
const StreamConfig& input_stream() const {
return streams[StreamName::kInputStream];
}
const StreamConfig& output_stream() const {
return streams[StreamName::kOutputStream];
}
const StreamConfig& reverse_input_stream() const {
return streams[StreamName::kReverseInputStream];
}
const StreamConfig& reverse_output_stream() const {
return streams[StreamName::kReverseOutputStream];
}
StreamConfig& input_stream() { return streams[StreamName::kInputStream]; }
StreamConfig& output_stream() { return streams[StreamName::kOutputStream]; }
StreamConfig& reverse_input_stream() {
return streams[StreamName::kReverseInputStream];
}
StreamConfig& reverse_output_stream() {
return streams[StreamName::kReverseOutputStream];
}
bool operator==(const ProcessingConfig& other) const {
for (int i = 0; i < StreamName::kNumStreamNames; ++i) {
if (this->streams[i] != other.streams[i]) {
return false;
}
}
return true;
}
bool operator!=(const ProcessingConfig& other) const {
return !(*this == other);
}
StreamConfig streams[StreamName::kNumStreamNames];
};
// Interface for an echo detector submodule.
class EchoDetector : public RefCountInterface {
public:
// (Re-)Initializes the submodule.
virtual void Initialize(int capture_sample_rate_hz,
int num_capture_channels,
int render_sample_rate_hz,
int num_render_channels) = 0;
// Analysis (not changing) of the first channel of the render signal.
virtual void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) = 0;
// Analysis (not changing) of the capture signal.
virtual void AnalyzeCaptureAudio(
rtc::ArrayView<const float> capture_audio) = 0;
struct Metrics {
std::optional<double> echo_likelihood;
std::optional<double> echo_likelihood_recent_max;
};
// Collect current metrics from the echo detector.
virtual Metrics GetMetrics() const = 0;
};
} // namespace webrtc
#endif // API_AUDIO_AUDIO_PROCESSING_H_

View File

@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "modules/audio_processing/include/audio_processing_statistics.h" #include "api/audio/audio_processing_statistics.h"
namespace webrtc { namespace webrtc {

View File

@ -0,0 +1,68 @@
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_AUDIO_AUDIO_PROCESSING_STATISTICS_H_
#define API_AUDIO_AUDIO_PROCESSING_STATISTICS_H_
#include <stdint.h>
#include <optional>
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// This version of the stats uses Optionals, it will replace the regular
// AudioProcessingStatistics struct.
struct RTC_EXPORT AudioProcessingStats {
AudioProcessingStats();
AudioProcessingStats(const AudioProcessingStats& other);
~AudioProcessingStats();
// Deprecated.
// TODO(bugs.webrtc.org/11226): Remove.
// True if voice is detected in the last capture frame, after processing.
// It is conservative in flagging audio as speech, with low likelihood of
// incorrectly flagging a frame as voice.
// Only reported if voice detection is enabled in AudioProcessing::Config.
std::optional<bool> voice_detected;
// AEC Statistics.
// ERL = 10log_10(P_far / P_echo)
std::optional<double> echo_return_loss;
// ERLE = 10log_10(P_echo / P_out)
std::optional<double> echo_return_loss_enhancement;
// Fraction of time that the AEC linear filter is divergent, in a 1-second
// non-overlapped aggregation window.
std::optional<double> divergent_filter_fraction;
// The delay metrics consists of the delay median and standard deviation. It
// also consists of the fraction of delay estimates that can make the echo
// cancellation perform poorly. The values are aggregated until the first
// call to `GetStatistics()` and afterwards aggregated and updated every
// second. Note that if there are several clients pulling metrics from
// `GetStatistics()` during a session the first call from any of them will
// change to one second aggregation window for all.
std::optional<int32_t> delay_median_ms;
std::optional<int32_t> delay_standard_deviation_ms;
// Residual echo detector likelihood.
std::optional<double> residual_echo_likelihood;
// Maximum residual echo likelihood from the last time period.
std::optional<double> residual_echo_likelihood_recent_max;
// The instantaneous delay estimate produced in the AEC. The unit is in
// milliseconds and the value is the instantaneous value at the time of the
// call to `GetStatistics()`.
std::optional<int32_t> delay_ms;
};
} // namespace webrtc
#endif // API_AUDIO_AUDIO_PROCESSING_STATISTICS_H_

View File

@ -0,0 +1,269 @@
/*
* Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_AUDIO_AUDIO_VIEW_H_
#define API_AUDIO_AUDIO_VIEW_H_
#include "api/array_view.h"
#include "api/audio/channel_layout.h"
#include "rtc_base/checks.h"
namespace webrtc {
// This file contains 3 types of view classes:
//
// * MonoView<>: A single channel contiguous buffer of samples.
//
// * InterleavedView<>: Channel samples are interleaved (side-by-side) in
// the buffer. A single channel InterleavedView<> is the same thing as a
// MonoView<>
//
// * DeinterleavedView<>: Each channel's samples are contiguous within the
// buffer. Channels can be enumerated and accessing the individual channel
// data is done via MonoView<>.
//
// The views are comparable to and built on rtc::ArrayView<> but add
// audio specific properties for the dimensions of the buffer and the above
// specialized [de]interleaved support.
//
// There are also a few generic utility functions that can simplify
// generic code for supporting more than one type of view.
// MonoView<> represents a view over a single contiguous, audio buffer. This
// can be either an single channel (mono) interleaved buffer (e.g. AudioFrame),
// or a de-interleaved channel (e.g. from AudioBuffer).
template <typename T>
using MonoView = rtc::ArrayView<T>;
// InterleavedView<> is a view over an interleaved audio buffer (e.g. from
// AudioFrame).
template <typename T>
class InterleavedView {
public:
using value_type = T;
InterleavedView() = default;
template <typename U>
InterleavedView(U* data, size_t samples_per_channel, size_t num_channels)
: num_channels_(num_channels),
samples_per_channel_(samples_per_channel),
data_(data, num_channels * samples_per_channel) {
RTC_DCHECK_LE(num_channels_, kMaxConcurrentChannels);
RTC_DCHECK(num_channels_ == 0u || samples_per_channel_ != 0u);
}
// Construct an InterleavedView from a C-style array. Samples per channels
// is calculated based on the array size / num_channels.
template <typename U, size_t N>
InterleavedView(U (&array)[N], // NOLINT
size_t num_channels)
: InterleavedView(array, N / num_channels, num_channels) {
RTC_DCHECK_EQ(N % num_channels, 0u);
}
template <typename U>
InterleavedView(const InterleavedView<U>& other)
: num_channels_(other.num_channels()),
samples_per_channel_(other.samples_per_channel()),
data_(other.data()) {}
size_t num_channels() const { return num_channels_; }
size_t samples_per_channel() const { return samples_per_channel_; }
rtc::ArrayView<T> data() const { return data_; }
bool empty() const { return data_.empty(); }
size_t size() const { return data_.size(); }
MonoView<T> AsMono() const {
RTC_DCHECK_EQ(num_channels(), 1u);
RTC_DCHECK_EQ(data_.size(), samples_per_channel_);
return data_;
}
// A simple wrapper around memcpy that includes checks for properties.
// TODO(tommi): Consider if this can be utility function for both interleaved
// and deinterleaved views.
template <typename U>
void CopyFrom(const InterleavedView<U>& source) {
static_assert(sizeof(T) == sizeof(U), "");
RTC_DCHECK_EQ(num_channels(), source.num_channels());
RTC_DCHECK_EQ(samples_per_channel(), source.samples_per_channel());
RTC_DCHECK_GE(data_.size(), source.data().size());
const auto data = source.data();
memcpy(&data_[0], &data[0], data.size() * sizeof(U));
}
T& operator[](size_t idx) const { return data_[idx]; }
T* begin() const { return data_.begin(); }
T* end() const { return data_.end(); }
const T* cbegin() const { return data_.cbegin(); }
const T* cend() const { return data_.cend(); }
std::reverse_iterator<T*> rbegin() const { return data_.rbegin(); }
std::reverse_iterator<T*> rend() const { return data_.rend(); }
std::reverse_iterator<const T*> crbegin() const { return data_.crbegin(); }
std::reverse_iterator<const T*> crend() const { return data_.crend(); }
private:
// TODO(tommi): Consider having these both be stored as uint16_t to
// save a few bytes per view. Use `dchecked_cast` to support size_t during
// construction.
size_t num_channels_ = 0u;
size_t samples_per_channel_ = 0u;
rtc::ArrayView<T> data_;
};
template <typename T>
class DeinterleavedView {
public:
using value_type = T;
DeinterleavedView() = default;
template <typename U>
DeinterleavedView(U* data, size_t samples_per_channel, size_t num_channels)
: num_channels_(num_channels),
samples_per_channel_(samples_per_channel),
data_(data, num_channels * samples_per_channel_) {}
template <typename U>
DeinterleavedView(const DeinterleavedView<U>& other)
: num_channels_(other.num_channels()),
samples_per_channel_(other.samples_per_channel()),
data_(other.data()) {}
// Returns a deinterleaved channel where `idx` is the zero based index,
// in the range [0 .. num_channels()-1].
MonoView<T> operator[](size_t idx) const {
RTC_DCHECK_LT(idx, num_channels_);
return MonoView<T>(&data_[idx * samples_per_channel_],
samples_per_channel_);
}
size_t num_channels() const { return num_channels_; }
size_t samples_per_channel() const { return samples_per_channel_; }
rtc::ArrayView<T> data() const { return data_; }
bool empty() const { return data_.empty(); }
size_t size() const { return data_.size(); }
// Returns the first (and possibly only) channel.
MonoView<T> AsMono() const {
RTC_DCHECK_GE(num_channels(), 1u);
return (*this)[0];
}
private:
// TODO(tommi): Consider having these be stored as uint16_t to save a few
// bytes per view. Use `dchecked_cast` to support size_t during construction.
size_t num_channels_ = 0u;
size_t samples_per_channel_ = 0u;
rtc::ArrayView<T> data_;
};
template <typename T>
constexpr size_t NumChannels(const MonoView<T>& view) {
return 1u;
}
template <typename T>
size_t NumChannels(const InterleavedView<T>& view) {
return view.num_channels();
}
template <typename T>
size_t NumChannels(const DeinterleavedView<T>& view) {
return view.num_channels();
}
template <typename T>
constexpr bool IsMono(const MonoView<T>& view) {
return true;
}
template <typename T>
constexpr bool IsInterleavedView(const MonoView<T>& view) {
return true;
}
template <typename T>
constexpr bool IsInterleavedView(const InterleavedView<T>& view) {
return true;
}
template <typename T>
constexpr bool IsInterleavedView(const DeinterleavedView<const T>& view) {
return false;
}
template <typename T>
bool IsMono(const InterleavedView<T>& view) {
return NumChannels(view) == 1u;
}
template <typename T>
bool IsMono(const DeinterleavedView<T>& view) {
return NumChannels(view) == 1u;
}
template <typename T>
size_t SamplesPerChannel(const MonoView<T>& view) {
return view.size();
}
template <typename T>
size_t SamplesPerChannel(const InterleavedView<T>& view) {
return view.samples_per_channel();
}
template <typename T>
size_t SamplesPerChannel(const DeinterleavedView<T>& view) {
return view.samples_per_channel();
}
// A simple wrapper around memcpy that includes checks for properties.
// The parameter order is the same as for memcpy(), first destination then
// source.
template <typename D, typename S>
void CopySamples(D& destination, const S& source) {
static_assert(
sizeof(typename D::value_type) == sizeof(typename S::value_type), "");
// Here we'd really like to do
// static_assert(IsInterleavedView(destination) == IsInterleavedView(source),
// "");
// but the compiler doesn't like it inside this template function for
// some reason. The following check is an approximation but unfortunately
// means that copying between a MonoView and single channel interleaved or
// deinterleaved views wouldn't work.
// static_assert(sizeof(destination) == sizeof(source),
// "Incompatible view types");
RTC_DCHECK_EQ(NumChannels(destination), NumChannels(source));
RTC_DCHECK_EQ(SamplesPerChannel(destination), SamplesPerChannel(source));
RTC_DCHECK_GE(destination.size(), source.size());
memcpy(&destination[0], &source[0],
source.size() * sizeof(typename S::value_type));
}
// Sets all the samples in a view to 0. This template function is a simple
// wrapper around `memset()` but adds the benefit of automatically calculating
// the byte size from the number of samples and sample type.
template <typename T>
void ClearSamples(T& view) {
memset(&view[0], 0, view.size() * sizeof(typename T::value_type));
}
// Same as `ClearSamples()` above but allows for clearing only the first
// `sample_count` number of samples.
template <typename T>
void ClearSamples(T& view, size_t sample_count) {
RTC_DCHECK_LE(sample_count, view.size());
memset(&view[0], 0, sample_count * sizeof(typename T::value_type));
}
} // namespace webrtc
#endif // API_AUDIO_AUDIO_VIEW_H_

View File

@ -275,7 +275,7 @@ const char* ChannelLayoutToString(ChannelLayout layout) {
case CHANNEL_LAYOUT_BITSTREAM: case CHANNEL_LAYOUT_BITSTREAM:
return "BITSTREAM"; return "BITSTREAM";
} }
RTC_NOTREACHED() << "Invalid channel layout provided: " << layout; RTC_DCHECK_NOTREACHED() << "Invalid channel layout provided: " << layout;
return ""; return "";
} }

View File

@ -153,6 +153,7 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res & Limit(&c->filter.config_change_duration_blocks, 0, 100000); res = res & Limit(&c->filter.config_change_duration_blocks, 0, 100000);
res = res & Limit(&c->filter.initial_state_seconds, 0.f, 100.f); res = res & Limit(&c->filter.initial_state_seconds, 0.f, 100.f);
res = res & Limit(&c->filter.coarse_reset_hangover_blocks, 0, 250000);
res = res & Limit(&c->erle.min, 1.f, 100000.f); res = res & Limit(&c->erle.min, 1.f, 100000.f);
res = res & Limit(&c->erle.max_l, 1.f, 100000.f); res = res & Limit(&c->erle.max_l, 1.f, 100000.f);
@ -165,6 +166,7 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f); res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f);
res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f); res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f);
res = res & Limit(&c->ep_strength.nearend_len, -1.0f, 1.0f);
res = res =
res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f); res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f);
@ -228,6 +230,12 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res =
res & Limit(&c->suppressor.nearend_tuning.max_dec_factor_lf, 0.f, 100.f); res & Limit(&c->suppressor.nearend_tuning.max_dec_factor_lf, 0.f, 100.f);
res = res & Limit(&c->suppressor.last_permanent_lf_smoothing_band, 0, 64);
res = res & Limit(&c->suppressor.last_lf_smoothing_band, 0, 64);
res = res & Limit(&c->suppressor.last_lf_band, 0, 63);
res = res &
Limit(&c->suppressor.first_hf_band, c->suppressor.last_lf_band + 1, 64);
res = res & Limit(&c->suppressor.dominant_nearend_detection.enr_threshold, res = res & Limit(&c->suppressor.dominant_nearend_detection.enr_threshold,
0.f, 1000000.f); 0.f, 1000000.f);
res = res & Limit(&c->suppressor.dominant_nearend_detection.snr_threshold, res = res & Limit(&c->suppressor.dominant_nearend_detection.snr_threshold,

View File

@ -43,6 +43,7 @@ struct RTC_EXPORT EchoCanceller3Config {
size_t hysteresis_limit_blocks = 1; size_t hysteresis_limit_blocks = 1;
size_t fixed_capture_delay_samples = 0; size_t fixed_capture_delay_samples = 0;
float delay_estimate_smoothing = 0.7f; float delay_estimate_smoothing = 0.7f;
float delay_estimate_smoothing_delay_found = 0.7f;
float delay_candidate_detection_threshold = 0.2f; float delay_candidate_detection_threshold = 0.2f;
struct DelaySelectionThresholds { struct DelaySelectionThresholds {
int initial; int initial;
@ -58,6 +59,7 @@ struct RTC_EXPORT EchoCanceller3Config {
}; };
AlignmentMixing render_alignment_mixing = {false, true, 10000.f, true}; AlignmentMixing render_alignment_mixing = {false, true, 10000.f, true};
AlignmentMixing capture_alignment_mixing = {false, true, 10000.f, false}; AlignmentMixing capture_alignment_mixing = {false, true, 10000.f, false};
bool detect_pre_echo = true;
} delay; } delay;
struct Filter { struct Filter {
@ -86,9 +88,11 @@ struct RTC_EXPORT EchoCanceller3Config {
size_t config_change_duration_blocks = 250; size_t config_change_duration_blocks = 250;
float initial_state_seconds = 2.5f; float initial_state_seconds = 2.5f;
int coarse_reset_hangover_blocks = 25;
bool conservative_initial_phase = false; bool conservative_initial_phase = false;
bool enable_coarse_filter_output_usage = true; bool enable_coarse_filter_output_usage = true;
bool use_linear_filter = true; bool use_linear_filter = true;
bool high_pass_filter_echo_reference = false;
bool export_linear_aec_output = false; bool export_linear_aec_output = false;
} filter; } filter;
@ -105,8 +109,11 @@ struct RTC_EXPORT EchoCanceller3Config {
struct EpStrength { struct EpStrength {
float default_gain = 1.f; float default_gain = 1.f;
float default_len = 0.83f; float default_len = 0.83f;
float nearend_len = 0.83f;
bool echo_can_saturate = true; bool echo_can_saturate = true;
bool bounded_erl = false; bool bounded_erl = false;
bool erle_onset_compensation_in_dominant_nearend = false;
bool use_conservative_tail_frequency_response = true;
} ep_strength; } ep_strength;
struct EchoAudibility { struct EchoAudibility {
@ -190,6 +197,12 @@ struct RTC_EXPORT EchoCanceller3Config {
2.0f, 2.0f,
0.25f); 0.25f);
bool lf_smoothing_during_initial_phase = true;
int last_permanent_lf_smoothing_band = 0;
int last_lf_smoothing_band = 5;
int last_lf_band = 5;
int first_hf_band = 8;
struct DominantNearendDetection { struct DominantNearendDetection {
float enr_threshold = .25f; float enr_threshold = .25f;
float enr_exit_threshold = 10.f; float enr_exit_threshold = 10.f;
@ -197,6 +210,7 @@ struct RTC_EXPORT EchoCanceller3Config {
int hold_duration = 50; int hold_duration = 50;
int trigger_threshold = 12; int trigger_threshold = 12;
bool use_during_initial_phase = true; bool use_during_initial_phase = true;
bool use_unbounded_echo_spectrum = true;
} dominant_nearend_detection; } dominant_nearend_detection;
struct SubbandNearendDetection { struct SubbandNearendDetection {
@ -221,7 +235,15 @@ struct RTC_EXPORT EchoCanceller3Config {
} high_bands_suppression; } high_bands_suppression;
float floor_first_increase = 0.00001f; float floor_first_increase = 0.00001f;
bool conservative_hf_suppression = false;
} suppressor; } suppressor;
struct MultiChannel {
bool detect_stereo_content = true;
float stereo_detection_threshold = 0.0f;
int stereo_detection_timeout_threshold_seconds = 300;
float stereo_detection_hysteresis_seconds = 2.0f;
} multi_channel;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -48,6 +48,13 @@ class EchoControl {
// Provides an optional external estimate of the audio buffer delay. // Provides an optional external estimate of the audio buffer delay.
virtual void SetAudioBufferDelay(int delay_ms) = 0; virtual void SetAudioBufferDelay(int delay_ms) = 0;
// Specifies whether the capture output will be used. The purpose of this is
// to allow the echo controller to deactivate some of the processing when the
// resulting output is anyway not used, for instance when the endpoint is
// muted.
// TODO(b/177830919): Make pure virtual.
virtual void SetCaptureOutputUsage(bool capture_output_used) {}
// Returns wheter the signal is altered. // Returns wheter the signal is altered.
virtual bool ActiveProcessing() const = 0; virtual bool ActiveProcessing() const = 0;

View File

@ -1,170 +0,0 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/audio_codecs/audio_decoder.h"
#include <assert.h>
#include <memory>
#include <utility>
#include "api/array_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/sanitizer.h"
#include "rtc_base/trace_event.h"
namespace webrtc {
namespace {
class OldStyleEncodedFrame final : public AudioDecoder::EncodedAudioFrame {
public:
OldStyleEncodedFrame(AudioDecoder* decoder, rtc::Buffer&& payload)
: decoder_(decoder), payload_(std::move(payload)) {}
size_t Duration() const override {
const int ret = decoder_->PacketDuration(payload_.data(), payload_.size());
return ret < 0 ? 0 : static_cast<size_t>(ret);
}
absl::optional<DecodeResult> Decode(
rtc::ArrayView<int16_t> decoded) const override {
auto speech_type = AudioDecoder::kSpeech;
const int ret = decoder_->Decode(
payload_.data(), payload_.size(), decoder_->SampleRateHz(),
decoded.size() * sizeof(int16_t), decoded.data(), &speech_type);
return ret < 0 ? absl::nullopt
: absl::optional<DecodeResult>(
{static_cast<size_t>(ret), speech_type});
}
private:
AudioDecoder* const decoder_;
const rtc::Buffer payload_;
};
} // namespace
bool AudioDecoder::EncodedAudioFrame::IsDtxPacket() const {
return false;
}
AudioDecoder::ParseResult::ParseResult() = default;
AudioDecoder::ParseResult::ParseResult(ParseResult&& b) = default;
AudioDecoder::ParseResult::ParseResult(uint32_t timestamp,
int priority,
std::unique_ptr<EncodedAudioFrame> frame)
: timestamp(timestamp), priority(priority), frame(std::move(frame)) {
RTC_DCHECK_GE(priority, 0);
}
AudioDecoder::ParseResult::~ParseResult() = default;
AudioDecoder::ParseResult& AudioDecoder::ParseResult::operator=(
ParseResult&& b) = default;
std::vector<AudioDecoder::ParseResult> AudioDecoder::ParsePayload(
rtc::Buffer&& payload,
uint32_t timestamp) {
std::vector<ParseResult> results;
std::unique_ptr<EncodedAudioFrame> frame(
new OldStyleEncodedFrame(this, std::move(payload)));
results.emplace_back(timestamp, 0, std::move(frame));
return results;
}
int AudioDecoder::Decode(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
size_t max_decoded_bytes,
int16_t* decoded,
SpeechType* speech_type) {
TRACE_EVENT0("webrtc", "AudioDecoder::Decode");
rtc::MsanCheckInitialized(rtc::MakeArrayView(encoded, encoded_len));
int duration = PacketDuration(encoded, encoded_len);
if (duration >= 0 &&
duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
return -1;
}
return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
speech_type);
}
int AudioDecoder::DecodeRedundant(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
size_t max_decoded_bytes,
int16_t* decoded,
SpeechType* speech_type) {
TRACE_EVENT0("webrtc", "AudioDecoder::DecodeRedundant");
rtc::MsanCheckInitialized(rtc::MakeArrayView(encoded, encoded_len));
int duration = PacketDurationRedundant(encoded, encoded_len);
if (duration >= 0 &&
duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
return -1;
}
return DecodeRedundantInternal(encoded, encoded_len, sample_rate_hz, decoded,
speech_type);
}
int AudioDecoder::DecodeRedundantInternal(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
int16_t* decoded,
SpeechType* speech_type) {
return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
speech_type);
}
bool AudioDecoder::HasDecodePlc() const {
return false;
}
size_t AudioDecoder::DecodePlc(size_t num_frames, int16_t* decoded) {
return 0;
}
// TODO(bugs.webrtc.org/9676): Remove default implementation.
void AudioDecoder::GeneratePlc(size_t /*requested_samples_per_channel*/,
rtc::BufferT<int16_t>* /*concealment_audio*/) {}
int AudioDecoder::ErrorCode() {
return 0;
}
int AudioDecoder::PacketDuration(const uint8_t* encoded,
size_t encoded_len) const {
return kNotImplemented;
}
int AudioDecoder::PacketDurationRedundant(const uint8_t* encoded,
size_t encoded_len) const {
return kNotImplemented;
}
bool AudioDecoder::PacketHasFec(const uint8_t* encoded,
size_t encoded_len) const {
return false;
}
AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) {
switch (type) {
case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech.
case 1:
return kSpeech;
case 2:
return kComfortNoise;
default:
assert(false);
return kSpeech;
}
}
} // namespace webrtc

View File

@ -1,193 +0,0 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_AUDIO_CODECS_AUDIO_DECODER_H_
#define API_AUDIO_CODECS_AUDIO_DECODER_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "rtc_base/buffer.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
class AudioDecoder {
public:
enum SpeechType {
kSpeech = 1,
kComfortNoise = 2,
};
// Used by PacketDuration below. Save the value -1 for errors.
enum { kNotImplemented = -2 };
AudioDecoder() = default;
virtual ~AudioDecoder() = default;
class EncodedAudioFrame {
public:
struct DecodeResult {
size_t num_decoded_samples;
SpeechType speech_type;
};
virtual ~EncodedAudioFrame() = default;
// Returns the duration in samples-per-channel of this audio frame.
// If no duration can be ascertained, returns zero.
virtual size_t Duration() const = 0;
// Returns true if this packet contains DTX.
virtual bool IsDtxPacket() const;
// Decodes this frame of audio and writes the result in |decoded|.
// |decoded| must be large enough to store as many samples as indicated by a
// call to Duration() . On success, returns an absl::optional containing the
// total number of samples across all channels, as well as whether the
// decoder produced comfort noise or speech. On failure, returns an empty
// absl::optional. Decode may be called at most once per frame object.
virtual absl::optional<DecodeResult> Decode(
rtc::ArrayView<int16_t> decoded) const = 0;
};
struct ParseResult {
ParseResult();
ParseResult(uint32_t timestamp,
int priority,
std::unique_ptr<EncodedAudioFrame> frame);
ParseResult(ParseResult&& b);
~ParseResult();
ParseResult& operator=(ParseResult&& b);
// The timestamp of the frame is in samples per channel.
uint32_t timestamp;
// The relative priority of the frame compared to other frames of the same
// payload and the same timeframe. A higher value means a lower priority.
// The highest priority is zero - negative values are not allowed.
int priority;
std::unique_ptr<EncodedAudioFrame> frame;
};
// Let the decoder parse this payload and prepare zero or more decodable
// frames. Each frame must be between 10 ms and 120 ms long. The caller must
// ensure that the AudioDecoder object outlives any frame objects returned by
// this call. The decoder is free to swap or move the data from the |payload|
// buffer. |timestamp| is the input timestamp, in samples, corresponding to
// the start of the payload.
virtual std::vector<ParseResult> ParsePayload(rtc::Buffer&& payload,
uint32_t timestamp);
// TODO(bugs.webrtc.org/10098): The Decode and DecodeRedundant methods are
// obsolete; callers should call ParsePayload instead. For now, subclasses
// must still implement DecodeInternal.
// Decodes |encode_len| bytes from |encoded| and writes the result in
// |decoded|. The maximum bytes allowed to be written into |decoded| is
// |max_decoded_bytes|. Returns the total number of samples across all
// channels. If the decoder produced comfort noise, |speech_type|
// is set to kComfortNoise, otherwise it is kSpeech. The desired output
// sample rate is provided in |sample_rate_hz|, which must be valid for the
// codec at hand.
int Decode(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
size_t max_decoded_bytes,
int16_t* decoded,
SpeechType* speech_type);
// Same as Decode(), but interfaces to the decoders redundant decode function.
// The default implementation simply calls the regular Decode() method.
int DecodeRedundant(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
size_t max_decoded_bytes,
int16_t* decoded,
SpeechType* speech_type);
// Indicates if the decoder implements the DecodePlc method.
virtual bool HasDecodePlc() const;
// Calls the packet-loss concealment of the decoder to update the state after
// one or several lost packets. The caller has to make sure that the
// memory allocated in |decoded| should accommodate |num_frames| frames.
virtual size_t DecodePlc(size_t num_frames, int16_t* decoded);
// Asks the decoder to generate packet-loss concealment and append it to the
// end of |concealment_audio|. The concealment audio should be in
// channel-interleaved format, with as many channels as the last decoded
// packet produced. The implementation must produce at least
// requested_samples_per_channel, or nothing at all. This is a signal to the
// caller to conceal the loss with other means. If the implementation provides
// concealment samples, it is also responsible for "stitching" it together
// with the decoded audio on either side of the concealment.
// Note: The default implementation of GeneratePlc will be deleted soon. All
// implementations must provide their own, which can be a simple as a no-op.
// TODO(bugs.webrtc.org/9676): Remove default impementation.
virtual void GeneratePlc(size_t requested_samples_per_channel,
rtc::BufferT<int16_t>* concealment_audio);
// Resets the decoder state (empty buffers etc.).
virtual void Reset() = 0;
// Returns the last error code from the decoder.
virtual int ErrorCode();
// Returns the duration in samples-per-channel of the payload in |encoded|
// which is |encoded_len| bytes long. Returns kNotImplemented if no duration
// estimate is available, or -1 in case of an error.
virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
// Returns the duration in samples-per-channel of the redandant payload in
// |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no
// duration estimate is available, or -1 in case of an error.
virtual int PacketDurationRedundant(const uint8_t* encoded,
size_t encoded_len) const;
// Detects whether a packet has forward error correction. The packet is
// comprised of the samples in |encoded| which is |encoded_len| bytes long.
// Returns true if the packet has FEC and false otherwise.
virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
// Returns the actual sample rate of the decoder's output. This value may not
// change during the lifetime of the decoder.
virtual int SampleRateHz() const = 0;
// The number of channels in the decoder's output. This value may not change
// during the lifetime of the decoder.
virtual size_t Channels() const = 0;
protected:
static SpeechType ConvertSpeechType(int16_t type);
virtual int DecodeInternal(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
int16_t* decoded,
SpeechType* speech_type) = 0;
virtual int DecodeRedundantInternal(const uint8_t* encoded,
size_t encoded_len,
int sample_rate_hz,
int16_t* decoded,
SpeechType* speech_type);
private:
RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
};
} // namespace webrtc
#endif // API_AUDIO_CODECS_AUDIO_DECODER_H_

View File

@ -1,113 +0,0 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/audio_codecs/audio_encoder.h"
#include "rtc_base/checks.h"
#include "rtc_base/trace_event.h"
namespace webrtc {
ANAStats::ANAStats() = default;
ANAStats::~ANAStats() = default;
ANAStats::ANAStats(const ANAStats&) = default;
AudioEncoder::EncodedInfo::EncodedInfo() = default;
AudioEncoder::EncodedInfo::EncodedInfo(const EncodedInfo&) = default;
AudioEncoder::EncodedInfo::EncodedInfo(EncodedInfo&&) = default;
AudioEncoder::EncodedInfo::~EncodedInfo() = default;
AudioEncoder::EncodedInfo& AudioEncoder::EncodedInfo::operator=(
const EncodedInfo&) = default;
AudioEncoder::EncodedInfo& AudioEncoder::EncodedInfo::operator=(EncodedInfo&&) =
default;
int AudioEncoder::RtpTimestampRateHz() const {
return SampleRateHz();
}
AudioEncoder::EncodedInfo AudioEncoder::Encode(
uint32_t rtp_timestamp,
rtc::ArrayView<const int16_t> audio,
rtc::Buffer* encoded) {
TRACE_EVENT0("webrtc", "AudioEncoder::Encode");
RTC_CHECK_EQ(audio.size(),
static_cast<size_t>(NumChannels() * SampleRateHz() / 100));
const size_t old_size = encoded->size();
EncodedInfo info = EncodeImpl(rtp_timestamp, audio, encoded);
RTC_CHECK_EQ(encoded->size() - old_size, info.encoded_bytes);
return info;
}
bool AudioEncoder::SetFec(bool enable) {
return !enable;
}
bool AudioEncoder::SetDtx(bool enable) {
return !enable;
}
bool AudioEncoder::GetDtx() const {
return false;
}
bool AudioEncoder::SetApplication(Application application) {
return false;
}
void AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {}
void AudioEncoder::SetTargetBitrate(int target_bps) {}
rtc::ArrayView<std::unique_ptr<AudioEncoder>>
AudioEncoder::ReclaimContainedEncoders() {
return nullptr;
}
bool AudioEncoder::EnableAudioNetworkAdaptor(const std::string& config_string,
RtcEventLog* event_log) {
return false;
}
void AudioEncoder::DisableAudioNetworkAdaptor() {}
void AudioEncoder::OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction) {}
void AudioEncoder::OnReceivedUplinkRecoverablePacketLossFraction(
float uplink_recoverable_packet_loss_fraction) {
RTC_NOTREACHED();
}
void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) {
OnReceivedUplinkBandwidth(target_audio_bitrate_bps, absl::nullopt);
}
void AudioEncoder::OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
absl::optional<int64_t> bwe_period_ms) {}
void AudioEncoder::OnReceivedUplinkAllocation(BitrateAllocationUpdate update) {
OnReceivedUplinkBandwidth(update.target_bitrate.bps(),
update.bwe_period.ms());
}
void AudioEncoder::OnReceivedRtt(int rtt_ms) {}
void AudioEncoder::OnReceivedOverhead(size_t overhead_bytes_per_packet) {}
void AudioEncoder::SetReceiverFrameLengthRange(int min_frame_length_ms,
int max_frame_length_ms) {}
ANAStats AudioEncoder::GetANAStats() const {
return ANAStats();
}
} // namespace webrtc

View File

@ -1,257 +0,0 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_AUDIO_CODECS_AUDIO_ENCODER_H_
#define API_AUDIO_CODECS_AUDIO_ENCODER_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "api/call/bitrate_allocation.h"
#include "api/units/time_delta.h"
#include "rtc_base/buffer.h"
#include "rtc_base/deprecation.h"
namespace webrtc {
class RtcEventLog;
// Statistics related to Audio Network Adaptation.
struct ANAStats {
ANAStats();
ANAStats(const ANAStats&);
~ANAStats();
// Number of actions taken by the ANA bitrate controller since the start of
// the call. If this value is not set, it indicates that the bitrate
// controller is disabled.
absl::optional<uint32_t> bitrate_action_counter;
// Number of actions taken by the ANA channel controller since the start of
// the call. If this value is not set, it indicates that the channel
// controller is disabled.
absl::optional<uint32_t> channel_action_counter;
// Number of actions taken by the ANA DTX controller since the start of the
// call. If this value is not set, it indicates that the DTX controller is
// disabled.
absl::optional<uint32_t> dtx_action_counter;
// Number of actions taken by the ANA FEC controller since the start of the
// call. If this value is not set, it indicates that the FEC controller is
// disabled.
absl::optional<uint32_t> fec_action_counter;
// Number of times the ANA frame length controller decided to increase the
// frame length since the start of the call. If this value is not set, it
// indicates that the frame length controller is disabled.
absl::optional<uint32_t> frame_length_increase_counter;
// Number of times the ANA frame length controller decided to decrease the
// frame length since the start of the call. If this value is not set, it
// indicates that the frame length controller is disabled.
absl::optional<uint32_t> frame_length_decrease_counter;
// The uplink packet loss fractions as set by the ANA FEC controller. If this
// value is not set, it indicates that the ANA FEC controller is not active.
absl::optional<float> uplink_packet_loss_fraction;
};
// This is the interface class for encoders in AudioCoding module. Each codec
// type must have an implementation of this class.
class AudioEncoder {
public:
// Used for UMA logging of codec usage. The same codecs, with the
// same values, must be listed in
// src/tools/metrics/histograms/histograms.xml in chromium to log
// correct values.
enum class CodecType {
kOther = 0, // Codec not specified, and/or not listed in this enum
kOpus = 1,
kIsac = 2,
kPcmA = 3,
kPcmU = 4,
kG722 = 5,
kIlbc = 6,
// Number of histogram bins in the UMA logging of codec types. The
// total number of different codecs that are logged cannot exceed this
// number.
kMaxLoggedAudioCodecTypes
};
struct EncodedInfoLeaf {
size_t encoded_bytes = 0;
uint32_t encoded_timestamp = 0;
int payload_type = 0;
bool send_even_if_empty = false;
bool speech = true;
CodecType encoder_type = CodecType::kOther;
};
// This is the main struct for auxiliary encoding information. Each encoded
// packet should be accompanied by one EncodedInfo struct, containing the
// total number of |encoded_bytes|, the |encoded_timestamp| and the
// |payload_type|. If the packet contains redundant encodings, the |redundant|
// vector will be populated with EncodedInfoLeaf structs. Each struct in the
// vector represents one encoding; the order of structs in the vector is the
// same as the order in which the actual payloads are written to the byte
// stream. When EncoderInfoLeaf structs are present in the vector, the main
// struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the
// vector.
struct EncodedInfo : public EncodedInfoLeaf {
EncodedInfo();
EncodedInfo(const EncodedInfo&);
EncodedInfo(EncodedInfo&&);
~EncodedInfo();
EncodedInfo& operator=(const EncodedInfo&);
EncodedInfo& operator=(EncodedInfo&&);
std::vector<EncodedInfoLeaf> redundant;
};
virtual ~AudioEncoder() = default;
// Returns the input sample rate in Hz and the number of input channels.
// These are constants set at instantiation time.
virtual int SampleRateHz() const = 0;
virtual size_t NumChannels() const = 0;
// Returns the rate at which the RTP timestamps are updated. The default
// implementation returns SampleRateHz().
virtual int RtpTimestampRateHz() const;
// Returns the number of 10 ms frames the encoder will put in the next
// packet. This value may only change when Encode() outputs a packet; i.e.,
// the encoder may vary the number of 10 ms frames from packet to packet, but
// it must decide the length of the next packet no later than when outputting
// the preceding packet.
virtual size_t Num10MsFramesInNextPacket() const = 0;
// Returns the maximum value that can be returned by
// Num10MsFramesInNextPacket().
virtual size_t Max10MsFramesInAPacket() const = 0;
// Returns the current target bitrate in bits/s. The value -1 means that the
// codec adapts the target automatically, and a current target cannot be
// provided.
virtual int GetTargetBitrate() const = 0;
// Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
// NumChannels() samples). Multi-channel audio must be sample-interleaved.
// The encoder appends zero or more bytes of output to |encoded| and returns
// additional encoding information. Encode() checks some preconditions, calls
// EncodeImpl() which does the actual work, and then checks some
// postconditions.
EncodedInfo Encode(uint32_t rtp_timestamp,
rtc::ArrayView<const int16_t> audio,
rtc::Buffer* encoded);
// Resets the encoder to its starting state, discarding any input that has
// been fed to the encoder but not yet emitted in a packet.
virtual void Reset() = 0;
// Enables or disables codec-internal FEC (forward error correction). Returns
// true if the codec was able to comply. The default implementation returns
// true when asked to disable FEC and false when asked to enable it (meaning
// that FEC isn't supported).
virtual bool SetFec(bool enable);
// Enables or disables codec-internal VAD/DTX. Returns true if the codec was
// able to comply. The default implementation returns true when asked to
// disable DTX and false when asked to enable it (meaning that DTX isn't
// supported).
virtual bool SetDtx(bool enable);
// Returns the status of codec-internal DTX. The default implementation always
// returns false.
virtual bool GetDtx() const;
// Sets the application mode. Returns true if the codec was able to comply.
// The default implementation just returns false.
enum class Application { kSpeech, kAudio };
virtual bool SetApplication(Application application);
// Tells the encoder about the highest sample rate the decoder is expected to
// use when decoding the bitstream. The encoder would typically use this
// information to adjust the quality of the encoding. The default
// implementation does nothing.
virtual void SetMaxPlaybackRate(int frequency_hz);
// This is to be deprecated. Please use |OnReceivedTargetAudioBitrate|
// instead.
// Tells the encoder what average bitrate we'd like it to produce. The
// encoder is free to adjust or disregard the given bitrate (the default
// implementation does the latter).
RTC_DEPRECATED virtual void SetTargetBitrate(int target_bps);
// Causes this encoder to let go of any other encoders it contains, and
// returns a pointer to an array where they are stored (which is required to
// live as long as this encoder). Unless the returned array is empty, you may
// not call any methods on this encoder afterwards, except for the
// destructor. The default implementation just returns an empty array.
// NOTE: This method is subject to change. Do not call or override it.
virtual rtc::ArrayView<std::unique_ptr<AudioEncoder>>
ReclaimContainedEncoders();
// Enables audio network adaptor. Returns true if successful.
virtual bool EnableAudioNetworkAdaptor(const std::string& config_string,
RtcEventLog* event_log);
// Disables audio network adaptor.
virtual void DisableAudioNetworkAdaptor();
// Provides uplink packet loss fraction to this encoder to allow it to adapt.
// |uplink_packet_loss_fraction| is in the range [0.0, 1.0].
virtual void OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction);
RTC_DEPRECATED virtual void OnReceivedUplinkRecoverablePacketLossFraction(
float uplink_recoverable_packet_loss_fraction);
// Provides target audio bitrate to this encoder to allow it to adapt.
virtual void OnReceivedTargetAudioBitrate(int target_bps);
// Provides target audio bitrate and corresponding probing interval of
// the bandwidth estimator to this encoder to allow it to adapt.
virtual void OnReceivedUplinkBandwidth(int target_audio_bitrate_bps,
absl::optional<int64_t> bwe_period_ms);
// Provides target audio bitrate and corresponding probing interval of
// the bandwidth estimator to this encoder to allow it to adapt.
virtual void OnReceivedUplinkAllocation(BitrateAllocationUpdate update);
// Provides RTT to this encoder to allow it to adapt.
virtual void OnReceivedRtt(int rtt_ms);
// Provides overhead to this encoder to adapt. The overhead is the number of
// bytes that will be added to each packet the encoder generates.
virtual void OnReceivedOverhead(size_t overhead_bytes_per_packet);
// To allow encoder to adapt its frame length, it must be provided the frame
// length range that receivers can accept.
virtual void SetReceiverFrameLengthRange(int min_frame_length_ms,
int max_frame_length_ms);
// Get statistics related to audio network adaptation.
virtual ANAStats GetANAStats() const;
// The range of frame lengths that are supported or nullopt if there's no sch
// information. This is used to calculated the full bitrate range, including
// overhead.
virtual absl::optional<std::pair<TimeDelta, TimeDelta>> GetFrameLengthRange()
const = 0;
protected:
// Subclasses implement this to perform the actual encoding. Called by
// Encode().
virtual EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
rtc::ArrayView<const int16_t> audio,
rtc::Buffer* encoded) = 0;
};
} // namespace webrtc
#endif // API_AUDIO_CODECS_AUDIO_ENCODER_H_

View File

@ -1,45 +0,0 @@
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_CALL_BITRATE_ALLOCATION_H_
#define API_CALL_BITRATE_ALLOCATION_H_
#include "api/units/data_rate.h"
#include "api/units/time_delta.h"
namespace webrtc {
// BitrateAllocationUpdate provides information to allocated streams about their
// bitrate allocation. It originates from the BitrateAllocater class and is
// propagated from there.
struct BitrateAllocationUpdate {
// The allocated target bitrate. Media streams should produce this amount of
// data. (Note that this may include packet overhead depending on
// configuration.)
DataRate target_bitrate = DataRate::Zero();
// The allocated part of the estimated link capacity. This is more stable than
// the target as it is based on the underlying link capacity estimate. This
// should be used to change encoder configuration when the cost of change is
// high.
DataRate stable_target_bitrate = DataRate::Zero();
// Predicted packet loss ratio.
double packet_loss_ratio = 0;
// Predicted round trip time.
TimeDelta round_trip_time = TimeDelta::PlusInfinity();
// |bwe_period| is deprecated, use |stable_target_bitrate| allocation instead.
TimeDelta bwe_period = TimeDelta::PlusInfinity();
// Congestion window pushback bitrate reduction fraction. Used in
// VideoStreamEncoder to reduce the bitrate by the given fraction
// by dropping frames.
double cwnd_reduce_ratio = 0;
};
} // namespace webrtc
#endif // API_CALL_BITRATE_ALLOCATION_H_

View File

@ -11,6 +11,7 @@
#ifndef API_FUNCTION_VIEW_H_ #ifndef API_FUNCTION_VIEW_H_
#define API_FUNCTION_VIEW_H_ #define API_FUNCTION_VIEW_H_
#include <cstddef>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

31
webrtc/api/location.h Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright 2023 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_LOCATION_H_
#define API_LOCATION_H_
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// Location provides basic info where of an object was constructed, or was
// significantly brought to life. This is a stripped down version of
// https://source.chromium.org/chromium/chromium/src/+/main:base/location.h
// that only specifies an interface compatible to how base::Location is
// supposed to be used.
// The declaration is overriden inside the Chromium build.
class RTC_EXPORT Location {
public:
static Location Current() { return Location(); }
};
} // namespace webrtc
#endif // API_LOCATION_H_

View File

@ -0,0 +1,130 @@
/*
* Copyright 2022 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_MAKE_REF_COUNTED_H_
#define API_MAKE_REF_COUNTED_H_
#include <type_traits>
#include <utility>
#include "absl/base/nullability.h"
#include "api/ref_count.h"
#include "api/scoped_refptr.h"
#include "rtc_base/ref_counted_object.h"
namespace webrtc {
namespace webrtc_make_ref_counted_internal {
// Determines if the given class has AddRef and Release methods.
template <typename T>
class HasAddRefAndRelease {
private:
template <typename C,
decltype(std::declval<C>().AddRef())* = nullptr,
decltype(std::declval<C>().Release())* = nullptr>
static int Test(int);
template <typename>
static char Test(...);
public:
static constexpr bool value = std::is_same_v<decltype(Test<T>(0)), int>;
};
} // namespace webrtc_make_ref_counted_internal
// General utilities for constructing a reference counted class and the
// appropriate reference count implementation for that class.
//
// These utilities select either the `RefCountedObject` implementation or
// `FinalRefCountedObject` depending on whether the to-be-shared class is
// derived from the RefCountInterface interface or not (respectively).
// `make_ref_counted`:
//
// Use this when you want to construct a reference counted object of type T and
// get a `scoped_refptr<>` back. Example:
//
// auto p = make_ref_counted<Foo>("bar", 123);
//
// For a class that inherits from RefCountInterface, this is equivalent to:
//
// auto p = scoped_refptr<Foo>(new RefCountedObject<Foo>("bar", 123));
//
// If the class does not inherit from RefCountInterface, but does have
// AddRef/Release methods (so a T* is convertible to rtc::scoped_refptr), this
// is equivalent to just
//
// auto p = scoped_refptr<Foo>(new Foo("bar", 123));
//
// Otherwise, the example is equivalent to:
//
// auto p = scoped_refptr<FinalRefCountedObject<Foo>>(
// new FinalRefCountedObject<Foo>("bar", 123));
//
// In these cases, `make_ref_counted` reduces the amount of boilerplate code but
// also helps with the most commonly intended usage of RefCountedObject whereby
// methods for reference counting, are virtual and designed to satisfy the need
// of an interface. When such a need does not exist, it is more efficient to use
// the `FinalRefCountedObject` template, which does not add the vtable overhead.
//
// Note that in some cases, using RefCountedObject directly may still be what's
// needed.
// `make_ref_counted` for abstract classes that are convertible to
// RefCountInterface. The is_abstract requirement rejects classes that inherit
// both RefCountInterface and RefCounted object, which is a a discouraged
// pattern, and would result in double inheritance of RefCountedObject if this
// template was applied.
template <
typename T,
typename... Args,
typename std::enable_if<std::is_convertible_v<T*, RefCountInterface*> &&
std::is_abstract_v<T>,
T>::type* = nullptr>
absl::Nonnull<scoped_refptr<T>> make_ref_counted(Args&&... args) {
return scoped_refptr<T>(new RefCountedObject<T>(std::forward<Args>(args)...));
}
// `make_ref_counted` for complete classes that are not convertible to
// RefCountInterface and already carry a ref count.
template <
typename T,
typename... Args,
typename std::enable_if<
!std::is_convertible_v<T*, RefCountInterface*> &&
webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
T>::type* = nullptr>
absl::Nonnull<scoped_refptr<T>> make_ref_counted(Args&&... args) {
return scoped_refptr<T>(new T(std::forward<Args>(args)...));
}
// `make_ref_counted` for complete classes that are not convertible to
// RefCountInterface and have no ref count of their own.
template <
typename T,
typename... Args,
typename std::enable_if<
!std::is_convertible_v<T*, RefCountInterface*> &&
!webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
T>::type* = nullptr>
absl::Nonnull<scoped_refptr<FinalRefCountedObject<T>>> make_ref_counted(
Args&&... args) {
return scoped_refptr<FinalRefCountedObject<T>>(
new FinalRefCountedObject<T>(std::forward<Args>(args)...));
}
} // namespace webrtc
namespace rtc {
// Backwards compatibe alias.
// TODO: bugs.webrtc.org/42225969 - deprecate and remove.
using ::webrtc::make_ref_counted;
} // namespace rtc
#endif // API_MAKE_REF_COUNTED_H_

View File

@ -1,14 +1,12 @@
api_sources = [ api_sources = [
'audio/audio_frame.cc', 'audio/audio_frame.cc',
'audio/audio_processing.cc',
'audio/audio_processing_statistics.cc',
'audio/channel_layout.cc', 'audio/channel_layout.cc',
'audio/echo_canceller3_config.cc', 'audio/echo_canceller3_config.cc',
'audio_codecs/audio_decoder.cc',
'audio_codecs/audio_encoder.cc',
'rtp_headers.cc', 'rtp_headers.cc',
'rtp_packet_info.cc', 'rtp_packet_info.cc',
'task_queue/task_queue_base.cc', 'task_queue/task_queue_base.cc',
'units/data_rate.cc',
'units/data_size.cc',
'units/frequency.cc', 'units/frequency.cc',
'units/time_delta.cc', 'units/time_delta.cc',
'units/timestamp.cc', 'units/timestamp.cc',
@ -20,9 +18,15 @@ api_sources = [
api_headers = [ api_headers = [
['', 'array_view.h'], ['', 'array_view.h'],
['', 'location.h'],
['', 'ref_count.h'],
['', 'scoped_refptr.h'], ['', 'scoped_refptr.h'],
['audio', 'audio_processing.h'],
['audio', 'audio_processing_statistics.h'],
['audio', 'echo_canceller3_config.h'], ['audio', 'echo_canceller3_config.h'],
['audio', 'echo_control.h'], ['audio', 'echo_control.h'],
['task_queue', 'task_queue_base.h'],
['units', 'time_delta.h'],
] ]
foreach h : api_headers foreach h : api_headers

67
webrtc/api/ref_count.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_REF_COUNT_H_
#define API_REF_COUNT_H_
namespace webrtc {
// Refcounted objects should implement the following informal interface:
//
// void AddRef() const ;
// RefCountReleaseStatus Release() const;
//
// You may access members of a reference-counted object, including the AddRef()
// and Release() methods, only if you already own a reference to it, or if
// you're borrowing someone else's reference. (A newly created object is a
// special case: the reference count is zero on construction, and the code that
// creates the object should immediately call AddRef(), bringing the reference
// count from zero to one, e.g., by constructing an rtc::scoped_refptr).
//
// AddRef() creates a new reference to the object.
//
// Release() releases a reference to the object; the caller now has one less
// reference than before the call. Returns kDroppedLastRef if the number of
// references dropped to zero because of this (in which case the object destroys
// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise
// time the caller's reference was dropped, other references still remained (but
// if other threads own references, this may of course have changed by the time
// Release() returns).
//
// The caller of Release() must treat it in the same way as a delete operation:
// Regardless of the return value from Release(), the caller mustn't access the
// object. The object might still be alive, due to references held by other
// users of the object, but the object can go away at any time, e.g., as the
// result of another thread calling Release().
//
// Calling AddRef() and Release() manually is discouraged. It's recommended to
// use rtc::scoped_refptr to manage all pointers to reference counted objects.
// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally
// implementing the below RefCountInterface is not required.
enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained };
// Interfaces where refcounting is part of the public api should
// inherit this abstract interface. The implementation of these
// methods is usually provided by the RefCountedObject template class,
// applied as a leaf in the inheritance tree.
class RefCountInterface {
public:
virtual void AddRef() const = 0;
virtual RefCountReleaseStatus Release() const = 0;
// Non-public destructor, because Release() has exclusive responsibility for
// destroying the object.
protected:
virtual ~RefCountInterface() {}
};
} // namespace webrtc
#endif // API_REF_COUNT_H_

View File

@ -10,16 +10,20 @@
#ifndef API_REF_COUNTED_BASE_H_ #ifndef API_REF_COUNTED_BASE_H_
#define API_REF_COUNTED_BASE_H_ #define API_REF_COUNTED_BASE_H_
#include "rtc_base/constructor_magic.h" #include <type_traits>
#include "rtc_base/ref_count.h"
#include "api/ref_count.h"
#include "rtc_base/ref_counter.h" #include "rtc_base/ref_counter.h"
namespace rtc { namespace webrtc {
class RefCountedBase { class RefCountedBase {
public: public:
RefCountedBase() = default; RefCountedBase() = default;
RefCountedBase(const RefCountedBase&) = delete;
RefCountedBase& operator=(const RefCountedBase&) = delete;
void AddRef() const { ref_count_.IncRef(); } void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const { RefCountReleaseStatus Release() const {
const auto status = ref_count_.DecRef(); const auto status = ref_count_.DecRef();
@ -30,14 +34,74 @@ class RefCountedBase {
} }
protected: protected:
// Provided for internal webrtc subclasses for corner cases where it's
// necessary to know whether or not a reference is exclusively held.
bool HasOneRef() const { return ref_count_.HasOneRef(); }
virtual ~RefCountedBase() = default; virtual ~RefCountedBase() = default;
private: private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0}; mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
}; };
// Template based version of `RefCountedBase` for simple implementations that do
// not need (or want) destruction via virtual destructor or the overhead of a
// vtable.
//
// To use:
// struct MyInt : public rtc::RefCountedNonVirtual<MyInt> {
// int foo_ = 0;
// };
//
// rtc::scoped_refptr<MyInt> my_int(new MyInt());
//
// sizeof(MyInt) on a 32 bit system would then be 8, int + refcount and no
// vtable generated.
template <typename T>
class RefCountedNonVirtual {
public:
RefCountedNonVirtual() = default;
RefCountedNonVirtual(const RefCountedNonVirtual&) = delete;
RefCountedNonVirtual& operator=(const RefCountedNonVirtual&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
// If you run into this assert, T has virtual methods. There are two
// options:
// 1) The class doesn't actually need virtual methods, the type is complete
// so the virtual attribute(s) can be removed.
// 2) The virtual methods are a part of the design of the class. In this
// case you can consider using `RefCountedBase` instead or alternatively
// use `rtc::RefCountedObject`.
static_assert(!std::is_polymorphic<T>::value,
"T has virtual methods. RefCountedBase is a better fit.");
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete static_cast<const T*>(this);
}
return status;
}
protected:
// Provided for internal webrtc subclasses for corner cases where it's
// necessary to know whether or not a reference is exclusively held.
bool HasOneRef() const { return ref_count_.HasOneRef(); }
~RefCountedNonVirtual() = default;
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
} // namespace webrtc
// Backwards compatibe aliases.
// TODO: https://issues.webrtc.org/42225969 - deprecate and remove.
namespace rtc {
using RefCountedBase = webrtc::RefCountedBase;
template <typename T>
using RefCountedNonVirtual = webrtc::RefCountedNonVirtual<T>;
} // namespace rtc } // namespace rtc
#endif // API_REF_COUNTED_BASE_H_ #endif // API_REF_COUNTED_BASE_H_

View File

@ -10,8 +10,20 @@
#include "api/rtp_headers.h" #include "api/rtp_headers.h"
#include "api/video/video_content_type.h"
#include "api/video/video_rotation.h"
#include "rtc_base/checks.h"
namespace webrtc { namespace webrtc {
AudioLevel::AudioLevel() : voice_activity_(false), audio_level_(0) {}
AudioLevel::AudioLevel(bool voice_activity, int audio_level)
: voice_activity_(voice_activity), audio_level_(audio_level) {
RTC_CHECK_GE(audio_level, 0);
RTC_CHECK_LE(audio_level, 127);
}
RTPHeaderExtension::RTPHeaderExtension() RTPHeaderExtension::RTPHeaderExtension()
: hasTransmissionTimeOffset(false), : hasTransmissionTimeOffset(false),
transmissionTimeOffset(0), transmissionTimeOffset(0),
@ -19,9 +31,6 @@ RTPHeaderExtension::RTPHeaderExtension()
absoluteSendTime(0), absoluteSendTime(0),
hasTransportSequenceNumber(false), hasTransportSequenceNumber(false),
transportSequenceNumber(0), transportSequenceNumber(0),
hasAudioLevel(false),
voiceActivity(false),
audioLevel(0),
hasVideoRotation(false), hasVideoRotation(false),
videoRotation(kVideoRotation_0), videoRotation(kVideoRotation_0),
hasVideoContentType(false), hasVideoContentType(false),
@ -44,7 +53,6 @@ RTPHeader::RTPHeader()
arrOfCSRCs(), arrOfCSRCs(),
paddingLength(0), paddingLength(0),
headerLength(0), headerLength(0),
payload_type_frequency(0),
extension() {} extension() {}
RTPHeader::RTPHeader(const RTPHeader& other) = default; RTPHeader::RTPHeader(const RTPHeader& other) = default;

View File

@ -14,15 +14,16 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <optional>
#include <string> #include <string>
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "api/units/timestamp.h" #include "api/units/timestamp.h"
#include "api/video/color_space.h" #include "api/video/color_space.h"
#include "api/video/video_content_type.h" #include "api/video/video_content_type.h"
#include "api/video/video_rotation.h" #include "api/video/video_rotation.h"
#include "api/video/video_timing.h" #include "api/video/video_timing.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc { namespace webrtc {
@ -74,7 +75,30 @@ struct AbsoluteCaptureTime {
// systems NTP clock: // systems NTP clock:
// //
// Capture NTP Clock = Sender NTP Clock + Capture Clock Offset // Capture NTP Clock = Sender NTP Clock + Capture Clock Offset
absl::optional<int64_t> estimated_capture_clock_offset; std::optional<int64_t> estimated_capture_clock_offset;
};
// The audio level extension is used to indicate the voice activity and the
// audio level of the payload in the RTP stream. See:
// https://tools.ietf.org/html/rfc6464#section-3.
class AudioLevel {
public:
AudioLevel();
AudioLevel(bool voice_activity, int audio_level);
AudioLevel(const AudioLevel& other) = default;
AudioLevel& operator=(const AudioLevel& other) = default;
// Flag indicating whether the encoder believes the audio packet contains
// voice activity.
bool voice_activity() const { return voice_activity_; }
// Audio level in -dBov. Values range from 0 to 127, representing 0 to -127
// dBov. 127 represents digital silence.
int level() const { return audio_level_; }
private:
bool voice_activity_;
int audio_level_;
}; };
inline bool operator==(const AbsoluteCaptureTime& lhs, inline bool operator==(const AbsoluteCaptureTime& lhs,
@ -103,29 +127,22 @@ struct RTPHeaderExtension {
(1 << kAbsSendTimeFraction)); (1 << kAbsSendTimeFraction));
} }
TimeDelta GetAbsoluteSendTimeDelta(uint32_t previous_sendtime) const {
RTC_DCHECK(hasAbsoluteSendTime);
RTC_DCHECK(absoluteSendTime < (1ul << 24));
RTC_DCHECK(previous_sendtime < (1ul << 24));
int32_t delta =
static_cast<int32_t>((absoluteSendTime - previous_sendtime) << 8) >> 8;
return TimeDelta::Micros((delta * 1000000ll) / (1 << kAbsSendTimeFraction));
}
bool hasTransmissionTimeOffset; bool hasTransmissionTimeOffset;
int32_t transmissionTimeOffset; int32_t transmissionTimeOffset;
bool hasAbsoluteSendTime; bool hasAbsoluteSendTime;
uint32_t absoluteSendTime; uint32_t absoluteSendTime;
absl::optional<AbsoluteCaptureTime> absolute_capture_time; std::optional<AbsoluteCaptureTime> absolute_capture_time;
bool hasTransportSequenceNumber; bool hasTransportSequenceNumber;
uint16_t transportSequenceNumber; uint16_t transportSequenceNumber;
absl::optional<FeedbackRequest> feedback_request; std::optional<FeedbackRequest> feedback_request;
// Audio Level includes both level in dBov and voiced/unvoiced bit. See: // Audio Level includes both level in dBov and voiced/unvoiced bit. See:
// https://tools.ietf.org/html/rfc6464#section-3 // https://tools.ietf.org/html/rfc6464#section-3
bool hasAudioLevel; std::optional<AudioLevel> audio_level() const { return audio_level_; }
bool voiceActivity;
uint8_t audioLevel; void set_audio_level(std::optional<AudioLevel> audio_level) {
audio_level_ = audio_level;
}
// For Coordination of Video Orientation. See // For Coordination of Video Orientation. See
// http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/ // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
@ -133,7 +150,7 @@ struct RTPHeaderExtension {
bool hasVideoRotation; bool hasVideoRotation;
VideoRotation videoRotation; VideoRotation videoRotation;
// TODO(ilnik): Refactor this and one above to be absl::optional() and remove // TODO(ilnik): Refactor this and one above to be std::optional() and remove
// a corresponding bool flag. // a corresponding bool flag.
bool hasVideoContentType; bool hasVideoContentType;
VideoContentType videoContentType; VideoContentType videoContentType;
@ -144,21 +161,23 @@ struct RTPHeaderExtension {
VideoPlayoutDelay playout_delay; VideoPlayoutDelay playout_delay;
// For identification of a stream when ssrc is not signaled. See // For identification of a stream when ssrc is not signaled. See
// https://tools.ietf.org/html/draft-ietf-avtext-rid-09 // https://tools.ietf.org/html/rfc8852
// TODO(danilchap): Update url from draft to release version.
std::string stream_id; std::string stream_id;
std::string repaired_stream_id; std::string repaired_stream_id;
// For identifying the media section used to interpret this RTP packet. See // For identifying the media section used to interpret this RTP packet. See
// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38 // https://tools.ietf.org/html/rfc8843
std::string mid; std::string mid;
absl::optional<ColorSpace> color_space; std::optional<ColorSpace> color_space;
private:
std::optional<AudioLevel> audio_level_;
}; };
enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13
struct RTPHeader { struct RTC_EXPORT RTPHeader {
RTPHeader(); RTPHeader();
RTPHeader(const RTPHeader& other); RTPHeader(const RTPHeader& other);
RTPHeader& operator=(const RTPHeader& other); RTPHeader& operator=(const RTPHeader& other);
@ -172,7 +191,6 @@ struct RTPHeader {
uint32_t arrOfCSRCs[kRtpCsrcSize]; uint32_t arrOfCSRCs[kRtpCsrcSize];
size_t paddingLength; size_t paddingLength;
size_t headerLength; size_t headerLength;
int payload_type_frequency;
RTPHeaderExtension extension; RTPHeaderExtension extension;
}; };

View File

@ -10,40 +10,42 @@
#include "api/rtp_packet_info.h" #include "api/rtp_packet_info.h"
#include <stddef.h>
#include <algorithm> #include <algorithm>
#include <cstdint>
#include <utility> #include <utility>
#include <vector>
#include "api/rtp_headers.h"
#include "api/units/timestamp.h"
namespace webrtc { namespace webrtc {
RtpPacketInfo::RtpPacketInfo() RtpPacketInfo::RtpPacketInfo()
: ssrc_(0), rtp_timestamp_(0), receive_time_ms_(-1) {} : ssrc_(0), rtp_timestamp_(0), receive_time_(Timestamp::MinusInfinity()) {}
RtpPacketInfo::RtpPacketInfo( RtpPacketInfo::RtpPacketInfo(uint32_t ssrc,
uint32_t ssrc, std::vector<uint32_t> csrcs,
std::vector<uint32_t> csrcs, uint32_t rtp_timestamp,
uint32_t rtp_timestamp, Timestamp receive_time)
absl::optional<uint8_t> audio_level,
absl::optional<AbsoluteCaptureTime> absolute_capture_time,
int64_t receive_time_ms)
: ssrc_(ssrc), : ssrc_(ssrc),
csrcs_(std::move(csrcs)), csrcs_(std::move(csrcs)),
rtp_timestamp_(rtp_timestamp), rtp_timestamp_(rtp_timestamp),
audio_level_(audio_level), receive_time_(receive_time) {}
absolute_capture_time_(absolute_capture_time),
receive_time_ms_(receive_time_ms) {}
RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header, RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header,
int64_t receive_time_ms) Timestamp receive_time)
: ssrc_(rtp_header.ssrc), : ssrc_(rtp_header.ssrc),
rtp_timestamp_(rtp_header.timestamp), rtp_timestamp_(rtp_header.timestamp),
receive_time_ms_(receive_time_ms) { receive_time_(receive_time) {
const auto& extension = rtp_header.extension; const auto& extension = rtp_header.extension;
const auto csrcs_count = std::min<size_t>(rtp_header.numCSRCs, kRtpCsrcSize); const auto csrcs_count = std::min<size_t>(rtp_header.numCSRCs, kRtpCsrcSize);
csrcs_.assign(&rtp_header.arrOfCSRCs[0], &rtp_header.arrOfCSRCs[csrcs_count]); csrcs_.assign(&rtp_header.arrOfCSRCs[0], &rtp_header.arrOfCSRCs[csrcs_count]);
if (extension.hasAudioLevel) { if (extension.audio_level()) {
audio_level_ = extension.audioLevel; audio_level_ = extension.audio_level()->level();
} }
absolute_capture_time_ = extension.absolute_capture_time; absolute_capture_time_ = extension.absolute_capture_time;
@ -52,9 +54,10 @@ RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header,
bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) { bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) {
return (lhs.ssrc() == rhs.ssrc()) && (lhs.csrcs() == rhs.csrcs()) && return (lhs.ssrc() == rhs.ssrc()) && (lhs.csrcs() == rhs.csrcs()) &&
(lhs.rtp_timestamp() == rhs.rtp_timestamp()) && (lhs.rtp_timestamp() == rhs.rtp_timestamp()) &&
(lhs.receive_time() == rhs.receive_time()) &&
(lhs.audio_level() == rhs.audio_level()) && (lhs.audio_level() == rhs.audio_level()) &&
(lhs.absolute_capture_time() == rhs.absolute_capture_time()) && (lhs.absolute_capture_time() == rhs.absolute_capture_time()) &&
(lhs.receive_time_ms() == rhs.receive_time_ms()); (lhs.local_capture_clock_offset() == rhs.local_capture_clock_offset());
} }
} // namespace webrtc } // namespace webrtc

View File

@ -12,19 +12,21 @@
#define API_RTP_PACKET_INFO_H_ #define API_RTP_PACKET_INFO_H_
#include <cstdint> #include <cstdint>
#include <optional>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/types/optional.h"
#include "api/rtp_headers.h" #include "api/rtp_headers.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/system/rtc_export.h" #include "rtc_base/system/rtc_export.h"
namespace webrtc { namespace webrtc {
// //
// Structure to hold information about a received |RtpPacket|. It is primarily // Structure to hold information about a received `RtpPacket`. It is primarily
// used to carry per-packet information from when a packet is received until // used to carry per-packet information from when a packet is received until
// the information is passed to |SourceTracker|. // the information is passed to `SourceTracker`.
// //
class RTC_EXPORT RtpPacketInfo { class RTC_EXPORT RtpPacketInfo {
public: public:
@ -33,11 +35,9 @@ class RTC_EXPORT RtpPacketInfo {
RtpPacketInfo(uint32_t ssrc, RtpPacketInfo(uint32_t ssrc,
std::vector<uint32_t> csrcs, std::vector<uint32_t> csrcs,
uint32_t rtp_timestamp, uint32_t rtp_timestamp,
absl::optional<uint8_t> audio_level, Timestamp receive_time);
absl::optional<AbsoluteCaptureTime> absolute_capture_time,
int64_t receive_time_ms);
RtpPacketInfo(const RTPHeader& rtp_header, int64_t receive_time_ms); RtpPacketInfo(const RTPHeader& rtp_header, Timestamp receive_time);
RtpPacketInfo(const RtpPacketInfo& other) = default; RtpPacketInfo(const RtpPacketInfo& other) = default;
RtpPacketInfo(RtpPacketInfo&& other) = default; RtpPacketInfo(RtpPacketInfo&& other) = default;
@ -53,19 +53,32 @@ class RTC_EXPORT RtpPacketInfo {
uint32_t rtp_timestamp() const { return rtp_timestamp_; } uint32_t rtp_timestamp() const { return rtp_timestamp_; }
void set_rtp_timestamp(uint32_t value) { rtp_timestamp_ = value; } void set_rtp_timestamp(uint32_t value) { rtp_timestamp_ = value; }
absl::optional<uint8_t> audio_level() const { return audio_level_; } Timestamp receive_time() const { return receive_time_; }
void set_audio_level(absl::optional<uint8_t> value) { audio_level_ = value; } void set_receive_time(Timestamp value) { receive_time_ = value; }
const absl::optional<AbsoluteCaptureTime>& absolute_capture_time() const { std::optional<uint8_t> audio_level() const { return audio_level_; }
RtpPacketInfo& set_audio_level(std::optional<uint8_t> value) {
audio_level_ = value;
return *this;
}
const std::optional<AbsoluteCaptureTime>& absolute_capture_time() const {
return absolute_capture_time_; return absolute_capture_time_;
} }
void set_absolute_capture_time( RtpPacketInfo& set_absolute_capture_time(
const absl::optional<AbsoluteCaptureTime>& value) { const std::optional<AbsoluteCaptureTime>& value) {
absolute_capture_time_ = value; absolute_capture_time_ = value;
return *this;
} }
int64_t receive_time_ms() const { return receive_time_ms_; } const std::optional<TimeDelta>& local_capture_clock_offset() const {
void set_receive_time_ms(int64_t value) { receive_time_ms_ = value; } return local_capture_clock_offset_;
}
RtpPacketInfo& set_local_capture_clock_offset(
std::optional<TimeDelta> value) {
local_capture_clock_offset_ = value;
return *this;
}
private: private:
// Fields from the RTP header: // Fields from the RTP header:
@ -74,16 +87,23 @@ class RTC_EXPORT RtpPacketInfo {
std::vector<uint32_t> csrcs_; std::vector<uint32_t> csrcs_;
uint32_t rtp_timestamp_; uint32_t rtp_timestamp_;
// Local `webrtc::Clock`-based timestamp of when the packet was received.
Timestamp receive_time_;
// Fields from the Audio Level header extension: // Fields from the Audio Level header extension:
// https://tools.ietf.org/html/rfc6464#section-3 // https://tools.ietf.org/html/rfc6464#section-3
absl::optional<uint8_t> audio_level_; std::optional<uint8_t> audio_level_;
// Fields from the Absolute Capture Time header extension: // Fields from the Absolute Capture Time header extension:
// http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time // http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time
absl::optional<AbsoluteCaptureTime> absolute_capture_time_; std::optional<AbsoluteCaptureTime> absolute_capture_time_;
// Local |webrtc::Clock|-based timestamp of when the packet was received. // Clock offset between the local clock and the capturer's clock.
int64_t receive_time_ms_; // Do not confuse with `AbsoluteCaptureTime::estimated_capture_clock_offset`
// which instead represents the clock offset between a remote sender and the
// capturer. The following holds:
// Capture's NTP Clock = Local NTP Clock + Local-Capture Clock Offset
std::optional<TimeDelta> local_capture_clock_offset_;
}; };
bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs); bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs);

View File

@ -11,10 +11,10 @@
#ifndef API_RTP_PACKET_INFOS_H_ #ifndef API_RTP_PACKET_INFOS_H_
#define API_RTP_PACKET_INFOS_H_ #define API_RTP_PACKET_INFOS_H_
#include <cstdint>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "api/make_ref_counted.h"
#include "api/ref_counted_base.h" #include "api/ref_counted_base.h"
#include "api/rtp_packet_info.h" #include "api/rtp_packet_info.h"
#include "api/scoped_refptr.h" #include "api/scoped_refptr.h"
@ -26,8 +26,8 @@ namespace webrtc {
// an audio or video frame. Uses internal reference counting to make it very // an audio or video frame. Uses internal reference counting to make it very
// cheap to copy. // cheap to copy.
// //
// We should ideally just use |std::vector<RtpPacketInfo>| and have it // We should ideally just use `std::vector<RtpPacketInfo>` and have it
// |std::move()|-ed as the per-packet information is transferred from one object // `std::move()`-ed as the per-packet information is transferred from one object
// to another. But moving the info, instead of copying it, is not easily done // to another. But moving the info, instead of copying it, is not easily done
// for the current video code. // for the current video code.
class RTC_EXPORT RtpPacketInfos { class RTC_EXPORT RtpPacketInfos {
@ -79,7 +79,7 @@ class RTC_EXPORT RtpPacketInfos {
size_type size() const { return entries().size(); } size_type size() const { return entries().size(); }
private: private:
class Data : public rtc::RefCountedBase { class Data final : public rtc::RefCountedNonVirtual<Data> {
public: public:
static rtc::scoped_refptr<Data> Create(const vector_type& entries) { static rtc::scoped_refptr<Data> Create(const vector_type& entries) {
// Performance optimization for the empty case. // Performance optimization for the empty case.
@ -87,7 +87,7 @@ class RTC_EXPORT RtpPacketInfos {
return nullptr; return nullptr;
} }
return new Data(entries); return rtc::make_ref_counted<Data>(entries);
} }
static rtc::scoped_refptr<Data> Create(vector_type&& entries) { static rtc::scoped_refptr<Data> Create(vector_type&& entries) {
@ -96,16 +96,16 @@ class RTC_EXPORT RtpPacketInfos {
return nullptr; return nullptr;
} }
return new Data(std::move(entries)); return rtc::make_ref_counted<Data>(std::move(entries));
} }
const vector_type& entries() const { return entries_; } const vector_type& entries() const { return entries_; }
private:
explicit Data(const vector_type& entries) : entries_(entries) {} explicit Data(const vector_type& entries) : entries_(entries) {}
explicit Data(vector_type&& entries) : entries_(std::move(entries)) {} explicit Data(vector_type&& entries) : entries_(std::move(entries)) {}
~Data() override {} ~Data() = default;
private:
const vector_type entries_; const vector_type entries_;
}; };

View File

@ -22,15 +22,15 @@
// }; // };
// //
// void some_function() { // void some_function() {
// scoped_refptr<MyFoo> foo = new MyFoo(); // scoped_refptr<MyFoo> foo = make_ref_counted<MyFoo>();
// foo->Method(param); // foo->Method(param);
// // |foo| is released when this function returns // // `foo` is released when this function returns
// } // }
// //
// void some_other_function() { // void some_other_function() {
// scoped_refptr<MyFoo> foo = new MyFoo(); // scoped_refptr<MyFoo> foo = make_ref_counted<MyFoo>();
// ... // ...
// foo = nullptr; // explicitly releases |foo| // foo = nullptr; // explicitly releases `foo`
// ... // ...
// if (foo) // if (foo)
// foo->Method(param); // foo->Method(param);
@ -41,41 +41,45 @@
// references between the two objects, like so: // references between the two objects, like so:
// //
// { // {
// scoped_refptr<MyFoo> a = new MyFoo(); // scoped_refptr<MyFoo> a = make_ref_counted<MyFoo>();
// scoped_refptr<MyFoo> b; // scoped_refptr<MyFoo> b;
// //
// b.swap(a); // b.swap(a);
// // now, |b| references the MyFoo object, and |a| references null. // // now, `b` references the MyFoo object, and `a` references null.
// } // }
// //
// To make both |a| and |b| in the above example reference the same MyFoo // To make both `a` and `b` in the above example reference the same MyFoo
// object, simply use the assignment operator: // object, simply use the assignment operator:
// //
// { // {
// scoped_refptr<MyFoo> a = new MyFoo(); // scoped_refptr<MyFoo> a = make_ref_counted<MyFoo>();
// scoped_refptr<MyFoo> b; // scoped_refptr<MyFoo> b;
// //
// b = a; // b = a;
// // now, |a| and |b| each own a reference to the same MyFoo object. // // now, `a` and `b` each own a reference to the same MyFoo object.
// } // }
// //
#ifndef API_SCOPED_REFPTR_H_ #ifndef API_SCOPED_REFPTR_H_
#define API_SCOPED_REFPTR_H_ #define API_SCOPED_REFPTR_H_
#include <memory> #include <cstddef>
#include <utility> #include <utility>
namespace rtc { #include "absl/base/nullability.h"
namespace webrtc {
template <class T> template <class T>
class scoped_refptr { class ABSL_NULLABILITY_COMPATIBLE scoped_refptr {
public: public:
typedef T element_type; using absl_nullability_compatible = void;
using element_type = T;
scoped_refptr() : ptr_(nullptr) {} scoped_refptr() : ptr_(nullptr) {}
scoped_refptr(std::nullptr_t) : ptr_(nullptr) {} // NOLINT(runtime/explicit)
scoped_refptr(T* p) : ptr_(p) { // NOLINT(runtime/explicit) explicit scoped_refptr(absl::Nullable<T*> p) : ptr_(p) {
if (ptr_) if (ptr_)
ptr_->AddRef(); ptr_->AddRef();
} }
@ -103,7 +107,8 @@ class scoped_refptr {
} }
T* get() const { return ptr_; } T* get() const { return ptr_; }
operator T*() const { return ptr_; } explicit operator bool() const { return ptr_ != nullptr; }
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; } T* operator->() const { return ptr_; }
// Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a // Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a
@ -117,7 +122,7 @@ class scoped_refptr {
return retVal; return retVal;
} }
scoped_refptr<T>& operator=(T* p) { scoped_refptr<T>& operator=(absl::Nullable<T*> p) {
// AddRef first so that self assignment should work // AddRef first so that self assignment should work
if (p) if (p)
p->AddRef(); p->AddRef();
@ -147,7 +152,7 @@ class scoped_refptr {
return *this; return *this;
} }
void swap(T** pp) noexcept { void swap(absl::Nonnull<T**> pp) noexcept {
T* p = ptr_; T* p = ptr_;
ptr_ = *pp; ptr_ = *pp;
*pp = p; *pp = p;
@ -159,6 +164,66 @@ class scoped_refptr {
T* ptr_; T* ptr_;
}; };
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
return a.get() == b.get();
}
template <typename T, typename U>
bool operator!=(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
return !(a == b);
}
template <typename T>
bool operator==(const scoped_refptr<T>& a, std::nullptr_t) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(const scoped_refptr<T>& a, std::nullptr_t) {
return !(a == nullptr);
}
template <typename T>
bool operator==(std::nullptr_t, const scoped_refptr<T>& a) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(std::nullptr_t, const scoped_refptr<T>& a) {
return !(a == nullptr);
}
// Comparison with raw pointer.
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& a, const U* b) {
return a.get() == b;
}
template <typename T, typename U>
bool operator!=(const scoped_refptr<T>& a, const U* b) {
return !(a == b);
}
template <typename T, typename U>
bool operator==(const T* a, const scoped_refptr<U>& b) {
return a == b.get();
}
template <typename T, typename U>
bool operator!=(const T* a, const scoped_refptr<U>& b) {
return !(a == b);
}
// Ordered comparison, needed for use as a std::map key.
template <typename T, typename U>
bool operator<(const scoped_refptr<T>& a, const scoped_refptr<U>& b) {
return a.get() < b.get();
}
} // namespace webrtc
namespace rtc {
// Backwards compatible alias.
// TODO: bugs.webrtc.org/42225969 - Deprecate and remove.
using ::webrtc::scoped_refptr;
} // namespace rtc } // namespace rtc
#endif // API_SCOPED_REFPTR_H_ #endif // API_SCOPED_REFPTR_H_

View File

@ -0,0 +1,141 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_SEQUENCE_CHECKER_H_
#define API_SEQUENCE_CHECKER_H_
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/sequence_checker_internal.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// SequenceChecker is a helper class used to help verify that some methods
// of a class are called on the same task queue or thread. A
// SequenceChecker is bound to a a task queue if the object is
// created on a task queue, or a thread otherwise.
//
//
// Example:
// class MyClass {
// public:
// void Foo() {
// RTC_DCHECK_RUN_ON(&sequence_checker_);
// ... (do stuff) ...
// }
//
// private:
// SequenceChecker sequence_checker_;
// }
//
// In Release mode, IsCurrent will always return true.
class RTC_LOCKABLE SequenceChecker
#if RTC_DCHECK_IS_ON
: public webrtc_sequence_checker_internal::SequenceCheckerImpl {
using Impl = webrtc_sequence_checker_internal::SequenceCheckerImpl;
#else
: public webrtc_sequence_checker_internal::SequenceCheckerDoNothing {
using Impl = webrtc_sequence_checker_internal::SequenceCheckerDoNothing;
#endif
public:
enum InitialState : bool { kDetached = false, kAttached = true };
// TODO(tommi): We could maybe join these two ctors and have fewer factory
// functions. At the moment they're separate to minimize code changes when
// we added the second ctor as well as avoiding to have unnecessary code at
// the SequenceChecker which much only run for the SequenceCheckerImpl
// implementation.
// In theory we could have something like:
//
// SequenceChecker(InitialState initial_state = kAttached,
// TaskQueueBase* attached_queue = TaskQueueBase::Current());
//
// But the problem with that is having the call to `Current()` exist for
// `SequenceCheckerDoNothing`.
explicit SequenceChecker(InitialState initial_state = kAttached)
: Impl(initial_state) {}
explicit SequenceChecker(TaskQueueBase* attached_queue)
: Impl(attached_queue) {}
// Returns true if sequence checker is attached to the current sequence.
bool IsCurrent() const { return Impl::IsCurrent(); }
// Detaches checker from sequence to which it is attached. Next attempt
// to do a check with this checker will result in attaching this checker
// to the sequence on which check was performed.
void Detach() { Impl::Detach(); }
};
} // namespace webrtc
// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
// variables are accessed from same thread/task queue.
// Using tools designed to check mutexes, it checks at compile time everywhere
// variable is access, there is a run-time dcheck thread/task queue is correct.
//
// class SequenceCheckerExample {
// public:
// int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) {
// return var2_;
// }
//
// void CallMeFromPacer() {
// RTC_DCHECK_RUN_ON(&pacer_sequence_checker_)
// << "Should be called from pacer";
// CalledFromPacer();
// }
//
// private:
// int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_);
// SequenceChecker pacer_sequence_checker_;
// };
//
// class TaskQueueExample {
// public:
// class Encoder {
// public:
// rtc::TaskQueueBase& Queue() { return encoder_queue_; }
// void Encode() {
// RTC_DCHECK_RUN_ON(&encoder_queue_);
// DoSomething(var_);
// }
//
// private:
// rtc::TaskQueueBase& encoder_queue_;
// Frame var_ RTC_GUARDED_BY(encoder_queue_);
// };
//
// void Encode() {
// // Will fail at runtime when DCHECK is enabled:
// // encoder_->Encode();
// // Will work:
// rtc::scoped_refptr<Encoder> encoder = encoder_;
// encoder_->Queue().PostTask([encoder] { encoder->Encode(); });
// }
//
// private:
// rtc::scoped_refptr<Encoder> encoder_;
// }
// Document if a function expected to be called from same thread/task queue.
#define RTC_RUN_ON(x) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
// Checks current code is running on the desired sequence.
//
// First statement validates it is running on the sequence `x`.
// Second statement annotates for the thread safety analyzer the check was done.
// Such annotation has to be attached to a function, and that function has to be
// called. Thus current implementation creates a noop lambda and calls it.
#define RTC_DCHECK_RUN_ON(x) \
RTC_DCHECK((x)->IsCurrent()) \
<< webrtc::webrtc_sequence_checker_internal::ExpectationToString(x); \
[]() RTC_ASSERT_EXCLUSIVE_LOCK(x) {}()
#endif // API_SEQUENCE_CHECKER_H_

View File

@ -1,32 +0,0 @@
/*
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_TASK_QUEUE_QUEUED_TASK_H_
#define API_TASK_QUEUE_QUEUED_TASK_H_
namespace webrtc {
// Base interface for asynchronously executed tasks.
// The interface basically consists of a single function, Run(), that executes
// on the target queue. For more details see the Run() method and TaskQueue.
class QueuedTask {
public:
virtual ~QueuedTask() = default;
// Main routine that will run when the task is executed on the desired queue.
// The task should return |true| to indicate that it should be deleted or
// |false| to indicate that the queue should consider ownership of the task
// having been transferred. Returning |false| can be useful if a task has
// re-posted itself to a different queue or is otherwise being re-used.
virtual bool Run() = 0;
};
} // namespace webrtc
#endif // API_TASK_QUEUE_QUEUED_TASK_H_

View File

@ -11,7 +11,6 @@
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/config.h" #include "absl/base/config.h"
#include "rtc_base/checks.h"
#if defined(ABSL_HAVE_THREAD_LOCAL) #if defined(ABSL_HAVE_THREAD_LOCAL)

View File

@ -10,9 +10,11 @@
#ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_ #ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_ #define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#include <memory> #include <utility>
#include "api/task_queue/queued_task.h" #include "absl/functional/any_invocable.h"
#include "api/location.h"
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h" #include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h" #include "rtc_base/thread_annotations.h"
@ -24,41 +26,139 @@ namespace webrtc {
// known task queue, use IsCurrent(). // known task queue, use IsCurrent().
class RTC_LOCKABLE RTC_EXPORT TaskQueueBase { class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
public: public:
enum class DelayPrecision {
// This may include up to a 17 ms leeway in addition to OS timer precision.
// See PostDelayedTask() for more information.
kLow,
// This does not have the additional delay that kLow has, but it is still
// limited by OS timer precision. See PostDelayedHighPrecisionTask() for
// more information.
kHigh,
};
// Starts destruction of the task queue. // Starts destruction of the task queue.
// On return ensures no task are running and no new tasks are able to start // On return ensures no task are running and no new tasks are able to start
// on the task queue. // on the task queue.
// Responsible for deallocation. Deallocation may happen syncrhoniously during // Responsible for deallocation. Deallocation may happen synchronously during
// Delete or asynchronously after Delete returns. // Delete or asynchronously after Delete returns.
// Code not running on the TaskQueue should not make any assumption when // Code not running on the TaskQueue should not make any assumption when
// TaskQueue is deallocated and thus should not call any methods after Delete. // TaskQueue is deallocated and thus should not call any methods after Delete.
// Code running on the TaskQueue should not call Delete, but can assume // Code running on the TaskQueue should not call Delete, but can assume
// TaskQueue still exists and may call other methods, e.g. PostTask. // TaskQueue still exists and may call other methods, e.g. PostTask.
// Should be called on the same task queue or thread that this task queue
// was created on.
virtual void Delete() = 0; virtual void Delete() = 0;
// Schedules a task to execute. Tasks are executed in FIFO order. // Schedules a `task` to execute. Tasks are executed in FIFO order.
// If |task->Run()| returns true, task is deleted on the task queue
// before next QueuedTask starts executing.
// When a TaskQueue is deleted, pending tasks will not be executed but they // When a TaskQueue is deleted, pending tasks will not be executed but they
// will be deleted. The deletion of tasks may happen synchronously on the // will be deleted.
// TaskQueue or it may happen asynchronously after TaskQueue is deleted. //
// This may vary from one implementation to the next so assumptions about // As long as tasks are not posted from task destruction, posted tasks are
// lifetimes of pending tasks should not be made. // guaranteed to be destroyed with Current() pointing to the task queue they
virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0; // were posted to, whether they're executed or not. That means SequenceChecker
// works during task destruction, a fact that can be used to guarantee
// thread-compatible object deletion happening on a particular task queue
// which can simplify class design.
// Note that this guarantee does not apply to delayed tasks.
//
// May be called on any thread or task queue, including this task queue.
void PostTask(absl::AnyInvocable<void() &&> task,
const Location& location = Location::Current()) {
PostTaskImpl(std::move(task), PostTaskTraits{}, location);
}
// Schedules a task to execute a specified number of milliseconds from when // Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// the call is made. The precision should be considered as "best effort" // possible.
// and in some cases, such as on Windows when all high precision timers have //
// been used up, can be off by as much as 15 millseconds. // Schedules a `task` to execute a specified `delay` from when the call is
virtual void PostDelayedTask(std::unique_ptr<QueuedTask> task, // made, using "low" precision. All scheduling is affected by OS-specific
uint32_t milliseconds) = 0; // leeway and current workloads which means that in terms of precision there
// are no hard guarantees, but in addition to the OS induced leeway, "low"
// precision adds up to a 17 ms additional leeway. The purpose of this leeway
// is to achieve more efficient CPU scheduling and reduce Idle Wake Up
// frequency.
//
// The task may execute with [-1, 17 + OS induced leeway) ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// "Low" precision is not implemented everywhere yet. Where not yet
// implemented, PostDelayedTask() has "high" precision. See
// https://crbug.com/webrtc/13583 for more information.
//
// May be called on any thread or task queue, including this task queue.
void PostDelayedTask(absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
PostDelayedTaskImpl(std::move(task), delay, PostDelayedTaskTraits{},
location);
}
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a `task` to execute a specified `delay` from when the call is
// made, using "high" precision. All scheduling is affected by OS-specific
// leeway and current workloads which means that in terms of precision there
// are no hard guarantees.
//
// The task may execute with [-1, OS induced leeway] ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// May be called on any thread or task queue, including this task queue.
void PostDelayedHighPrecisionTask(
absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
PostDelayedTaskTraits traits;
traits.high_precision = true;
PostDelayedTaskImpl(std::move(task), delay, traits, location);
}
// As specified by `precision`, calls either PostDelayedTask() or
// PostDelayedHighPrecisionTask().
void PostDelayedTaskWithPrecision(
DelayPrecision precision,
absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
switch (precision) {
case DelayPrecision::kLow:
PostDelayedTask(std::move(task), delay, location);
break;
case DelayPrecision::kHigh:
PostDelayedHighPrecisionTask(std::move(task), delay, location);
break;
}
}
// Returns the task queue that is running the current thread. // Returns the task queue that is running the current thread.
// Returns nullptr if this thread is not associated with any task queue. // Returns nullptr if this thread is not associated with any task queue.
// May be called on any thread or task queue, including this task queue.
static TaskQueueBase* Current(); static TaskQueueBase* Current();
bool IsCurrent() const { return Current() == this; } bool IsCurrent() const { return Current() == this; }
protected: protected:
class CurrentTaskQueueSetter { // This is currently only present here to simplify introduction of future
// planned task queue changes.
struct PostTaskTraits {};
struct PostDelayedTaskTraits {
// If `high_precision` is false, tasks may execute within up to a 17 ms
// leeway in addition to OS timer precision. Otherwise the task should be
// limited to OS timer precision. See PostDelayedTask() and
// PostDelayedHighPrecisionTask() for more information.
bool high_precision = false;
};
class RTC_EXPORT CurrentTaskQueueSetter {
public: public:
explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue); explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete; CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
@ -69,6 +169,20 @@ class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
TaskQueueBase* const previous_; TaskQueueBase* const previous_;
}; };
// Subclasses should implement this method to support the behavior defined in
// the PostTask and PostTaskTraits docs above.
virtual void PostTaskImpl(absl::AnyInvocable<void() &&> task,
const PostTaskTraits& traits,
const Location& location) = 0;
// Subclasses should implement this method to support the behavior defined in
// the PostDelayedTask/PostHighPrecisionDelayedTask and PostDelayedTaskTraits
// docs above.
virtual void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const PostDelayedTaskTraits& traits,
const Location& location) = 0;
// Users of the TaskQueue should call Delete instead of directly deleting // Users of the TaskQueue should call Delete instead of directly deleting
// this object. // this object.
virtual ~TaskQueueBase() = default; virtual ~TaskQueueBase() = default;

View File

@ -1,34 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/units/data_rate.h"
#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
std::string ToString(DataRate value) {
char buf[64];
rtc::SimpleStringBuilder sb(buf);
if (value.IsPlusInfinity()) {
sb << "+inf bps";
} else if (value.IsMinusInfinity()) {
sb << "-inf bps";
} else {
if (value.bps() == 0 || value.bps() % 1000 != 0) {
sb << value.bps() << " bps";
} else {
sb << value.kbps() << " kbps";
}
}
return sb.str();
}
} // namespace webrtc

View File

@ -1,155 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_DATA_RATE_H_
#define API_UNITS_DATA_RATE_H_
#ifdef UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#include <limits>
#include <string>
#include <type_traits>
#include "api/units/data_size.h"
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "rtc_base/checks.h"
#include "rtc_base/units/unit_base.h"
namespace webrtc {
// DataRate is a class that represents a given data rate. This can be used to
// represent bandwidth, encoding bitrate, etc. The internal storage is bits per
// second (bps).
class DataRate final : public rtc_units_impl::RelativeUnit<DataRate> {
public:
template <typename T>
static constexpr DataRate BitsPerSec(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
template <typename T>
static constexpr DataRate BytesPerSec(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(8, value);
}
template <typename T>
static constexpr DataRate KilobitsPerSec(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromFraction(1000, value);
}
static constexpr DataRate Infinity() { return PlusInfinity(); }
DataRate() = delete;
template <typename T = int64_t>
constexpr T bps() const {
return ToValue<T>();
}
template <typename T = int64_t>
constexpr T bytes_per_sec() const {
return ToFraction<8, T>();
}
template <typename T = int64_t>
constexpr T kbps() const {
return ToFraction<1000, T>();
}
constexpr int64_t bps_or(int64_t fallback_value) const {
return ToValueOr(fallback_value);
}
constexpr int64_t kbps_or(int64_t fallback_value) const {
return ToFractionOr<1000>(fallback_value);
}
private:
// Bits per second used internally to simplify debugging by making the value
// more recognizable.
friend class rtc_units_impl::UnitBase<DataRate>;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = true;
};
namespace data_rate_impl {
inline constexpr int64_t Microbits(const DataSize& size) {
constexpr int64_t kMaxBeforeConversion =
std::numeric_limits<int64_t>::max() / 8000000;
RTC_DCHECK_LE(size.bytes(), kMaxBeforeConversion)
<< "size is too large to be expressed in microbits";
return size.bytes() * 8000000;
}
inline constexpr int64_t MillibytePerSec(const DataRate& size) {
constexpr int64_t kMaxBeforeConversion =
std::numeric_limits<int64_t>::max() / (1000 / 8);
RTC_DCHECK_LE(size.bps(), kMaxBeforeConversion)
<< "rate is too large to be expressed in microbytes per second";
return size.bps() * (1000 / 8);
}
} // namespace data_rate_impl
inline constexpr DataRate operator/(const DataSize size,
const TimeDelta duration) {
return DataRate::BitsPerSec(data_rate_impl::Microbits(size) / duration.us());
}
inline constexpr TimeDelta operator/(const DataSize size, const DataRate rate) {
return TimeDelta::Micros(data_rate_impl::Microbits(size) / rate.bps());
}
inline constexpr DataSize operator*(const DataRate rate,
const TimeDelta duration) {
int64_t microbits = rate.bps() * duration.us();
return DataSize::Bytes((microbits + 4000000) / 8000000);
}
inline constexpr DataSize operator*(const TimeDelta duration,
const DataRate rate) {
return rate * duration;
}
inline constexpr DataSize operator/(const DataRate rate,
const Frequency frequency) {
int64_t millihertz = frequency.millihertz<int64_t>();
// Note that the value is truncated here reather than rounded, potentially
// introducing an error of .5 bytes if rounding were expected.
return DataSize::Bytes(data_rate_impl::MillibytePerSec(rate) / millihertz);
}
inline constexpr Frequency operator/(const DataRate rate, const DataSize size) {
return Frequency::MilliHertz(data_rate_impl::MillibytePerSec(rate) /
size.bytes());
}
inline constexpr DataRate operator*(const DataSize size,
const Frequency frequency) {
RTC_DCHECK(frequency.IsZero() ||
size.bytes() <= std::numeric_limits<int64_t>::max() / 8 /
frequency.millihertz<int64_t>());
int64_t millibits_per_second =
size.bytes() * 8 * frequency.millihertz<int64_t>();
return DataRate::BitsPerSec((millibits_per_second + 500) / 1000);
}
inline constexpr DataRate operator*(const Frequency frequency,
const DataSize size) {
return size * frequency;
}
std::string ToString(DataRate value);
inline std::string ToLogString(DataRate value) {
return ToString(value);
}
#ifdef UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
DataRate value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
} // namespace webrtc
#endif // API_UNITS_DATA_RATE_H_

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/units/data_size.h"
#include "api/array_view.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
std::string ToString(DataSize value) {
char buf[64];
rtc::SimpleStringBuilder sb(buf);
if (value.IsPlusInfinity()) {
sb << "+inf bytes";
} else if (value.IsMinusInfinity()) {
sb << "-inf bytes";
} else {
sb << value.bytes() << " bytes";
}
return sb.str();
}
} // namespace webrtc

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_UNITS_DATA_SIZE_H_
#define API_UNITS_DATA_SIZE_H_
#ifdef UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#include <string>
#include <type_traits>
#include "rtc_base/units/unit_base.h"
namespace webrtc {
// DataSize is a class represeting a count of bytes.
class DataSize final : public rtc_units_impl::RelativeUnit<DataSize> {
public:
template <typename T>
static constexpr DataSize Bytes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
static constexpr DataSize Infinity() { return PlusInfinity(); }
DataSize() = delete;
template <typename T = int64_t>
constexpr T bytes() const {
return ToValue<T>();
}
constexpr int64_t bytes_or(int64_t fallback_value) const {
return ToValueOr(fallback_value);
}
private:
friend class rtc_units_impl::UnitBase<DataSize>;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = true;
};
std::string ToString(DataSize value);
inline std::string ToLogString(DataSize value) {
return ToString(value);
}
#ifdef UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
DataSize value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
} // namespace webrtc
#endif // API_UNITS_DATA_SIZE_H_

View File

@ -9,6 +9,9 @@
*/ */
#include "api/units/frequency.h" #include "api/units/frequency.h"
#include <cstdint>
#include <string>
#include "rtc_base/strings/string_builder.h" #include "rtc_base/strings/string_builder.h"
namespace webrtc { namespace webrtc {

View File

@ -10,17 +10,16 @@
#ifndef API_UNITS_FREQUENCY_H_ #ifndef API_UNITS_FREQUENCY_H_
#define API_UNITS_FREQUENCY_H_ #define API_UNITS_FREQUENCY_H_
#ifdef UNIT_TEST #include <cstdint>
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#include <cstdlib> #include <cstdlib>
#include <limits> #include <limits>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "rtc_base/units/unit_base.h" #include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc { namespace webrtc {
@ -44,6 +43,9 @@ class Frequency final : public rtc_units_impl::RelativeUnit<Frequency> {
Frequency() = delete; Frequency() = delete;
template <typename Sink>
friend void AbslStringify(Sink& sink, Frequency value);
template <typename T = int64_t> template <typename T = int64_t>
constexpr T hertz() const { constexpr T hertz() const {
return ToFraction<1000, T>(); return ToFraction<1000, T>();
@ -84,18 +86,15 @@ inline constexpr double operator*(TimeDelta time_delta, Frequency frequency) {
return frequency * time_delta; return frequency * time_delta;
} }
std::string ToString(Frequency value); RTC_EXPORT std::string ToString(Frequency value);
inline std::string ToLogString(Frequency value) { inline std::string ToLogString(Frequency value) {
return ToString(value); return ToString(value);
} }
#ifdef UNIT_TEST template <typename Sink>
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) void AbslStringify(Sink& sink, Frequency value) {
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) sink.Append(ToString(value));
Frequency value) {
return stream << ToString(value);
} }
#endif // UNIT_TEST
} // namespace webrtc } // namespace webrtc
#endif // API_UNITS_FREQUENCY_H_ #endif // API_UNITS_FREQUENCY_H_

View File

@ -10,6 +10,8 @@
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include <string>
#include "api/array_view.h" #include "api/array_view.h"
#include "rtc_base/strings/string_builder.h" #include "rtc_base/strings/string_builder.h"

View File

@ -11,15 +11,13 @@
#ifndef API_UNITS_TIME_DELTA_H_ #ifndef API_UNITS_TIME_DELTA_H_
#define API_UNITS_TIME_DELTA_H_ #define API_UNITS_TIME_DELTA_H_
#ifdef UNIT_TEST #include <cstdint>
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "rtc_base/units/unit_base.h" #include "rtc_base/system/rtc_export.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc { namespace webrtc {
@ -32,6 +30,11 @@ namespace webrtc {
// microseconds (us). // microseconds (us).
class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> { class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
public: public:
template <typename T>
static constexpr TimeDelta Minutes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return Seconds(value * 60);
}
template <typename T> template <typename T>
static constexpr TimeDelta Seconds(T value) { static constexpr TimeDelta Seconds(T value) {
static_assert(std::is_arithmetic<T>::value, ""); static_assert(std::is_arithmetic<T>::value, "");
@ -50,6 +53,9 @@ class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
TimeDelta() = delete; TimeDelta() = delete;
template <typename Sink>
friend void AbslStringify(Sink& sink, TimeDelta value);
template <typename T = int64_t> template <typename T = int64_t>
constexpr T seconds() const { constexpr T seconds() const {
return ToFraction<1000000, T>(); return ToFraction<1000000, T>();
@ -87,18 +93,15 @@ class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
static constexpr bool one_sided = false; static constexpr bool one_sided = false;
}; };
std::string ToString(TimeDelta value); RTC_EXPORT std::string ToString(TimeDelta value);
inline std::string ToLogString(TimeDelta value) { inline std::string ToLogString(TimeDelta value) {
return ToString(value); return ToString(value);
} }
#ifdef UNIT_TEST template <typename Sink>
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) void AbslStringify(Sink& sink, TimeDelta value) {
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) sink.Append(ToString(value));
TimeDelta value) {
return stream << ToString(value);
} }
#endif // UNIT_TEST
} // namespace webrtc } // namespace webrtc

View File

@ -10,6 +10,8 @@
#include "api/units/timestamp.h" #include "api/units/timestamp.h"
#include <string>
#include "api/array_view.h" #include "api/array_view.h"
#include "rtc_base/strings/string_builder.h" #include "rtc_base/strings/string_builder.h"

View File

@ -11,15 +11,14 @@
#ifndef API_UNITS_TIMESTAMP_H_ #ifndef API_UNITS_TIMESTAMP_H_
#define API_UNITS_TIMESTAMP_H_ #define API_UNITS_TIMESTAMP_H_
#ifdef UNIT_TEST #include <cstdint>
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc { namespace webrtc {
// Timestamp represents the time that has passed since some unspecified epoch. // Timestamp represents the time that has passed since some unspecified epoch.
@ -46,6 +45,9 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
Timestamp() = delete; Timestamp() = delete;
template <typename Sink>
friend void AbslStringify(Sink& sink, Timestamp value);
template <typename T = int64_t> template <typename T = int64_t>
constexpr T seconds() const { constexpr T seconds() const {
return ToFraction<1000000, T>(); return ToFraction<1000000, T>();
@ -120,18 +122,15 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
static constexpr bool one_sided = true; static constexpr bool one_sided = true;
}; };
std::string ToString(Timestamp value); RTC_EXPORT std::string ToString(Timestamp value);
inline std::string ToLogString(Timestamp value) { inline std::string ToLogString(Timestamp value) {
return ToString(value); return ToString(value);
} }
#ifdef UNIT_TEST template <typename Sink>
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) void AbslStringify(Sink& sink, Timestamp value) {
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) sink.Append(ToString(value));
Timestamp value) {
return stream << ToString(value);
} }
#endif // UNIT_TEST
} // namespace webrtc } // namespace webrtc

View File

@ -10,9 +10,17 @@
#include "api/video/color_space.h" #include "api/video/color_space.h"
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include "api/video/hdr_metadata.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc { namespace webrtc {
namespace { namespace {
// Try to convert |enum_value| into the enum class T. |enum_bitmask| is created // Try to convert `enum_value` into the enum class T. `enum_bitmask` is created
// by the funciton below. Returns true if conversion was successful, false // by the funciton below. Returns true if conversion was successful, false
// otherwise. // otherwise.
template <typename T> template <typename T>
@ -43,7 +51,7 @@ constexpr int MakeMask(const int index, const int length, T (&values)[N]) {
} }
// Create a bitmask where each bit corresponds to one potential enum value. // Create a bitmask where each bit corresponds to one potential enum value.
// |values| should be an array listing all possible enum values. The bit is set // `values` should be an array listing all possible enum values. The bit is set
// to one if the corresponding enum exists. Only works for enums with values // to one if the corresponding enum exists. Only works for enums with values
// less than 64. // less than 64.
template <typename T, size_t N> template <typename T, size_t N>
@ -93,8 +101,8 @@ ColorSpace::ColorSpace(PrimaryID primaries,
range_(range), range_(range),
chroma_siting_horizontal_(chroma_siting_horz), chroma_siting_horizontal_(chroma_siting_horz),
chroma_siting_vertical_(chroma_siting_vert), chroma_siting_vertical_(chroma_siting_vert),
hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata) hdr_metadata_(hdr_metadata ? std::make_optional(*hdr_metadata)
: absl::nullopt) {} : std::nullopt) {}
ColorSpace::PrimaryID ColorSpace::primaries() const { ColorSpace::PrimaryID ColorSpace::primaries() const {
return primaries_; return primaries_;
@ -124,6 +132,80 @@ const HdrMetadata* ColorSpace::hdr_metadata() const {
return hdr_metadata_ ? &*hdr_metadata_ : nullptr; return hdr_metadata_ ? &*hdr_metadata_ : nullptr;
} }
#define PRINT_ENUM_CASE(TYPE, NAME) \
case TYPE::NAME: \
ss << #NAME; \
break;
std::string ColorSpace::AsString() const {
char buf[1024];
rtc::SimpleStringBuilder ss(buf);
ss << "{primaries:";
switch (primaries_) {
PRINT_ENUM_CASE(PrimaryID, kBT709)
PRINT_ENUM_CASE(PrimaryID, kUnspecified)
PRINT_ENUM_CASE(PrimaryID, kBT470M)
PRINT_ENUM_CASE(PrimaryID, kBT470BG)
PRINT_ENUM_CASE(PrimaryID, kSMPTE170M)
PRINT_ENUM_CASE(PrimaryID, kSMPTE240M)
PRINT_ENUM_CASE(PrimaryID, kFILM)
PRINT_ENUM_CASE(PrimaryID, kBT2020)
PRINT_ENUM_CASE(PrimaryID, kSMPTEST428)
PRINT_ENUM_CASE(PrimaryID, kSMPTEST431)
PRINT_ENUM_CASE(PrimaryID, kSMPTEST432)
PRINT_ENUM_CASE(PrimaryID, kJEDECP22)
}
ss << ", transfer:";
switch (transfer_) {
PRINT_ENUM_CASE(TransferID, kBT709)
PRINT_ENUM_CASE(TransferID, kUnspecified)
PRINT_ENUM_CASE(TransferID, kGAMMA22)
PRINT_ENUM_CASE(TransferID, kGAMMA28)
PRINT_ENUM_CASE(TransferID, kSMPTE170M)
PRINT_ENUM_CASE(TransferID, kSMPTE240M)
PRINT_ENUM_CASE(TransferID, kLINEAR)
PRINT_ENUM_CASE(TransferID, kLOG)
PRINT_ENUM_CASE(TransferID, kLOG_SQRT)
PRINT_ENUM_CASE(TransferID, kIEC61966_2_4)
PRINT_ENUM_CASE(TransferID, kBT1361_ECG)
PRINT_ENUM_CASE(TransferID, kIEC61966_2_1)
PRINT_ENUM_CASE(TransferID, kBT2020_10)
PRINT_ENUM_CASE(TransferID, kBT2020_12)
PRINT_ENUM_CASE(TransferID, kSMPTEST2084)
PRINT_ENUM_CASE(TransferID, kSMPTEST428)
PRINT_ENUM_CASE(TransferID, kARIB_STD_B67)
}
ss << ", matrix:";
switch (matrix_) {
PRINT_ENUM_CASE(MatrixID, kRGB)
PRINT_ENUM_CASE(MatrixID, kBT709)
PRINT_ENUM_CASE(MatrixID, kUnspecified)
PRINT_ENUM_CASE(MatrixID, kFCC)
PRINT_ENUM_CASE(MatrixID, kBT470BG)
PRINT_ENUM_CASE(MatrixID, kSMPTE170M)
PRINT_ENUM_CASE(MatrixID, kSMPTE240M)
PRINT_ENUM_CASE(MatrixID, kYCOCG)
PRINT_ENUM_CASE(MatrixID, kBT2020_NCL)
PRINT_ENUM_CASE(MatrixID, kBT2020_CL)
PRINT_ENUM_CASE(MatrixID, kSMPTE2085)
PRINT_ENUM_CASE(MatrixID, kCDNCLS)
PRINT_ENUM_CASE(MatrixID, kCDCLS)
PRINT_ENUM_CASE(MatrixID, kBT2100_ICTCP)
}
ss << ", range:";
switch (range_) {
PRINT_ENUM_CASE(RangeID, kInvalid)
PRINT_ENUM_CASE(RangeID, kLimited)
PRINT_ENUM_CASE(RangeID, kFull)
PRINT_ENUM_CASE(RangeID, kDerived)
}
ss << "}";
return ss.str();
}
#undef PRINT_ENUM_CASE
bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) { bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
constexpr PrimaryID kPrimaryIds[] = { constexpr PrimaryID kPrimaryIds[] = {
PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M, PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M,
@ -181,7 +263,7 @@ bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) {
void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) { void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) {
hdr_metadata_ = hdr_metadata_ =
hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt; hdr_metadata ? std::make_optional(*hdr_metadata) : std::nullopt;
} }
} // namespace webrtc } // namespace webrtc

View File

@ -13,7 +13,9 @@
#include <stdint.h> #include <stdint.h>
#include "absl/types/optional.h" #include <optional>
#include <string>
#include "api/video/hdr_metadata.h" #include "api/video/hdr_metadata.h"
#include "rtc_base/system/rtc_export.h" #include "rtc_base/system/rtc_export.h"
@ -101,7 +103,7 @@ class RTC_EXPORT ColorSpace {
kInvalid = 0, kInvalid = 0,
// Limited Rec. 709 color range with RGB values ranging from 16 to 235. // Limited Rec. 709 color range with RGB values ranging from 16 to 235.
kLimited = 1, kLimited = 1,
// Full RGB color range with RGB valees from 0 to 255. // Full RGB color range with RGB values from 0 to 255.
kFull = 2, kFull = 2,
// Range is defined by MatrixCoefficients/TransferCharacteristics. // Range is defined by MatrixCoefficients/TransferCharacteristics.
kDerived = 3, kDerived = 3,
@ -155,6 +157,7 @@ class RTC_EXPORT ColorSpace {
ChromaSiting chroma_siting_horizontal() const; ChromaSiting chroma_siting_horizontal() const;
ChromaSiting chroma_siting_vertical() const; ChromaSiting chroma_siting_vertical() const;
const HdrMetadata* hdr_metadata() const; const HdrMetadata* hdr_metadata() const;
std::string AsString() const;
bool set_primaries_from_uint8(uint8_t enum_value); bool set_primaries_from_uint8(uint8_t enum_value);
bool set_transfer_from_uint8(uint8_t enum_value); bool set_transfer_from_uint8(uint8_t enum_value);
@ -171,7 +174,7 @@ class RTC_EXPORT ColorSpace {
RangeID range_ = RangeID::kInvalid; RangeID range_ = RangeID::kInvalid;
ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified; ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified;
ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified; ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified;
absl::optional<HdrMetadata> hdr_metadata_; std::optional<HdrMetadata> hdr_metadata_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -10,21 +10,9 @@
#include "api/video/video_content_type.h" #include "api/video/video_content_type.h"
// VideoContentType stored as a single byte, which is sent over the network. #include <cstdint>
// Structure:
// #include "rtc_base/checks.h"
// 0 1 2 3 4 5 6 7
// +---------------+
// |r r e e e s s c|
//
// where:
// r - reserved bits.
// e - 3-bit number of an experiment group counted from 1. 0 means there's no
// experiment ongoing.
// s - 2-bit simulcast stream id or spatial layer, counted from 1. 0 means that
// no simulcast information is set.
// c - content type. 0 means real-time video, 1 means screenshare.
//
namespace webrtc { namespace webrtc {
namespace videocontenttypehelpers { namespace videocontenttypehelpers {
@ -33,57 +21,21 @@ namespace {
static constexpr uint8_t kScreenshareBitsSize = 1; static constexpr uint8_t kScreenshareBitsSize = 1;
static constexpr uint8_t kScreenshareBitsMask = static constexpr uint8_t kScreenshareBitsMask =
(1u << kScreenshareBitsSize) - 1; (1u << kScreenshareBitsSize) - 1;
static constexpr uint8_t kSimulcastShift = 1;
static constexpr uint8_t kSimulcastBitsSize = 2;
static constexpr uint8_t kSimulcastBitsMask = ((1u << kSimulcastBitsSize) - 1)
<< kSimulcastShift; // 0b00000110
static constexpr uint8_t kExperimentShift = 3;
static constexpr uint8_t kExperimentBitsSize = 3;
static constexpr uint8_t kExperimentBitsMask =
((1u << kExperimentBitsSize) - 1) << kExperimentShift; // 0b00111000
static constexpr uint8_t kTotalBitsSize =
kScreenshareBitsSize + kSimulcastBitsSize + kExperimentBitsSize;
} // namespace } // namespace
bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id) {
// Store in bits 2-4.
if (experiment_id >= (1 << kExperimentBitsSize))
return false;
*content_type = static_cast<VideoContentType>(
(static_cast<uint8_t>(*content_type) & ~kExperimentBitsMask) |
((experiment_id << kExperimentShift) & kExperimentBitsMask));
return true;
}
bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id) {
// Store in bits 5-6.
if (simulcast_id >= (1 << kSimulcastBitsSize))
return false;
*content_type = static_cast<VideoContentType>(
(static_cast<uint8_t>(*content_type) & ~kSimulcastBitsMask) |
((simulcast_id << kSimulcastShift) & kSimulcastBitsMask));
return true;
}
uint8_t GetExperimentId(const VideoContentType& content_type) {
return (static_cast<uint8_t>(content_type) & kExperimentBitsMask) >>
kExperimentShift;
}
uint8_t GetSimulcastId(const VideoContentType& content_type) {
return (static_cast<uint8_t>(content_type) & kSimulcastBitsMask) >>
kSimulcastShift;
}
bool IsScreenshare(const VideoContentType& content_type) { bool IsScreenshare(const VideoContentType& content_type) {
// Ensure no bits apart from the screenshare bit is set.
// This CHECK is a temporary measure to detect code that introduces
// values according to old versions.
RTC_CHECK((static_cast<uint8_t>(content_type) & !kScreenshareBitsMask) == 0);
return (static_cast<uint8_t>(content_type) & kScreenshareBitsMask) > 0; return (static_cast<uint8_t>(content_type) & kScreenshareBitsMask) > 0;
} }
bool IsValidContentType(uint8_t value) { bool IsValidContentType(uint8_t value) {
// Any 6-bit value is allowed. // Only the screenshare bit is allowed.
return value < (1 << kTotalBitsSize); // However, due to previous usage of the next 5 bits, we allow
// the lower 6 bits to be set.
return value < (1 << 6);
} }
const char* ToString(const VideoContentType& content_type) { const char* ToString(const VideoContentType& content_type) {

View File

@ -15,18 +15,15 @@
namespace webrtc { namespace webrtc {
// VideoContentType stored as a single byte, which is sent over the network
// in the rtp-hdrext/video-content-type extension.
// Only the lowest bit is used, per the enum.
enum class VideoContentType : uint8_t { enum class VideoContentType : uint8_t {
UNSPECIFIED = 0, UNSPECIFIED = 0,
SCREENSHARE = 1, SCREENSHARE = 1,
}; };
namespace videocontenttypehelpers { namespace videocontenttypehelpers {
bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id);
bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id);
uint8_t GetExperimentId(const VideoContentType& content_type);
uint8_t GetSimulcastId(const VideoContentType& content_type);
bool IsScreenshare(const VideoContentType& content_type); bool IsScreenshare(const VideoContentType& content_type);
bool IsValidContentType(uint8_t value); bool IsValidContentType(uint8_t value);

View File

@ -10,7 +10,12 @@
#include "api/video/video_timing.h" #include "api/video/video_timing.h"
#include <algorithm>
#include <cstdint>
#include <string>
#include "api/array_view.h" #include "api/array_view.h"
#include "api/units/time_delta.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/strings/string_builder.h" #include "rtc_base/strings/string_builder.h"
@ -25,6 +30,14 @@ uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
return rtc::saturated_cast<uint16_t>(time_ms - base_ms); return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
} }
uint16_t VideoSendTiming::GetDeltaCappedMs(TimeDelta delta) {
if (delta < TimeDelta::Zero()) {
RTC_DLOG(LS_ERROR) << "Delta " << delta.ms()
<< "ms expected to be positive";
}
return rtc::saturated_cast<uint16_t>(delta.ms());
}
TimingFrameInfo::TimingFrameInfo() TimingFrameInfo::TimingFrameInfo()
: rtp_timestamp(0), : rtp_timestamp(0),
capture_time_ms(-1), capture_time_ms(-1),
@ -89,4 +102,23 @@ std::string TimingFrameInfo::ToString() const {
return sb.str(); return sb.str();
} }
VideoPlayoutDelay::VideoPlayoutDelay(TimeDelta min, TimeDelta max)
: min_(std::clamp(min, TimeDelta::Zero(), kMax)),
max_(std::clamp(max, min_, kMax)) {
if (!(TimeDelta::Zero() <= min && min <= max && max <= kMax)) {
RTC_LOG(LS_ERROR) << "Invalid video playout delay: [" << min << "," << max
<< "]. Clamped to [" << this->min() << "," << this->max()
<< "]";
}
}
bool VideoPlayoutDelay::Set(TimeDelta min, TimeDelta max) {
if (TimeDelta::Zero() <= min && min <= max && max <= kMax) {
min_ = min;
max_ = max;
return true;
}
return false;
}
} // namespace webrtc } // namespace webrtc

View File

@ -16,11 +16,14 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc { namespace webrtc {
// Video timing timestamps in ms counted from capture_time_ms of a frame. // Video timing timestamps in ms counted from capture_time_ms of a frame.
// This structure represents data sent in video-timing RTP header extension. // This structure represents data sent in video-timing RTP header extension.
struct VideoSendTiming { struct RTC_EXPORT VideoSendTiming {
enum TimingFrameFlags : uint8_t { enum TimingFrameFlags : uint8_t {
kNotTriggered = 0, // Timing info valid, but not to be transmitted. kNotTriggered = 0, // Timing info valid, but not to be transmitted.
// Used on send-side only. // Used on send-side only.
@ -34,6 +37,7 @@ struct VideoSendTiming {
// https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores // https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
// 16-bit deltas of timestamps from packet capture time. // 16-bit deltas of timestamps from packet capture time.
static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms); static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
static uint16_t GetDeltaCappedMs(TimeDelta delta);
uint16_t encode_start_delta_ms; uint16_t encode_start_delta_ms;
uint16_t encode_finish_delta_ms; uint16_t encode_finish_delta_ms;
@ -41,21 +45,21 @@ struct VideoSendTiming {
uint16_t pacer_exit_delta_ms; uint16_t pacer_exit_delta_ms;
uint16_t network_timestamp_delta_ms; uint16_t network_timestamp_delta_ms;
uint16_t network2_timestamp_delta_ms; uint16_t network2_timestamp_delta_ms;
uint8_t flags; uint8_t flags = TimingFrameFlags::kInvalid;
}; };
// Used to report precise timings of a 'timing frames'. Contains all important // Used to report precise timings of a 'timing frames'. Contains all important
// timestamps for a lifetime of that specific frame. Reported as a string via // timestamps for a lifetime of that specific frame. Reported as a string via
// GetStats(). Only frame which took the longest between two GetStats calls is // GetStats(). Only frame which took the longest between two GetStats calls is
// reported. // reported.
struct TimingFrameInfo { struct RTC_EXPORT TimingFrameInfo {
TimingFrameInfo(); TimingFrameInfo();
// Returns end-to-end delay of a frame, if sender and receiver timestamps are // Returns end-to-end delay of a frame, if sender and receiver timestamps are
// synchronized, -1 otherwise. // synchronized, -1 otherwise.
int64_t EndToEndDelay() const; int64_t EndToEndDelay() const;
// Returns true if current frame took longer to process than |other| frame. // Returns true if current frame took longer to process than `other` frame.
// If other frame's clocks are not synchronized, current frame is always // If other frame's clocks are not synchronized, current frame is always
// preferred. // preferred.
bool IsLongerThan(const TimingFrameInfo& other) const; bool IsLongerThan(const TimingFrameInfo& other) const;
@ -103,26 +107,43 @@ struct TimingFrameInfo {
// Minimum and maximum playout delay values from capture to render. // Minimum and maximum playout delay values from capture to render.
// These are best effort values. // These are best effort values.
// //
// A value < 0 indicates no change from previous valid value.
//
// min = max = 0 indicates that the receiver should try and render // min = max = 0 indicates that the receiver should try and render
// frame as soon as possible. // frame as soon as possible.
// //
// min = x, max = y indicates that the receiver is free to adapt // min = x, max = y indicates that the receiver is free to adapt
// in the range (x, y) based on network jitter. // in the range (x, y) based on network jitter.
struct VideoPlayoutDelay { // This class ensures invariant 0 <= min <= max <= kMax.
VideoPlayoutDelay() = default; class RTC_EXPORT VideoPlayoutDelay {
VideoPlayoutDelay(int min_ms, int max_ms) : min_ms(min_ms), max_ms(max_ms) {} public:
int min_ms = -1; // Maximum supported value for the delay limit.
int max_ms = -1; static constexpr TimeDelta kMax = TimeDelta::Millis(10) * 0xFFF;
bool operator==(const VideoPlayoutDelay& rhs) const { // Creates delay limits that indicates receiver should try to render frame
return min_ms == rhs.min_ms && max_ms == rhs.max_ms; // as soon as possible.
static VideoPlayoutDelay Minimal() {
return VideoPlayoutDelay(TimeDelta::Zero(), TimeDelta::Zero());
} }
};
// TODO(bugs.webrtc.org/7660): Old name, delete after downstream use is updated. // Creates valid, but unspecified limits.
using PlayoutDelay = VideoPlayoutDelay; VideoPlayoutDelay() = default;
VideoPlayoutDelay(const VideoPlayoutDelay&) = default;
VideoPlayoutDelay& operator=(const VideoPlayoutDelay&) = default;
VideoPlayoutDelay(TimeDelta min, TimeDelta max);
bool Set(TimeDelta min, TimeDelta max);
TimeDelta min() const { return min_; }
TimeDelta max() const { return max_; }
friend bool operator==(const VideoPlayoutDelay& lhs,
const VideoPlayoutDelay& rhs) {
return lhs.min_ == rhs.min_ && lhs.max_ == rhs.max_;
}
private:
TimeDelta min_ = TimeDelta::Zero();
TimeDelta max_ = kMax;
};
} // namespace webrtc } // namespace webrtc

View File

@ -23,12 +23,13 @@ rtc_library("audio_frame_operations") {
] ]
deps = [ deps = [
"../../api:array_view",
"../../api/audio:audio_frame_api", "../../api/audio:audio_frame_api",
"../../common_audio", "../../common_audio",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../rtc_base:deprecation", "../../rtc_base:logging",
"../../rtc_base:rtc_base_approved", "../../rtc_base:safe_conversions",
"../../system_wrappers:field_trial", "//third_party/abseil-cpp/absl/base:core_headers",
] ]
} }
@ -44,8 +45,9 @@ if (rtc_include_tests) {
":audio_frame_operations", ":audio_frame_operations",
"../../api/audio:audio_frame_api", "../../api/audio:audio_frame_api",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../rtc_base:rtc_base_approved", "../../rtc_base:logging",
"../../test:field_trial", "../../rtc_base:macromagic",
"../../rtc_base:stringutils",
"../../test:test_support", "../../test:test_support",
"//testing/gtest", "//testing/gtest",
] ]

View File

@ -29,72 +29,17 @@ const float kMuteFadeInc = 1.0f / kMuteFadeFrames;
} // namespace } // namespace
void AudioFrameOperations::Add(const AudioFrame& frame_to_add, void AudioFrameOperations::QuadToStereo(
AudioFrame* result_frame) { InterleavedView<const int16_t> src_audio,
// Sanity check. InterleavedView<int16_t> dst_audio) {
RTC_DCHECK(result_frame); RTC_DCHECK_EQ(NumChannels(src_audio), 4);
RTC_DCHECK_GT(result_frame->num_channels_, 0); RTC_DCHECK_EQ(NumChannels(dst_audio), 2);
RTC_DCHECK_EQ(result_frame->num_channels_, frame_to_add.num_channels_); RTC_DCHECK_EQ(SamplesPerChannel(src_audio), SamplesPerChannel(dst_audio));
for (size_t i = 0; i < SamplesPerChannel(src_audio); ++i) {
bool no_previous_data = result_frame->muted(); auto dst_frame = i * 2;
if (result_frame->samples_per_channel_ != frame_to_add.samples_per_channel_) { dst_audio[dst_frame] =
// Special case we have no data to start with.
RTC_DCHECK_EQ(result_frame->samples_per_channel_, 0);
result_frame->samples_per_channel_ = frame_to_add.samples_per_channel_;
no_previous_data = true;
}
if (result_frame->vad_activity_ == AudioFrame::kVadActive ||
frame_to_add.vad_activity_ == AudioFrame::kVadActive) {
result_frame->vad_activity_ = AudioFrame::kVadActive;
} else if (result_frame->vad_activity_ == AudioFrame::kVadUnknown ||
frame_to_add.vad_activity_ == AudioFrame::kVadUnknown) {
result_frame->vad_activity_ = AudioFrame::kVadUnknown;
}
if (result_frame->speech_type_ != frame_to_add.speech_type_)
result_frame->speech_type_ = AudioFrame::kUndefined;
if (!frame_to_add.muted()) {
const int16_t* in_data = frame_to_add.data();
int16_t* out_data = result_frame->mutable_data();
size_t length =
frame_to_add.samples_per_channel_ * frame_to_add.num_channels_;
if (no_previous_data) {
std::copy(in_data, in_data + length, out_data);
} else {
for (size_t i = 0; i < length; i++) {
const int32_t wrap_guard = static_cast<int32_t>(out_data[i]) +
static_cast<int32_t>(in_data[i]);
out_data[i] = rtc::saturated_cast<int16_t>(wrap_guard);
}
}
}
}
int AudioFrameOperations::MonoToStereo(AudioFrame* frame) {
if (frame->num_channels_ != 1) {
return -1;
}
UpmixChannels(2, frame);
return 0;
}
int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
if (frame->num_channels_ != 2) {
return -1;
}
DownmixChannels(1, frame);
return frame->num_channels_ == 1 ? 0 : -1;
}
void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
size_t samples_per_channel,
int16_t* dst_audio) {
for (size_t i = 0; i < samples_per_channel; i++) {
dst_audio[i * 2] =
(static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1; (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1;
dst_audio[i * 2 + 1] = dst_audio[dst_frame + 1] =
(static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >> (static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >>
1; 1;
} }
@ -109,30 +54,34 @@ int AudioFrameOperations::QuadToStereo(AudioFrame* frame) {
AudioFrame::kMaxDataSizeSamples); AudioFrame::kMaxDataSizeSamples);
if (!frame->muted()) { if (!frame->muted()) {
QuadToStereo(frame->data(), frame->samples_per_channel_, // Note that `src` and `dst` will map in to the same buffer, but the call
frame->mutable_data()); // to `mutable_data()` changes the layout of `frame`, so `src` and `dst`
// will have different dimensions (important to call `data_view()` first).
auto src = frame->data_view();
auto dst = frame->mutable_data(frame->samples_per_channel_, 2);
QuadToStereo(src, dst);
} else {
frame->num_channels_ = 2;
} }
frame->num_channels_ = 2;
return 0; return 0;
} }
void AudioFrameOperations::DownmixChannels(const int16_t* src_audio, void AudioFrameOperations::DownmixChannels(
size_t src_channels, InterleavedView<const int16_t> src_audio,
size_t samples_per_channel, InterleavedView<int16_t> dst_audio) {
size_t dst_channels, RTC_DCHECK_EQ(SamplesPerChannel(src_audio), SamplesPerChannel(dst_audio));
int16_t* dst_audio) { if (NumChannels(src_audio) > 1 && IsMono(dst_audio)) {
if (src_channels > 1 && dst_channels == 1) { // TODO(tommi): change DownmixInterleavedToMono to support InterleavedView
DownmixInterleavedToMono(src_audio, samples_per_channel, src_channels, // and MonoView.
dst_audio); DownmixInterleavedToMono(&src_audio.data()[0], SamplesPerChannel(src_audio),
return; NumChannels(src_audio), &dst_audio.data()[0]);
} else if (src_channels == 4 && dst_channels == 2) { } else if (NumChannels(src_audio) == 4 && NumChannels(dst_audio) == 2) {
QuadToStereo(src_audio, samples_per_channel, dst_audio); QuadToStereo(src_audio, dst_audio);
return; } else {
RTC_DCHECK_NOTREACHED() << "src_channels: " << NumChannels(src_audio)
<< ", dst_channels: " << NumChannels(dst_audio);
} }
RTC_NOTREACHED() << "src_channels: " << src_channels
<< ", dst_channels: " << dst_channels;
} }
void AudioFrameOperations::DownmixChannels(size_t dst_channels, void AudioFrameOperations::DownmixChannels(size_t dst_channels,
@ -149,8 +98,8 @@ void AudioFrameOperations::DownmixChannels(size_t dst_channels,
int err = QuadToStereo(frame); int err = QuadToStereo(frame);
RTC_DCHECK_EQ(err, 0); RTC_DCHECK_EQ(err, 0);
} else { } else {
RTC_NOTREACHED() << "src_channels: " << frame->num_channels_ RTC_DCHECK_NOTREACHED() << "src_channels: " << frame->num_channels_
<< ", dst_channels: " << dst_channels; << ", dst_channels: " << dst_channels;
} }
} }
@ -169,14 +118,16 @@ void AudioFrameOperations::UpmixChannels(size_t target_number_of_channels,
if (!frame->muted()) { if (!frame->muted()) {
// Up-mixing done in place. Going backwards through the frame ensure nothing // Up-mixing done in place. Going backwards through the frame ensure nothing
// is irrevocably overwritten. // is irrevocably overwritten.
for (int i = frame->samples_per_channel_ - 1; i >= 0; i--) { auto frame_data = frame->mutable_data(frame->samples_per_channel_,
target_number_of_channels);
for (int i = frame->samples_per_channel_ - 1; i >= 0; --i) {
for (size_t j = 0; j < target_number_of_channels; ++j) { for (size_t j = 0; j < target_number_of_channels; ++j) {
frame->mutable_data()[target_number_of_channels * i + j] = frame_data[target_number_of_channels * i + j] = frame_data[i];
frame->data()[i];
} }
} }
} else {
frame->num_channels_ = target_number_of_channels;
} }
frame->num_channels_ = target_number_of_channels;
} }
void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) { void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
@ -222,14 +173,14 @@ void AudioFrameOperations::Mute(AudioFrame* frame,
size_t end = count; size_t end = count;
float start_g = 0.0f; float start_g = 0.0f;
if (current_frame_muted) { if (current_frame_muted) {
// Fade out the last |count| samples of frame. // Fade out the last `count` samples of frame.
RTC_DCHECK(!previous_frame_muted); RTC_DCHECK(!previous_frame_muted);
start = frame->samples_per_channel_ - count; start = frame->samples_per_channel_ - count;
end = frame->samples_per_channel_; end = frame->samples_per_channel_;
start_g = 1.0f; start_g = 1.0f;
inc = -inc; inc = -inc;
} else { } else {
// Fade in the first |count| samples of frame. // Fade in the first `count` samples of frame.
RTC_DCHECK(previous_frame_muted); RTC_DCHECK(previous_frame_muted);
} }
@ -250,35 +201,6 @@ void AudioFrameOperations::Mute(AudioFrame* frame) {
Mute(frame, true, true); Mute(frame, true, true);
} }
void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
RTC_DCHECK(frame);
RTC_DCHECK_GT(frame->num_channels_, 0);
if (frame->num_channels_ < 1 || frame->muted()) {
return;
}
int16_t* frame_data = frame->mutable_data();
for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
i++) {
frame_data[i] = frame_data[i] >> 1;
}
}
int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
if (frame->num_channels_ != 2) {
return -1;
} else if (frame->muted()) {
return 0;
}
int16_t* frame_data = frame->mutable_data();
for (size_t i = 0; i < frame->samples_per_channel_; i++) {
frame_data[2 * i] = static_cast<int16_t>(left * frame_data[2 * i]);
frame_data[2 * i + 1] = static_cast<int16_t>(right * frame_data[2 * i + 1]);
}
return 0;
}
int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) { int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
if (frame->muted()) { if (frame->muted()) {
return 0; return 0;

View File

@ -14,8 +14,9 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "absl/base/attributes.h"
#include "api/array_view.h"
#include "api/audio/audio_frame.h" #include "api/audio/audio_frame.h"
#include "rtc_base/deprecation.h"
namespace webrtc { namespace webrtc {
@ -24,67 +25,44 @@ namespace webrtc {
// than a class. // than a class.
class AudioFrameOperations { class AudioFrameOperations {
public: public:
// Add samples in |frame_to_add| with samples in |result_frame| // Downmixes 4 channels `src_audio` to stereo `dst_audio`. This is an in-place
// putting the results in |results_frame|. The fields // operation, meaning `src_audio` and `dst_audio` may point to the same
// |vad_activity_| and |speech_type_| of the result frame are
// updated. If |result_frame| is empty (|samples_per_channel_|==0),
// the samples in |frame_to_add| are added to it. The number of
// channels and number of samples per channel must match except when
// |result_frame| is empty.
static void Add(const AudioFrame& frame_to_add, AudioFrame* result_frame);
// |frame.num_channels_| will be updated. This version checks for sufficient
// buffer size and that |num_channels_| is mono. Use UpmixChannels
// instead. TODO(bugs.webrtc.org/8649): remove.
RTC_DEPRECATED static int MonoToStereo(AudioFrame* frame);
// |frame.num_channels_| will be updated. This version checks that
// |num_channels_| is stereo. Use DownmixChannels
// instead. TODO(bugs.webrtc.org/8649): remove.
RTC_DEPRECATED static int StereoToMono(AudioFrame* frame);
// Downmixes 4 channels |src_audio| to stereo |dst_audio|. This is an in-place
// operation, meaning |src_audio| and |dst_audio| may point to the same
// buffer. // buffer.
static void QuadToStereo(const int16_t* src_audio, static void QuadToStereo(InterleavedView<const int16_t> src_audio,
size_t samples_per_channel, InterleavedView<int16_t> dst_audio);
int16_t* dst_audio);
// |frame.num_channels_| will be updated. This version checks that // `frame.num_channels_` will be updated. This version checks that
// |num_channels_| is 4 channels. // `num_channels_` is 4 channels.
static int QuadToStereo(AudioFrame* frame); static int QuadToStereo(AudioFrame* frame);
// Downmixes |src_channels| |src_audio| to |dst_channels| |dst_audio|. // Downmixes `src_channels` `src_audio` to `dst_channels` `dst_audio`.
// This is an in-place operation, meaning |src_audio| and |dst_audio| // This is an in-place operation, meaning `src_audio` and `dst_audio`
// may point to the same buffer. Supported channel combinations are // may point to the same buffer. Supported channel combinations are
// Stereo to Mono, Quad to Mono, and Quad to Stereo. // Stereo to Mono, Quad to Mono, and Quad to Stereo.
static void DownmixChannels(const int16_t* src_audio, static void DownmixChannels(InterleavedView<const int16_t> src_audio,
size_t src_channels, InterleavedView<int16_t> dst_audio);
size_t samples_per_channel,
size_t dst_channels,
int16_t* dst_audio);
// |frame.num_channels_| will be updated. This version checks that // `frame.num_channels_` will be updated. This version checks that
// |num_channels_| and |dst_channels| are valid and performs relevant downmix. // `num_channels_` and `dst_channels` are valid and performs relevant downmix.
// Supported channel combinations are N channels to Mono, and Quad to Stereo. // Supported channel combinations are N channels to Mono, and Quad to Stereo.
static void DownmixChannels(size_t dst_channels, AudioFrame* frame); static void DownmixChannels(size_t dst_channels, AudioFrame* frame);
// |frame.num_channels_| will be updated. This version checks that // `frame.num_channels_` will be updated. This version checks that
// |num_channels_| and |dst_channels| are valid and performs relevant // `num_channels_` and `dst_channels` are valid and performs relevant
// downmix. Supported channel combinations are Mono to N // downmix. Supported channel combinations are Mono to N
// channels. The single channel is replicated. // channels. The single channel is replicated.
static void UpmixChannels(size_t target_number_of_channels, static void UpmixChannels(size_t target_number_of_channels,
AudioFrame* frame); AudioFrame* frame);
// Swap the left and right channels of |frame|. Fails silently if |frame| is // Swap the left and right channels of `frame`. Fails silently if `frame` is
// not stereo. // not stereo.
static void SwapStereoChannels(AudioFrame* frame); static void SwapStereoChannels(AudioFrame* frame);
// Conditionally zero out contents of |frame| for implementing audio mute: // Conditionally zero out contents of `frame` for implementing audio mute:
// |previous_frame_muted| && |current_frame_muted| - Zero out whole frame. // `previous_frame_muted` && `current_frame_muted` - Zero out whole frame.
// |previous_frame_muted| && !|current_frame_muted| - Fade-in at frame start. // `previous_frame_muted` && !`current_frame_muted` - Fade-in at frame start.
// !|previous_frame_muted| && |current_frame_muted| - Fade-out at frame end. // !`previous_frame_muted` && `current_frame_muted` - Fade-out at frame end.
// !|previous_frame_muted| && !|current_frame_muted| - Leave frame untouched. // !`previous_frame_muted` && !`current_frame_muted` - Leave frame untouched.
static void Mute(AudioFrame* frame, static void Mute(AudioFrame* frame,
bool previous_frame_muted, bool previous_frame_muted,
bool current_frame_muted); bool current_frame_muted);
@ -92,11 +70,6 @@ class AudioFrameOperations {
// Zero out contents of frame. // Zero out contents of frame.
static void Mute(AudioFrame* frame); static void Mute(AudioFrame* frame);
// Halve samples in |frame|.
static void ApplyHalfGain(AudioFrame* frame);
static int Scale(float left, float right, AudioFrame* frame);
static int ScaleWithSat(float scale, AudioFrame* frame); static int ScaleWithSat(float scale, AudioFrame* frame);
}; };

View File

@ -46,17 +46,19 @@ rtc_library("common_audio") {
":common_audio_c", ":common_audio_c",
":sinc_resampler", ":sinc_resampler",
"../api:array_view", "../api:array_view",
"../api/audio:audio_frame_api",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:gtest_prod", "../rtc_base:gtest_prod",
"../rtc_base:rtc_base_approved", "../rtc_base:logging",
"../rtc_base:safe_conversions",
"../rtc_base:sanitizer", "../rtc_base:sanitizer",
"../rtc_base:timeutils",
"../rtc_base/memory:aligned_malloc", "../rtc_base/memory:aligned_malloc",
"../rtc_base/system:arch", "../rtc_base/system:arch",
"../rtc_base/system:file_wrapper", "../rtc_base/system:file_wrapper",
"../system_wrappers", "../system_wrappers",
"third_party/ooura:fft_size_256", "third_party/ooura:fft_size_256",
] ]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
defines = [] defines = []
@ -180,7 +182,6 @@ rtc_library("common_audio_c") {
":common_audio_cc", ":common_audio_cc",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:compile_assert_c", "../rtc_base:compile_assert_c",
"../rtc_base:rtc_base_approved",
"../rtc_base:sanitizer", "../rtc_base:sanitizer",
"../rtc_base/system:arch", "../rtc_base/system:arch",
"../system_wrappers", "../system_wrappers",
@ -196,7 +197,7 @@ rtc_library("common_audio_cc") {
] ]
deps = [ deps = [
"../rtc_base:rtc_base_approved", "../rtc_base:safe_conversions",
"../system_wrappers", "../system_wrappers",
] ]
} }
@ -205,7 +206,6 @@ rtc_source_set("sinc_resampler") {
sources = [ "resampler/sinc_resampler.h" ] sources = [ "resampler/sinc_resampler.h" ]
deps = [ deps = [
"../rtc_base:gtest_prod", "../rtc_base:gtest_prod",
"../rtc_base:rtc_base_approved",
"../rtc_base/memory:aligned_malloc", "../rtc_base/memory:aligned_malloc",
"../rtc_base/system:arch", "../rtc_base/system:arch",
"../system_wrappers", "../system_wrappers",
@ -228,7 +228,6 @@ rtc_library("fir_filter_factory") {
deps = [ deps = [
":fir_filter", ":fir_filter",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/system:arch", "../rtc_base/system:arch",
"../system_wrappers", "../system_wrappers",
] ]
@ -257,7 +256,6 @@ if (current_cpu == "x86" || current_cpu == "x64") {
":fir_filter", ":fir_filter",
":sinc_resampler", ":sinc_resampler",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/memory:aligned_malloc", "../rtc_base/memory:aligned_malloc",
] ]
} }
@ -282,7 +280,6 @@ if (current_cpu == "x86" || current_cpu == "x64") {
":fir_filter", ":fir_filter",
":sinc_resampler", ":sinc_resampler",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/memory:aligned_malloc", "../rtc_base/memory:aligned_malloc",
] ]
} }
@ -307,7 +304,6 @@ if (rtc_build_with_neon) {
":fir_filter", ":fir_filter",
":sinc_resampler", ":sinc_resampler",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/memory:aligned_malloc", "../rtc_base/memory:aligned_malloc",
] ]
} }
@ -329,13 +325,12 @@ if (rtc_build_with_neon) {
deps = [ deps = [
":common_audio_c", ":common_audio_c",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/system:arch", "../rtc_base/system:arch",
] ]
} }
} }
if (rtc_include_tests) { if (rtc_include_tests && !build_with_chromium) {
rtc_test("common_audio_unittests") { rtc_test("common_audio_unittests") {
visibility += webrtc_default_visibility visibility += webrtc_default_visibility
testonly = true testonly = true
@ -378,8 +373,10 @@ if (rtc_include_tests) {
":fir_filter_factory", ":fir_filter_factory",
":sinc_resampler", ":sinc_resampler",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved", "../rtc_base:macromagic",
"../rtc_base:rtc_base_tests_utils", "../rtc_base:rtc_base_tests_utils",
"../rtc_base:stringutils",
"../rtc_base:timeutils",
"../rtc_base/system:arch", "../rtc_base/system:arch",
"../system_wrappers", "../system_wrappers",
"../test:fileutils", "../test:fileutils",

View File

@ -15,12 +15,10 @@
#include <memory> #include <memory>
#include "rtc_base/constructor_magic.h"
namespace webrtc { namespace webrtc {
// Format conversion (remixing and resampling) for audio. Only simple remixing // Format conversion (remixing and resampling) for audio. Only simple remixing
// conversions are supported: downmix to mono (i.e. |dst_channels| == 1) or // conversions are supported: downmix to mono (i.e. `dst_channels` == 1) or
// upmix from mono (i.e. |src_channels == 1|). // upmix from mono (i.e. |src_channels == 1|).
// //
// The source and destination chunks have the same duration in time; specifying // The source and destination chunks have the same duration in time; specifying
@ -35,8 +33,11 @@ class AudioConverter {
size_t dst_frames); size_t dst_frames);
virtual ~AudioConverter() {} virtual ~AudioConverter() {}
// Convert |src|, containing |src_size| samples, to |dst|, having a sample AudioConverter(const AudioConverter&) = delete;
// capacity of |dst_capacity|. Both point to a series of buffers containing AudioConverter& operator=(const AudioConverter&) = delete;
// Convert `src`, containing `src_size` samples, to `dst`, having a sample
// capacity of `dst_capacity`. Both point to a series of buffers containing
// the samples for each channel. The sizes must correspond to the format // the samples for each channel. The sizes must correspond to the format
// passed to Create(). // passed to Create().
virtual void Convert(const float* const* src, virtual void Convert(const float* const* src,
@ -64,8 +65,6 @@ class AudioConverter {
const size_t src_frames_; const size_t src_frames_;
const size_t dst_channels_; const size_t dst_channels_;
const size_t dst_frames_; const size_t dst_frames_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -23,21 +23,59 @@
namespace webrtc { namespace webrtc {
// TODO: b/335805780 - Remove this method. Instead, use Deinterleave() from
// audio_util.h which requires size checked buffer views.
template <typename T>
void Deinterleave(const T* interleaved,
size_t samples_per_channel,
size_t num_channels,
T* const* deinterleaved) {
for (size_t i = 0; i < num_channels; ++i) {
T* channel = deinterleaved[i];
size_t interleaved_idx = i;
for (size_t j = 0; j < samples_per_channel; ++j) {
channel[j] = interleaved[interleaved_idx];
interleaved_idx += num_channels;
}
}
}
// `Interleave()` variant for cases where the deinterleaved channels aren't
// represented by a `DeinterleavedView`.
// TODO: b/335805780 - Remove this method. Instead, use Deinterleave() from
// audio_util.h which requires size checked buffer views.
template <typename T>
void Interleave(const T* const* deinterleaved,
size_t samples_per_channel,
size_t num_channels,
InterleavedView<T>& interleaved) {
RTC_DCHECK_EQ(NumChannels(interleaved), num_channels);
RTC_DCHECK_EQ(SamplesPerChannel(interleaved), samples_per_channel);
for (size_t i = 0; i < num_channels; ++i) {
const T* channel = deinterleaved[i];
size_t interleaved_idx = i;
for (size_t j = 0; j < samples_per_channel; ++j) {
interleaved[interleaved_idx] = channel[j];
interleaved_idx += num_channels;
}
}
}
// Helper to encapsulate a contiguous data buffer, full or split into frequency // Helper to encapsulate a contiguous data buffer, full or split into frequency
// bands, with access to a pointer arrays of the deinterleaved channels and // bands, with access to a pointer arrays of the deinterleaved channels and
// bands. The buffer is zero initialized at creation. // bands. The buffer is zero initialized at creation.
// //
// The buffer structure is showed below for a 2 channel and 2 bands case: // The buffer structure is showed below for a 2 channel and 2 bands case:
// //
// |data_|: // `data_`:
// { [ --- b1ch1 --- ] [ --- b2ch1 --- ] [ --- b1ch2 --- ] [ --- b2ch2 --- ] } // { [ --- b1ch1 --- ] [ --- b2ch1 --- ] [ --- b1ch2 --- ] [ --- b2ch2 --- ] }
// //
// The pointer arrays for the same example are as follows: // The pointer arrays for the same example are as follows:
// //
// |channels_|: // `channels_`:
// { [ b1ch1* ] [ b1ch2* ] [ b2ch1* ] [ b2ch2* ] } // { [ b1ch1* ] [ b1ch2* ] [ b2ch1* ] [ b2ch2* ] }
// //
// |bands_|: // `bands_`:
// { [ b1ch1* ] [ b2ch1* ] [ b1ch2* ] [ b2ch2* ] } // { [ b1ch1* ] [ b2ch1* ] [ b1ch2* ] [ b2ch2* ] }
template <typename T> template <typename T>
class ChannelBuffer { class ChannelBuffer {
@ -81,15 +119,15 @@ class ChannelBuffer {
// If band is explicitly specificed, the channels for a specific band are // If band is explicitly specificed, the channels for a specific band are
// returned and the usage becomes: channels(band)[channel][sample]. // returned and the usage becomes: channels(band)[channel][sample].
// Where: // Where:
// 0 <= band < |num_bands_| // 0 <= band < `num_bands_`
// 0 <= channel < |num_allocated_channels_| // 0 <= channel < `num_allocated_channels_`
// 0 <= sample < |num_frames_per_band_| // 0 <= sample < `num_frames_per_band_`
// If band is not explicitly specified, the full-band channels (or lower band // If band is not explicitly specified, the full-band channels (or lower band
// channels) are returned and the usage becomes: channels()[channel][sample]. // channels) are returned and the usage becomes: channels()[channel][sample].
// Where: // Where:
// 0 <= channel < |num_allocated_channels_| // 0 <= channel < `num_allocated_channels_`
// 0 <= sample < |num_frames_| // 0 <= sample < `num_frames_`
const T* const* channels(size_t band = 0) const { const T* const* channels(size_t band = 0) const {
RTC_DCHECK_LT(band, num_bands_); RTC_DCHECK_LT(band, num_bands_);
return &channels_[band * num_allocated_channels_]; return &channels_[band * num_allocated_channels_];
@ -109,9 +147,9 @@ class ChannelBuffer {
// Usage: // Usage:
// bands(channel)[band][sample]. // bands(channel)[band][sample].
// Where: // Where:
// 0 <= channel < |num_channels_| // 0 <= channel < `num_channels_`
// 0 <= band < |num_bands_| // 0 <= band < `num_bands_`
// 0 <= sample < |num_frames_per_band_| // 0 <= sample < `num_frames_per_band_`
const T* const* bands(size_t channel) const { const T* const* bands(size_t channel) const {
RTC_DCHECK_LT(channel, num_channels_); RTC_DCHECK_LT(channel, num_channels_);
RTC_DCHECK_GE(channel, 0); RTC_DCHECK_GE(channel, 0);
@ -129,8 +167,8 @@ class ChannelBuffer {
return bands_view_[channel]; return bands_view_[channel];
} }
// Sets the |slice| pointers to the |start_frame| position for each channel. // Sets the `slice` pointers to the `start_frame` position for each channel.
// Returns |slice| for convenience. // Returns `slice` for convenience.
const T* const* Slice(T** slice, size_t start_frame) const { const T* const* Slice(T** slice, size_t start_frame) const {
RTC_DCHECK_LT(start_frame, num_frames_); RTC_DCHECK_LT(start_frame, num_frames_);
for (size_t i = 0; i < num_channels_; ++i) for (size_t i = 0; i < num_channels_; ++i)

View File

@ -20,8 +20,8 @@ class FIRFilter {
public: public:
virtual ~FIRFilter() {} virtual ~FIRFilter() {}
// Filters the |in| data supplied. // Filters the `in` data supplied.
// |out| must be previously allocated and it must be at least of |length|. // `out` must be previously allocated and it must be at least of `length`.
virtual void Filter(const float* in, size_t length, float* out) = 0; virtual void Filter(const float* in, size_t length, float* out) = 0;
}; };

View File

@ -52,7 +52,7 @@ void FIRFilterAVX2::Filter(const float* in, size_t length, float* out) {
memcpy(&state_[state_length_], in, length * sizeof(*in)); memcpy(&state_[state_length_], in, length * sizeof(*in));
// Convolves the input signal |in| with the filter kernel |coefficients_| // Convolves the input signal `in` with the filter kernel `coefficients_`
// taking into account the previous state. // taking into account the previous state.
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
float* in_ptr = &state_[i]; float* in_ptr = &state_[i];

View File

@ -34,7 +34,7 @@ FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length)
void FIRFilterC::Filter(const float* in, size_t length, float* out) { void FIRFilterC::Filter(const float* in, size_t length, float* out) {
RTC_DCHECK_GT(length, 0); RTC_DCHECK_GT(length, 0);
// Convolves the input signal |in| with the filter kernel |coefficients_| // Convolves the input signal `in` with the filter kernel `coefficients_`
// taking into account the previous state. // taking into account the previous state.
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
out[i] = 0.f; out[i] = 0.f;

View File

@ -28,7 +28,7 @@ FIRFilter* CreateFirFilter(const float* coefficients,
size_t coefficients_length, size_t coefficients_length,
size_t max_input_length) { size_t max_input_length) {
if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) { if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) {
RTC_NOTREACHED(); RTC_DCHECK_NOTREACHED();
return nullptr; return nullptr;
} }

View File

@ -20,7 +20,7 @@ class FIRFilter;
// Creates a filter with the given coefficients. All initial state values will // Creates a filter with the given coefficients. All initial state values will
// be zeros. // be zeros.
// The length of the chunks fed to the filter should never be greater than // The length of the chunks fed to the filter should never be greater than
// |max_input_length|. This is needed because, when vectorizing it is // `max_input_length`. This is needed because, when vectorizing it is
// necessary to concatenate the input after the state, and resizing this array // necessary to concatenate the input after the state, and resizing this array
// dynamically is expensive. // dynamically is expensive.
FIRFilter* CreateFirFilter(const float* coefficients, FIRFilter* CreateFirFilter(const float* coefficients,

View File

@ -48,7 +48,7 @@ void FIRFilterNEON::Filter(const float* in, size_t length, float* out) {
memcpy(&state_[state_length_], in, length * sizeof(*in)); memcpy(&state_[state_length_], in, length * sizeof(*in));
// Convolves the input signal |in| with the filter kernel |coefficients_| // Convolves the input signal `in` with the filter kernel `coefficients_`
// taking into account the previous state. // taking into account the previous state.
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
float* in_ptr = &state_[i]; float* in_ptr = &state_[i];

View File

@ -49,7 +49,7 @@ void FIRFilterSSE2::Filter(const float* in, size_t length, float* out) {
memcpy(&state_[state_length_], in, length * sizeof(*in)); memcpy(&state_[state_length_], in, length * sizeof(*in));
// Convolves the input signal |in| with the filter kernel |coefficients_| // Convolves the input signal `in` with the filter kernel `coefficients_`
// taking into account the previous state. // taking into account the previous state.
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
float* in_ptr = &state_[i]; float* in_ptr = &state_[i];

View File

@ -18,12 +18,24 @@
#include <cstring> #include <cstring>
#include <limits> #include <limits>
#include "api/audio/audio_view.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
namespace webrtc { namespace webrtc {
typedef std::numeric_limits<int16_t> limits_int16; typedef std::numeric_limits<int16_t> limits_int16;
// TODO(tommi, peah): Move these constants to their own header, e.g.
// `audio_constants.h`. Also consider if they should be in api/.
// Absolute highest acceptable sample rate supported for audio processing,
// capture and codecs. Note that for some components some cases a lower limit
// applies which typically is 48000 but in some cases is lower.
constexpr int kMaxSampleRateHz = 384000;
// Number of samples per channel for 10ms of audio at the highest sample rate.
constexpr size_t kMaxSamplesPerChannel10ms = kMaxSampleRateHz / 100u;
// The conversion functions use the following naming convention: // The conversion functions use the following naming convention:
// S16: int16_t [-32768, 32767] // S16: int16_t [-32768, 32767]
// Float: float [-1.0, 1.0] // Float: float [-1.0, 1.0]
@ -91,9 +103,10 @@ inline float FloatS16ToDbfs(float v) {
return 20.0f * std::log10(v) + kMinDbfs; return 20.0f * std::log10(v) + kMinDbfs;
} }
// Copy audio from |src| channels to |dest| channels unless |src| and |dest| // Copy audio from `src` channels to `dest` channels unless `src` and `dest`
// point to the same address. |src| and |dest| must have the same number of // point to the same address. `src` and `dest` must have the same number of
// channels, and there must be sufficient space allocated in |dest|. // channels, and there must be sufficient space allocated in `dest`.
// TODO: b/335805780 - Accept ArrayView.
template <typename T> template <typename T>
void CopyAudioIfNeeded(const T* const* src, void CopyAudioIfNeeded(const T* const* src,
int num_frames, int num_frames,
@ -106,17 +119,20 @@ void CopyAudioIfNeeded(const T* const* src,
} }
} }
// Deinterleave audio from |interleaved| to the channel buffers pointed to // Deinterleave audio from `interleaved` to the channel buffers pointed to
// by |deinterleaved|. There must be sufficient space allocated in the // by `deinterleaved`. There must be sufficient space allocated in the
// |deinterleaved| buffers (|num_channel| buffers with |samples_per_channel| // `deinterleaved` buffers (`num_channel` buffers with `samples_per_channel`
// per buffer). // per buffer).
template <typename T> template <typename T>
void Deinterleave(const T* interleaved, void Deinterleave(const InterleavedView<const T>& interleaved,
size_t samples_per_channel, const DeinterleavedView<T>& deinterleaved) {
size_t num_channels, RTC_DCHECK_EQ(NumChannels(interleaved), NumChannels(deinterleaved));
T* const* deinterleaved) { RTC_DCHECK_EQ(SamplesPerChannel(interleaved),
SamplesPerChannel(deinterleaved));
const auto num_channels = NumChannels(interleaved);
const auto samples_per_channel = SamplesPerChannel(interleaved);
for (size_t i = 0; i < num_channels; ++i) { for (size_t i = 0; i < num_channels; ++i) {
T* channel = deinterleaved[i]; MonoView<T> channel = deinterleaved[i];
size_t interleaved_idx = i; size_t interleaved_idx = i;
for (size_t j = 0; j < samples_per_channel; ++j) { for (size_t j = 0; j < samples_per_channel; ++j) {
channel[j] = interleaved[interleaved_idx]; channel[j] = interleaved[interleaved_idx];
@ -125,56 +141,28 @@ void Deinterleave(const T* interleaved,
} }
} }
// Interleave audio from the channel buffers pointed to by |deinterleaved| to // Interleave audio from the channel buffers pointed to by `deinterleaved` to
// |interleaved|. There must be sufficient space allocated in |interleaved| // `interleaved`. There must be sufficient space allocated in `interleaved`
// (|samples_per_channel| * |num_channels|). // (`samples_per_channel` * `num_channels`).
template <typename T> template <typename T>
void Interleave(const T* const* deinterleaved, void Interleave(const DeinterleavedView<const T>& deinterleaved,
size_t samples_per_channel, const InterleavedView<T>& interleaved) {
size_t num_channels, RTC_DCHECK_EQ(NumChannels(interleaved), NumChannels(deinterleaved));
T* interleaved) { RTC_DCHECK_EQ(SamplesPerChannel(interleaved),
for (size_t i = 0; i < num_channels; ++i) { SamplesPerChannel(deinterleaved));
const T* channel = deinterleaved[i]; for (size_t i = 0; i < deinterleaved.num_channels(); ++i) {
const auto channel = deinterleaved[i];
size_t interleaved_idx = i; size_t interleaved_idx = i;
for (size_t j = 0; j < samples_per_channel; ++j) { for (size_t j = 0; j < deinterleaved.samples_per_channel(); ++j) {
interleaved[interleaved_idx] = channel[j]; interleaved[interleaved_idx] = channel[j];
interleaved_idx += num_channels; interleaved_idx += deinterleaved.num_channels();
} }
} }
} }
// Copies audio from a single channel buffer pointed to by |mono| to each
// channel of |interleaved|. There must be sufficient space allocated in
// |interleaved| (|samples_per_channel| * |num_channels|).
template <typename T>
void UpmixMonoToInterleaved(const T* mono,
int num_frames,
int num_channels,
T* interleaved) {
int interleaved_idx = 0;
for (int i = 0; i < num_frames; ++i) {
for (int j = 0; j < num_channels; ++j) {
interleaved[interleaved_idx++] = mono[i];
}
}
}
template <typename T, typename Intermediate>
void DownmixToMono(const T* const* input_channels,
size_t num_frames,
int num_channels,
T* out) {
for (size_t i = 0; i < num_frames; ++i) {
Intermediate value = input_channels[0][i];
for (int j = 1; j < num_channels; ++j) {
value += input_channels[j][i];
}
out[i] = value / num_channels;
}
}
// Downmixes an interleaved multichannel signal to a single channel by averaging // Downmixes an interleaved multichannel signal to a single channel by averaging
// all channels. // all channels.
// TODO: b/335805780 - Accept InterleavedView and DeinterleavedView.
template <typename T, typename Intermediate> template <typename T, typename Intermediate>
void DownmixInterleavedToMonoImpl(const T* interleaved, void DownmixInterleavedToMonoImpl(const T* interleaved,
size_t num_frames, size_t num_frames,
@ -197,12 +185,14 @@ void DownmixInterleavedToMonoImpl(const T* interleaved,
} }
} }
// TODO: b/335805780 - Accept InterleavedView and DeinterleavedView.
template <typename T> template <typename T>
void DownmixInterleavedToMono(const T* interleaved, void DownmixInterleavedToMono(const T* interleaved,
size_t num_frames, size_t num_frames,
int num_channels, int num_channels,
T* deinterleaved); T* deinterleaved);
// TODO: b/335805780 - Accept InterleavedView and DeinterleavedView.
template <> template <>
void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved, void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved,
size_t num_frames, size_t num_frames,

View File

@ -4,8 +4,6 @@ common_audio_sources = [
'channel_buffer.cc', 'channel_buffer.cc',
'fir_filter_c.cc', 'fir_filter_c.cc',
'fir_filter_factory.cc', 'fir_filter_factory.cc',
'real_fourier.cc',
'real_fourier_ooura.cc',
'resampler/push_resampler.cc', 'resampler/push_resampler.cc',
'resampler/push_sinc_resampler.cc', 'resampler/push_sinc_resampler.cc',
'resampler/resampler.cc', 'resampler/resampler.cc',
@ -55,9 +53,6 @@ common_audio_sources = [
'vad/vad_gmm.c', 'vad/vad_gmm.c',
'vad/vad_sp.c', 'vad/vad_sp.c',
'vad/webrtc_vad.c', 'vad/webrtc_vad.c',
'wav_file.cc',
'wav_header.cc',
'window_generator.cc',
] ]
arch_libs = [] arch_libs = []
@ -83,8 +78,8 @@ if have_x86
], ],
dependencies: common_deps, dependencies: common_deps,
include_directories: webrtc_inc, include_directories: webrtc_inc,
c_args: common_cflags + ['-mavx2', '-mfma'], c_args: common_cflags + avx_flags,
cpp_args: common_cxxflags + ['-mavx2', '-mfma'] cpp_args: common_cxxflags + avx_flags
) )
] ]
endif endif
@ -99,7 +94,7 @@ if have_mips
'signal_processing/min_max_operations_mips.c', 'signal_processing/min_max_operations_mips.c',
'signal_processing/resample_by_2_mips.c', 'signal_processing/resample_by_2_mips.c',
'signal_processing/vector_scaling_operations_mips.c', 'signal_processing/vector_scaling_operations_mips.c',
'third_party/ooura/fft_size_128/ooura_fft_mips.c', 'third_party/ooura/fft_size_128/ooura_fft_mips.cc',
'third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c', 'third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c',
] ]
endif endif
@ -117,7 +112,7 @@ if have_armv7
] ]
endif endif
if have_neon if neon_opt.enabled()
common_audio_sources += [ common_audio_sources += [
'fir_filter_neon.cc', 'fir_filter_neon.cc',
'resampler/sinc_resampler_neon.cc', 'resampler/sinc_resampler_neon.cc',

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "common_audio/real_fourier.h"
#include "common_audio/real_fourier_ooura.h"
#include "common_audio/signal_processing/include/signal_processing_library.h"
#include "rtc_base/checks.h"
namespace webrtc {
using std::complex;
const size_t RealFourier::kFftBufferAlignment = 32;
std::unique_ptr<RealFourier> RealFourier::Create(int fft_order) {
return std::unique_ptr<RealFourier>(new RealFourierOoura(fft_order));
}
int RealFourier::FftOrder(size_t length) {
RTC_CHECK_GT(length, 0U);
return WebRtcSpl_GetSizeInBits(static_cast<uint32_t>(length - 1));
}
size_t RealFourier::FftLength(int order) {
RTC_CHECK_GE(order, 0);
return size_t{1} << order;
}
size_t RealFourier::ComplexLength(int order) {
return FftLength(order) / 2 + 1;
}
RealFourier::fft_real_scoper RealFourier::AllocRealBuffer(int count) {
return fft_real_scoper(static_cast<float*>(
AlignedMalloc(sizeof(float) * count, kFftBufferAlignment)));
}
RealFourier::fft_cplx_scoper RealFourier::AllocCplxBuffer(int count) {
return fft_cplx_scoper(static_cast<complex<float>*>(
AlignedMalloc(sizeof(complex<float>) * count, kFftBufferAlignment)));
}
} // namespace webrtc

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef COMMON_AUDIO_REAL_FOURIER_H_
#define COMMON_AUDIO_REAL_FOURIER_H_
#include <stddef.h>
#include <complex>
#include <memory>
#include "rtc_base/memory/aligned_malloc.h"
// Uniform interface class for the real DFT and its inverse, for power-of-2
// input lengths. Also contains helper functions for buffer allocation, taking
// care of any memory alignment requirements the underlying library might have.
namespace webrtc {
class RealFourier {
public:
// Shorthand typenames for the scopers used by the buffer allocation helpers.
typedef std::unique_ptr<float[], AlignedFreeDeleter> fft_real_scoper;
typedef std::unique_ptr<std::complex<float>[], AlignedFreeDeleter>
fft_cplx_scoper;
// The alignment required for all input and output buffers, in bytes.
static const size_t kFftBufferAlignment;
// Construct a wrapper instance for the given input order, which must be
// between 1 and kMaxFftOrder, inclusively.
static std::unique_ptr<RealFourier> Create(int fft_order);
virtual ~RealFourier() {}
// Helper to compute the smallest FFT order (a power of 2) which will contain
// the given input length.
static int FftOrder(size_t length);
// Helper to compute the input length from the FFT order.
static size_t FftLength(int order);
// Helper to compute the exact length, in complex floats, of the transform
// output (i.e. |2^order / 2 + 1|).
static size_t ComplexLength(int order);
// Buffer allocation helpers. The buffers are large enough to hold |count|
// floats/complexes and suitably aligned for use by the implementation.
// The returned scopers are set up with proper deleters; the caller owns
// the allocated memory.
static fft_real_scoper AllocRealBuffer(int count);
static fft_cplx_scoper AllocCplxBuffer(int count);
// Main forward transform interface. The output array need only be big
// enough for |2^order / 2 + 1| elements - the conjugate pairs are not
// returned. Input and output must be properly aligned (e.g. through
// AllocRealBuffer and AllocCplxBuffer) and input length must be
// |2^order| (same as given at construction time).
virtual void Forward(const float* src, std::complex<float>* dest) const = 0;
// Inverse transform. Same input format as output above, conjugate pairs
// not needed.
virtual void Inverse(const std::complex<float>* src, float* dest) const = 0;
virtual int order() const = 0;
};
} // namespace webrtc
#endif // COMMON_AUDIO_REAL_FOURIER_H_

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "common_audio/real_fourier_ooura.h"
#include <algorithm>
#include <cmath>
#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
#include "rtc_base/checks.h"
namespace webrtc {
using std::complex;
namespace {
void Conjugate(complex<float>* array, size_t complex_length) {
std::for_each(array, array + complex_length,
[=](complex<float>& v) { v = std::conj(v); });
}
size_t ComputeWorkIpSize(size_t fft_length) {
return static_cast<size_t>(
2 + std::ceil(std::sqrt(static_cast<float>(fft_length))));
}
} // namespace
RealFourierOoura::RealFourierOoura(int fft_order)
: order_(fft_order),
length_(FftLength(order_)),
complex_length_(ComplexLength(order_)),
// Zero-initializing work_ip_ will cause rdft to initialize these work
// arrays on the first call.
work_ip_(new size_t[ComputeWorkIpSize(length_)]()),
work_w_(new float[complex_length_]()) {
RTC_CHECK_GE(fft_order, 1);
}
RealFourierOoura::~RealFourierOoura() = default;
void RealFourierOoura::Forward(const float* src, complex<float>* dest) const {
{
// This cast is well-defined since C++11. See "Non-static data members" at:
// http://en.cppreference.com/w/cpp/numeric/complex
auto* dest_float = reinterpret_cast<float*>(dest);
std::copy(src, src + length_, dest_float);
WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get());
}
// Ooura places real[n/2] in imag[0].
dest[complex_length_ - 1] = complex<float>(dest[0].imag(), 0.0f);
dest[0] = complex<float>(dest[0].real(), 0.0f);
// Ooura returns the conjugate of the usual Fourier definition.
Conjugate(dest, complex_length_);
}
void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
{
auto* dest_complex = reinterpret_cast<complex<float>*>(dest);
// The real output array is shorter than the input complex array by one
// complex element.
const size_t dest_complex_length = complex_length_ - 1;
std::copy(src, src + dest_complex_length, dest_complex);
// Restore Ooura's conjugate definition.
Conjugate(dest_complex, dest_complex_length);
// Restore real[n/2] to imag[0].
dest_complex[0] =
complex<float>(dest_complex[0].real(), src[complex_length_ - 1].real());
}
WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get());
// Ooura returns a scaled version.
const float scale = 2.0f / length_;
std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; });
}
int RealFourierOoura::order() const {
return order_;
}
} // namespace webrtc

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef COMMON_AUDIO_REAL_FOURIER_OOURA_H_
#define COMMON_AUDIO_REAL_FOURIER_OOURA_H_
#include <stddef.h>
#include <complex>
#include <memory>
#include "common_audio/real_fourier.h"
namespace webrtc {
class RealFourierOoura : public RealFourier {
public:
explicit RealFourierOoura(int fft_order);
~RealFourierOoura() override;
void Forward(const float* src, std::complex<float>* dest) const override;
void Inverse(const std::complex<float>* src, float* dest) const override;
int order() const override;
private:
const int order_;
const size_t length_;
const size_t complex_length_;
// These are work arrays for Ooura. The names are based on the comments in
// common_audio/third_party/ooura/fft_size_256/fft4g.cc.
const std::unique_ptr<size_t[]> work_ip_;
const std::unique_ptr<float[]> work_w_;
};
} // namespace webrtc
#endif // COMMON_AUDIO_REAL_FOURIER_OOURA_H_

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
#include <complex>
#include "webrtc/common_audio/real_fourier.h"
namespace webrtc {
class RealFourierOpenmax : public RealFourier {
public:
explicit RealFourierOpenmax(int fft_order);
~RealFourierOpenmax() override;
void Forward(const float* src, std::complex<float>* dest) const override;
void Inverse(const std::complex<float>* src, float* dest) const override;
int order() const override {
return order_;
}
private:
// Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the
// dependency on openmax.
typedef void OMXFFTSpec_R_F32_;
const int order_;
OMXFFTSpec_R_F32_* const omx_spec_;
};
} // namespace webrtc
#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_

View File

@ -14,45 +14,44 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "api/audio/audio_view.h"
namespace webrtc { namespace webrtc {
class PushSincResampler; class PushSincResampler;
// Wraps PushSincResampler to provide stereo support. // Wraps PushSincResampler to provide stereo support.
// TODO(ajm): add support for an arbitrary number of channels. // Note: This implementation assumes 10ms buffer sizes throughout.
template <typename T> template <typename T>
class PushResampler { class PushResampler final {
public: public:
PushResampler(); PushResampler();
virtual ~PushResampler(); PushResampler(size_t src_samples_per_channel,
size_t dst_samples_per_channel,
// Must be called whenever the parameters change. Free to be called at any size_t num_channels);
// time as it is a no-op if parameters have not changed since the last call. ~PushResampler();
int InitializeIfNeeded(int src_sample_rate_hz,
int dst_sample_rate_hz,
size_t num_channels);
// Returns the total number of samples provided in destination (e.g. 32 kHz, // Returns the total number of samples provided in destination (e.g. 32 kHz,
// 2 channel audio gives 640 samples). // 2 channel audio gives 640 samples).
int Resample(const T* src, size_t src_length, T* dst, size_t dst_capacity); int Resample(InterleavedView<const T> src, InterleavedView<T> dst);
// For when a deinterleaved/mono channel already exists and we can skip the
// deinterleaved operation.
int Resample(MonoView<const T> src, MonoView<T> dst);
private: private:
int src_sample_rate_hz_; // Ensures that source and destination buffers for deinterleaving are
int dst_sample_rate_hz_; // correctly configured prior to resampling that requires deinterleaving.
size_t num_channels_; void EnsureInitialized(size_t src_samples_per_channel,
// Vector that is needed to provide the proper inputs and outputs to the size_t dst_samples_per_channel,
// interleave/de-interleave methods used in Resample. This needs to be size_t num_channels);
// heap-allocated on the state to support an arbitrary number of channels
// without doing run-time heap-allocations in the Resample method.
std::vector<T*> channel_data_array_;
struct ChannelResampler { // Buffers used for when a deinterleaving step is necessary.
std::unique_ptr<PushSincResampler> resampler; std::unique_ptr<T[]> source_;
std::vector<T> source; std::unique_ptr<T[]> destination_;
std::vector<T> destination; DeinterleavedView<T> source_view_;
}; DeinterleavedView<T> destination_view_;
std::vector<ChannelResampler> channel_resamplers_; std::vector<std::unique_ptr<PushSincResampler>> resamplers_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -15,133 +15,109 @@
#include <memory> #include <memory>
#include "api/audio/audio_frame.h"
#include "common_audio/include/audio_util.h" #include "common_audio/include/audio_util.h"
#include "common_audio/resampler/push_sinc_resampler.h" #include "common_audio/resampler/push_sinc_resampler.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
namespace webrtc { namespace webrtc {
namespace {
// These checks were factored out into a non-templatized function
// due to problems with clang on Windows in debug builds.
// For some reason having the DCHECKs inline in the template code
// caused the compiler to generate code that threw off the linker.
// TODO(tommi): Re-enable when we've figured out what the problem is.
// http://crbug.com/615050
void CheckValidInitParams(int src_sample_rate_hz,
int dst_sample_rate_hz,
size_t num_channels) {
// The below checks are temporarily disabled on WEBRTC_WIN due to problems
// with clang debug builds.
#if !defined(WEBRTC_WIN) && defined(__clang__)
RTC_DCHECK_GT(src_sample_rate_hz, 0);
RTC_DCHECK_GT(dst_sample_rate_hz, 0);
RTC_DCHECK_GT(num_channels, 0);
#endif
}
void CheckExpectedBufferSizes(size_t src_length, namespace {
size_t dst_capacity, // Maximum concurrent number of channels for `PushResampler<>`.
size_t num_channels, // Note that this may be different from what the maximum is for audio codecs.
int src_sample_rate, constexpr int kMaxNumberOfChannels = 8;
int dst_sample_rate) {
// The below checks are temporarily disabled on WEBRTC_WIN due to problems
// with clang debug builds.
// TODO(tommi): Re-enable when we've figured out what the problem is.
// http://crbug.com/615050
#if !defined(WEBRTC_WIN) && defined(__clang__)
const size_t src_size_10ms = src_sample_rate * num_channels / 100;
const size_t dst_size_10ms = dst_sample_rate * num_channels / 100;
RTC_DCHECK_EQ(src_length, src_size_10ms);
RTC_DCHECK_GE(dst_capacity, dst_size_10ms);
#endif
}
} // namespace } // namespace
template <typename T> template <typename T>
PushResampler<T>::PushResampler() PushResampler<T>::PushResampler() = default;
: src_sample_rate_hz_(0), dst_sample_rate_hz_(0), num_channels_(0) {}
template <typename T> template <typename T>
PushResampler<T>::~PushResampler() {} PushResampler<T>::PushResampler(size_t src_samples_per_channel,
size_t dst_samples_per_channel,
template <typename T> size_t num_channels) {
int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz, EnsureInitialized(src_samples_per_channel, dst_samples_per_channel,
int dst_sample_rate_hz, num_channels);
size_t num_channels) {
CheckValidInitParams(src_sample_rate_hz, dst_sample_rate_hz, num_channels);
if (src_sample_rate_hz == src_sample_rate_hz_ &&
dst_sample_rate_hz == dst_sample_rate_hz_ &&
num_channels == num_channels_) {
// No-op if settings haven't changed.
return 0;
}
if (src_sample_rate_hz <= 0 || dst_sample_rate_hz <= 0 || num_channels <= 0) {
return -1;
}
src_sample_rate_hz_ = src_sample_rate_hz;
dst_sample_rate_hz_ = dst_sample_rate_hz;
num_channels_ = num_channels;
const size_t src_size_10ms_mono =
static_cast<size_t>(src_sample_rate_hz / 100);
const size_t dst_size_10ms_mono =
static_cast<size_t>(dst_sample_rate_hz / 100);
channel_resamplers_.clear();
for (size_t i = 0; i < num_channels; ++i) {
channel_resamplers_.push_back(ChannelResampler());
auto channel_resampler = channel_resamplers_.rbegin();
channel_resampler->resampler = std::make_unique<PushSincResampler>(
src_size_10ms_mono, dst_size_10ms_mono);
channel_resampler->source.resize(src_size_10ms_mono);
channel_resampler->destination.resize(dst_size_10ms_mono);
}
channel_data_array_.resize(num_channels_);
return 0;
} }
template <typename T> template <typename T>
int PushResampler<T>::Resample(const T* src, PushResampler<T>::~PushResampler() = default;
size_t src_length,
T* dst,
size_t dst_capacity) {
CheckExpectedBufferSizes(src_length, dst_capacity, num_channels_,
src_sample_rate_hz_, dst_sample_rate_hz_);
if (src_sample_rate_hz_ == dst_sample_rate_hz_) { template <typename T>
void PushResampler<T>::EnsureInitialized(size_t src_samples_per_channel,
size_t dst_samples_per_channel,
size_t num_channels) {
RTC_DCHECK_GT(src_samples_per_channel, 0);
RTC_DCHECK_GT(dst_samples_per_channel, 0);
RTC_DCHECK_GT(num_channels, 0);
RTC_DCHECK_LE(src_samples_per_channel, kMaxSamplesPerChannel10ms);
RTC_DCHECK_LE(dst_samples_per_channel, kMaxSamplesPerChannel10ms);
RTC_DCHECK_LE(num_channels, kMaxNumberOfChannels);
if (src_samples_per_channel == SamplesPerChannel(source_view_) &&
dst_samples_per_channel == SamplesPerChannel(destination_view_) &&
num_channels == NumChannels(source_view_)) {
// No-op if settings haven't changed.
return;
}
// Allocate two buffers for all source and destination channels.
// Then organize source and destination views together with an array of
// resamplers for each channel in the deinterlaved buffers.
source_.reset(new T[src_samples_per_channel * num_channels]);
destination_.reset(new T[dst_samples_per_channel * num_channels]);
source_view_ = DeinterleavedView<T>(source_.get(), src_samples_per_channel,
num_channels);
destination_view_ = DeinterleavedView<T>(
destination_.get(), dst_samples_per_channel, num_channels);
resamplers_.resize(num_channels);
for (size_t i = 0; i < num_channels; ++i) {
resamplers_[i] = std::make_unique<PushSincResampler>(
src_samples_per_channel, dst_samples_per_channel);
}
}
template <typename T>
int PushResampler<T>::Resample(InterleavedView<const T> src,
InterleavedView<T> dst) {
EnsureInitialized(SamplesPerChannel(src), SamplesPerChannel(dst),
NumChannels(src));
RTC_DCHECK_EQ(NumChannels(src), NumChannels(source_view_));
RTC_DCHECK_EQ(NumChannels(dst), NumChannels(destination_view_));
RTC_DCHECK_EQ(SamplesPerChannel(src), SamplesPerChannel(source_view_));
RTC_DCHECK_EQ(SamplesPerChannel(dst), SamplesPerChannel(destination_view_));
if (SamplesPerChannel(src) == SamplesPerChannel(dst)) {
// The old resampler provides this memcpy facility in the case of matching // The old resampler provides this memcpy facility in the case of matching
// sample rates, so reproduce it here for the sinc resampler. // sample rates, so reproduce it here for the sinc resampler.
memcpy(dst, src, src_length * sizeof(T)); CopySamples(dst, src);
return static_cast<int>(src_length); return static_cast<int>(src.data().size());
} }
const size_t src_length_mono = src_length / num_channels_; Deinterleave(src, source_view_);
const size_t dst_capacity_mono = dst_capacity / num_channels_;
for (size_t ch = 0; ch < num_channels_; ++ch) { for (size_t i = 0; i < resamplers_.size(); ++i) {
channel_data_array_[ch] = channel_resamplers_[ch].source.data(); size_t dst_length_mono =
resamplers_[i]->Resample(source_view_[i], destination_view_[i]);
RTC_DCHECK_EQ(dst_length_mono, SamplesPerChannel(dst));
} }
Deinterleave(src, src_length_mono, num_channels_, channel_data_array_.data()); Interleave<T>(destination_view_, dst);
return static_cast<int>(dst.size());
}
size_t dst_length_mono = 0; template <typename T>
int PushResampler<T>::Resample(MonoView<const T> src, MonoView<T> dst) {
RTC_DCHECK_EQ(resamplers_.size(), 1);
RTC_DCHECK_EQ(SamplesPerChannel(src), SamplesPerChannel(source_view_));
RTC_DCHECK_EQ(SamplesPerChannel(dst), SamplesPerChannel(destination_view_));
for (auto& resampler : channel_resamplers_) { if (SamplesPerChannel(src) == SamplesPerChannel(dst)) {
dst_length_mono = resampler.resampler->Resample( CopySamples(dst, src);
resampler.source.data(), src_length_mono, resampler.destination.data(), return static_cast<int>(src.size());
dst_capacity_mono);
} }
for (size_t ch = 0; ch < num_channels_; ++ch) { return resamplers_[0]->Resample(src, dst);
channel_data_array_[ch] = channel_resamplers_[ch].destination.data();
}
Interleave(channel_data_array_.data(), dst_length_mono, num_channels_, dst);
return static_cast<int>(dst_length_mono * num_channels_);
} }
// Explictly generate required instantiations. // Explictly generate required instantiations.

View File

@ -63,12 +63,12 @@ size_t PushSincResampler::Resample(const float* source,
// request through Run(). // request through Run().
// //
// If this wasn't done, SincResampler would call Run() twice on the first // If this wasn't done, SincResampler would call Run() twice on the first
// pass, and we'd have to introduce an entire |source_frames| of delay, rather // pass, and we'd have to introduce an entire `source_frames` of delay, rather
// than the minimum half kernel. // than the minimum half kernel.
// //
// It works out that ChunkSize() is exactly the amount of output we need to // It works out that ChunkSize() is exactly the amount of output we need to
// request in order to prime the buffer with a single Run() request for // request in order to prime the buffer with a single Run() request for
// |source_frames|. // `source_frames`.
if (first_pass_) if (first_pass_)
resampler_->Resample(resampler_->ChunkSize(), destination); resampler_->Resample(resampler_->ChunkSize(), destination);

View File

@ -16,8 +16,8 @@
#include <memory> #include <memory>
#include "api/audio/audio_view.h"
#include "common_audio/resampler/sinc_resampler.h" #include "common_audio/resampler/sinc_resampler.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc { namespace webrtc {
@ -33,11 +33,20 @@ class PushSincResampler : public SincResamplerCallback {
PushSincResampler(size_t source_frames, size_t destination_frames); PushSincResampler(size_t source_frames, size_t destination_frames);
~PushSincResampler() override; ~PushSincResampler() override;
// Perform the resampling. |source_frames| must always equal the PushSincResampler(const PushSincResampler&) = delete;
// |source_frames| provided at construction. |destination_capacity| must be PushSincResampler& operator=(const PushSincResampler&) = delete;
// at least as large as |destination_frames|. Returns the number of samples
// Perform the resampling. `source_frames` must always equal the
// `source_frames` provided at construction. `destination_capacity` must be
// at least as large as `destination_frames`. Returns the number of samples
// provided in destination (for convenience, since this will always be equal // provided in destination (for convenience, since this will always be equal
// to |destination_frames|). // to `destination_frames`).
template <typename S, typename D>
size_t Resample(const MonoView<S>& source, const MonoView<D>& destination) {
return Resample(&source[0], SamplesPerChannel(source), &destination[0],
SamplesPerChannel(destination));
}
size_t Resample(const int16_t* source, size_t Resample(const int16_t* source,
size_t source_frames, size_t source_frames,
int16_t* destination, int16_t* destination,
@ -72,8 +81,6 @@ class PushSincResampler : public SincResamplerCallback {
// Used to assert we are only requested for as much data as is available. // Used to assert we are only requested for as much data as is available.
size_t source_available_; size_t source_available_;
RTC_DISALLOW_COPY_AND_ASSIGN(PushSincResampler);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -916,7 +916,6 @@ int Resampler::Push(const int16_t* samplesIn,
outLen = (lengthIn * 8) / 11; outLen = (lengthIn * 8) / 11;
free(tmp_mem); free(tmp_mem);
return 0; return 0;
break;
} }
return 0; return 0;
} }

View File

@ -80,7 +80,7 @@
// 8) Else, if we're not on the second load, goto (4). // 8) Else, if we're not on the second load, goto (4).
// //
// Note: we're glossing over how the sub-sample handling works with // Note: we're glossing over how the sub-sample handling works with
// |virtual_source_idx_|, etc. // `virtual_source_idx_`, etc.
// MSVC++ requires this to be set before any other includes to get M_PI. // MSVC++ requires this to be set before any other includes to get M_PI.
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
@ -102,7 +102,7 @@ namespace webrtc {
namespace { namespace {
double SincScaleFactor(double io_ratio) { double SincScaleFactor(double io_ratio) {
// |sinc_scale_factor| is basically the normalized cutoff frequency of the // `sinc_scale_factor` is basically the normalized cutoff frequency of the
// low-pass filter. // low-pass filter.
double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0; double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0;
@ -126,8 +126,8 @@ void SincResampler::InitializeCPUSpecificFeatures() {
#if defined(WEBRTC_HAS_NEON) #if defined(WEBRTC_HAS_NEON)
convolve_proc_ = Convolve_NEON; convolve_proc_ = Convolve_NEON;
#elif defined(WEBRTC_ARCH_X86_FAMILY) #elif defined(WEBRTC_ARCH_X86_FAMILY)
// Using AVX2 instead of SSE2 when AVX2 supported. // Using AVX2 instead of SSE2 when AVX2/FMA3 supported.
if (GetCPUInfo(kAVX2)) if (GetCPUInfo(kAVX2) && GetCPUInfo(kFMA3))
convolve_proc_ = Convolve_AVX2; convolve_proc_ = Convolve_AVX2;
else if (GetCPUInfo(kSSE2)) else if (GetCPUInfo(kSSE2))
convolve_proc_ = Convolve_SSE; convolve_proc_ = Convolve_SSE;
@ -238,7 +238,7 @@ void SincResampler::SetRatio(double io_sample_rate_ratio) {
io_sample_rate_ratio_ = io_sample_rate_ratio; io_sample_rate_ratio_ = io_sample_rate_ratio;
// Optimize reinitialization by reusing values which are independent of // Optimize reinitialization by reusing values which are independent of
// |sinc_scale_factor|. Provides a 3x speedup. // `sinc_scale_factor`. Provides a 3x speedup.
const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_);
for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) {
for (size_t i = 0; i < kKernelSize; ++i) { for (size_t i = 0; i < kKernelSize; ++i) {
@ -268,8 +268,8 @@ void SincResampler::Resample(size_t frames, float* destination) {
const double current_io_ratio = io_sample_rate_ratio_; const double current_io_ratio = io_sample_rate_ratio_;
const float* const kernel_ptr = kernel_storage_.get(); const float* const kernel_ptr = kernel_storage_.get();
while (remaining_frames) { while (remaining_frames) {
// |i| may be negative if the last Resample() call ended on an iteration // `i` may be negative if the last Resample() call ended on an iteration
// that put |virtual_source_idx_| over the limit. // that put `virtual_source_idx_` over the limit.
// //
// Note: The loop construct here can severely impact performance on ARM // Note: The loop construct here can severely impact performance on ARM
// or when built with clang. See https://codereview.chromium.org/18566009/ // or when built with clang. See https://codereview.chromium.org/18566009/
@ -278,7 +278,7 @@ void SincResampler::Resample(size_t frames, float* destination) {
i > 0; --i) { i > 0; --i) {
RTC_DCHECK_LT(virtual_source_idx_, block_size_); RTC_DCHECK_LT(virtual_source_idx_, block_size_);
// |virtual_source_idx_| lies in between two kernel offsets so figure out // `virtual_source_idx_` lies in between two kernel offsets so figure out
// what they are. // what they are.
const int source_idx = static_cast<int>(virtual_source_idx_); const int source_idx = static_cast<int>(virtual_source_idx_);
const double subsample_remainder = virtual_source_idx_ - source_idx; const double subsample_remainder = virtual_source_idx_ - source_idx;
@ -288,16 +288,16 @@ void SincResampler::Resample(size_t frames, float* destination) {
const int offset_idx = static_cast<int>(virtual_offset_idx); const int offset_idx = static_cast<int>(virtual_offset_idx);
// We'll compute "convolutions" for the two kernels which straddle // We'll compute "convolutions" for the two kernels which straddle
// |virtual_source_idx_|. // `virtual_source_idx_`.
const float* const k1 = kernel_ptr + offset_idx * kKernelSize; const float* const k1 = kernel_ptr + offset_idx * kKernelSize;
const float* const k2 = k1 + kKernelSize; const float* const k2 = k1 + kKernelSize;
// Ensure |k1|, |k2| are 32-byte aligned for SIMD usage. Should always be // Ensure `k1`, `k2` are 32-byte aligned for SIMD usage. Should always be
// true so long as kKernelSize is a multiple of 32. // true so long as kKernelSize is a multiple of 32.
RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k1) % 32); RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k1) % 32);
RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k2) % 32); RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k2) % 32);
// Initialize input pointer based on quantized |virtual_source_idx_|. // Initialize input pointer based on quantized `virtual_source_idx_`.
const float* const input_ptr = r1_ + source_idx; const float* const input_ptr = r1_ + source_idx;
// Figure out how much to weight each kernel's "convolution". // Figure out how much to weight each kernel's "convolution".

View File

@ -18,15 +18,14 @@
#include <memory> #include <memory>
#include "rtc_base/constructor_magic.h"
#include "rtc_base/gtest_prod_util.h" #include "rtc_base/gtest_prod_util.h"
#include "rtc_base/memory/aligned_malloc.h" #include "rtc_base/memory/aligned_malloc.h"
#include "rtc_base/system/arch.h" #include "rtc_base/system/arch.h"
namespace webrtc { namespace webrtc {
// Callback class for providing more data into the resampler. Expects |frames| // Callback class for providing more data into the resampler. Expects `frames`
// of data to be rendered into |destination|; zero padded if not enough frames // of data to be rendered into `destination`; zero padded if not enough frames
// are available to satisfy the request. // are available to satisfy the request.
class SincResamplerCallback { class SincResamplerCallback {
public: public:
@ -53,10 +52,10 @@ class SincResampler {
static const size_t kKernelStorageSize = static const size_t kKernelStorageSize =
kKernelSize * (kKernelOffsetCount + 1); kKernelSize * (kKernelOffsetCount + 1);
// Constructs a SincResampler with the specified |read_cb|, which is used to // Constructs a SincResampler with the specified `read_cb`, which is used to
// acquire audio data for resampling. |io_sample_rate_ratio| is the ratio // acquire audio data for resampling. `io_sample_rate_ratio` is the ratio
// of input / output sample rates. |request_frames| controls the size in // of input / output sample rates. `request_frames` controls the size in
// frames of the buffer requested by each |read_cb| call. The value must be // frames of the buffer requested by each `read_cb` call. The value must be
// greater than kKernelSize. Specify kDefaultRequestSize if there are no // greater than kKernelSize. Specify kDefaultRequestSize if there are no
// request size constraints. // request size constraints.
SincResampler(double io_sample_rate_ratio, SincResampler(double io_sample_rate_ratio,
@ -64,11 +63,14 @@ class SincResampler {
SincResamplerCallback* read_cb); SincResamplerCallback* read_cb);
virtual ~SincResampler(); virtual ~SincResampler();
// Resample |frames| of data from |read_cb_| into |destination|. SincResampler(const SincResampler&) = delete;
SincResampler& operator=(const SincResampler&) = delete;
// Resample `frames` of data from `read_cb_` into `destination`.
void Resample(size_t frames, float* destination); void Resample(size_t frames, float* destination);
// The maximum size in frames that guarantees Resample() will only make a // The maximum size in frames that guarantees Resample() will only make a
// single call to |read_cb_| for more data. // single call to `read_cb_` for more data.
size_t ChunkSize() const; size_t ChunkSize() const;
size_t request_frames() const { return request_frames_; } size_t request_frames() const { return request_frames_; }
@ -77,12 +79,12 @@ class SincResampler {
// not call while Resample() is in progress. // not call while Resample() is in progress.
void Flush(); void Flush();
// Update |io_sample_rate_ratio_|. SetRatio() will cause a reconstruction of // Update `io_sample_rate_ratio_`. SetRatio() will cause a reconstruction of
// the kernels used for resampling. Not thread safe, do not call while // the kernels used for resampling. Not thread safe, do not call while
// Resample() is in progress. // Resample() is in progress.
// //
// TODO(ajm): Use this in PushSincResampler rather than reconstructing // TODO(ajm): Use this in PushSincResampler rather than reconstructing
// SincResampler. We would also need a way to update |request_frames_|. // SincResampler. We would also need a way to update `request_frames_`.
void SetRatio(double io_sample_rate_ratio); void SetRatio(double io_sample_rate_ratio);
float* get_kernel_for_testing() { return kernel_storage_.get(); } float* get_kernel_for_testing() { return kernel_storage_.get(); }
@ -97,11 +99,11 @@ class SincResampler {
// Selects runtime specific CPU features like SSE. Must be called before // Selects runtime specific CPU features like SSE. Must be called before
// using SincResampler. // using SincResampler.
// TODO(ajm): Currently managed by the class internally. See the note with // TODO(ajm): Currently managed by the class internally. See the note with
// |convolve_proc_| below. // `convolve_proc_` below.
void InitializeCPUSpecificFeatures(); void InitializeCPUSpecificFeatures();
// Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are // Compute convolution of `k1` and `k2` over `input_ptr`, resultant sums are
// linearly interpolated using |kernel_interpolation_factor|. On x86 and ARM // linearly interpolated using `kernel_interpolation_factor`. On x86 and ARM
// the underlying implementation is chosen at run time. // the underlying implementation is chosen at run time.
static float Convolve_C(const float* input_ptr, static float Convolve_C(const float* input_ptr,
const float* k1, const float* k1,
@ -136,7 +138,7 @@ class SincResampler {
// Source of data for resampling. // Source of data for resampling.
SincResamplerCallback* read_cb_; SincResamplerCallback* read_cb_;
// The size (in samples) to request from each |read_cb_| execution. // The size (in samples) to request from each `read_cb_` execution.
const size_t request_frames_; const size_t request_frames_;
// The number of source frames processed per pass. // The number of source frames processed per pass.
@ -155,25 +157,23 @@ class SincResampler {
// Data from the source is copied into this buffer for each processing pass. // Data from the source is copied into this buffer for each processing pass.
std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_; std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_;
// Stores the runtime selection of which Convolve function to use. // Stores the runtime selection of which Convolve function to use.
// TODO(ajm): Move to using a global static which must only be initialized // TODO(ajm): Move to using a global static which must only be initialized
// once by the user. We're not doing this initially, because we don't have // once by the user. We're not doing this initially, because we don't have
// e.g. a LazyInstance helper in webrtc. // e.g. a LazyInstance helper in webrtc.
typedef float (*ConvolveProc)(const float*, typedef float (*ConvolveProc)(const float*,
const float*, const float*,
const float*, const float*,
double); double);
ConvolveProc convolve_proc_; ConvolveProc convolve_proc_;
// Pointers to the various regions inside |input_buffer_|. See the diagram at // Pointers to the various regions inside `input_buffer_`. See the diagram at
// the top of the .cc file for more information. // the top of the .cc file for more information.
float* r0_; float* r0_;
float* const r1_; float* const r1_;
float* const r2_; float* const r2_;
float* r3_; float* r3_;
float* r4_; float* r4_;
RTC_DISALLOW_COPY_AND_ASSIGN(SincResampler);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -25,7 +25,7 @@ float SincResampler::Convolve_AVX2(const float* input_ptr,
__m256 m_sums1 = _mm256_setzero_ps(); __m256 m_sums1 = _mm256_setzero_ps();
__m256 m_sums2 = _mm256_setzero_ps(); __m256 m_sums2 = _mm256_setzero_ps();
// Based on |input_ptr| alignment, we need to use loadu or load. Unrolling // Based on `input_ptr` alignment, we need to use loadu or load. Unrolling
// these loops has not been tested or benchmarked. // these loops has not been tested or benchmarked.
bool aligned_input = (reinterpret_cast<uintptr_t>(input_ptr) & 0x1F) == 0; bool aligned_input = (reinterpret_cast<uintptr_t>(input_ptr) & 0x1F) == 0;
if (!aligned_input) { if (!aligned_input) {

View File

@ -27,7 +27,7 @@ float SincResampler::Convolve_SSE(const float* input_ptr,
__m128 m_sums1 = _mm_setzero_ps(); __m128 m_sums1 = _mm_setzero_ps();
__m128 m_sums2 = _mm_setzero_ps(); __m128 m_sums2 = _mm_setzero_ps();
// Based on |input_ptr| alignment, we need to use loadu or load. Unrolling // Based on `input_ptr` alignment, we need to use loadu or load. Unrolling
// these loops hurt performance in local testing. // these loops hurt performance in local testing.
if (reinterpret_cast<uintptr_t>(input_ptr) & 0x0F) { if (reinterpret_cast<uintptr_t>(input_ptr) & 0x0F) {
for (size_t i = 0; i < kKernelSize; i += 4) { for (size_t i = 0; i < kKernelSize; i += 4) {

View File

@ -15,7 +15,6 @@
#define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ #define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
#include "common_audio/resampler/sinc_resampler.h" #include "common_audio/resampler/sinc_resampler.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc { namespace webrtc {
@ -24,7 +23,7 @@ namespace webrtc {
// resampler for the specific sample rate conversion being used. // resampler for the specific sample rate conversion being used.
class SinusoidalLinearChirpSource : public SincResamplerCallback { class SinusoidalLinearChirpSource : public SincResamplerCallback {
public: public:
// |delay_samples| can be used to insert a fractional sample delay into the // `delay_samples` can be used to insert a fractional sample delay into the
// source. It will produce zeros until non-negative time is reached. // source. It will produce zeros until non-negative time is reached.
SinusoidalLinearChirpSource(int sample_rate, SinusoidalLinearChirpSource(int sample_rate,
size_t samples, size_t samples,
@ -33,12 +32,16 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback {
~SinusoidalLinearChirpSource() override {} ~SinusoidalLinearChirpSource() override {}
SinusoidalLinearChirpSource(const SinusoidalLinearChirpSource&) = delete;
SinusoidalLinearChirpSource& operator=(const SinusoidalLinearChirpSource&) =
delete;
void Run(size_t frames, float* destination) override; void Run(size_t frames, float* destination) override;
double Frequency(size_t position); double Frequency(size_t position);
private: private:
enum { kMinFrequency = 5 }; static constexpr int kMinFrequency = 5;
int sample_rate_; int sample_rate_;
size_t total_samples_; size_t total_samples_;
@ -46,8 +49,6 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback {
double k_; double k_;
size_t current_index_; size_t current_index_;
double delay_samples_; double delay_samples_;
RTC_DISALLOW_COPY_AND_ASSIGN(SinusoidalLinearChirpSource);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -18,9 +18,9 @@
#include <string.h> #include <string.h>
// Get address of region(s) from which we can read data. // Get address of region(s) from which we can read data.
// If the region is contiguous, |data_ptr_bytes_2| will be zero. // If the region is contiguous, `data_ptr_bytes_2` will be zero.
// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second // If non-contiguous, `data_ptr_bytes_2` will be the size in bytes of the second
// region. Returns room available to be read or |element_count|, whichever is // region. Returns room available to be read or `element_count`, whichever is
// smaller. // smaller.
static size_t GetBufferReadRegions(RingBuffer* buf, static size_t GetBufferReadRegions(RingBuffer* buf,
size_t element_count, size_t element_count,
@ -120,7 +120,7 @@ size_t WebRtc_ReadBuffer(RingBuffer* self,
&buf_ptr_bytes_2); &buf_ptr_bytes_2);
if (buf_ptr_bytes_2 > 0) { if (buf_ptr_bytes_2 > 0) {
// We have a wrap around when reading the buffer. Copy the buffer data to // We have a wrap around when reading the buffer. Copy the buffer data to
// |data| and point to it. // `data` and point to it.
memcpy(data, buf_ptr_1, buf_ptr_bytes_1); memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
buf_ptr_1 = data; buf_ptr_1 = data;
@ -129,7 +129,7 @@ size_t WebRtc_ReadBuffer(RingBuffer* self,
memcpy(data, buf_ptr_1, buf_ptr_bytes_1); memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
} }
if (data_ptr) { if (data_ptr) {
// |buf_ptr_1| == |data| in the case of a wrap. // `buf_ptr_1` == `data` in the case of a wrap.
*data_ptr = read_count == 0 ? NULL : buf_ptr_1; *data_ptr = read_count == 0 ? NULL : buf_ptr_1;
} }

View File

@ -39,14 +39,14 @@ void WebRtc_InitBuffer(RingBuffer* handle);
void WebRtc_FreeBuffer(void* handle); void WebRtc_FreeBuffer(void* handle);
// Reads data from the buffer. Returns the number of elements that were read. // Reads data from the buffer. Returns the number of elements that were read.
// The |data_ptr| will point to the address where the read data is located. // The `data_ptr` will point to the address where the read data is located.
// If no data can be read, |data_ptr| is set to |NULL|. If all data can be read // If no data can be read, `data_ptr` is set to `NULL`. If all data can be read
// without buffer wrap around then |data_ptr| will point to the location in the // without buffer wrap around then `data_ptr` will point to the location in the
// buffer. Otherwise, the data will be copied to |data| (memory allocation done // buffer. Otherwise, the data will be copied to `data` (memory allocation done
// by the user) and |data_ptr| points to the address of |data|. |data_ptr| is // by the user) and `data_ptr` points to the address of `data`. `data_ptr` is
// only guaranteed to be valid until the next call to WebRtc_WriteBuffer(). // only guaranteed to be valid until the next call to WebRtc_WriteBuffer().
// //
// To force a copying to |data|, pass a null |data_ptr|. // To force a copying to `data`, pass a null `data_ptr`.
// //
// Returns number of elements read. // Returns number of elements read.
size_t WebRtc_ReadBuffer(RingBuffer* handle, size_t WebRtc_ReadBuffer(RingBuffer* handle,
@ -54,14 +54,14 @@ size_t WebRtc_ReadBuffer(RingBuffer* handle,
void* data, void* data,
size_t element_count); size_t element_count);
// Writes |data| to buffer and returns the number of elements written. // Writes `data` to buffer and returns the number of elements written.
size_t WebRtc_WriteBuffer(RingBuffer* handle, size_t WebRtc_WriteBuffer(RingBuffer* handle,
const void* data, const void* data,
size_t element_count); size_t element_count);
// Moves the buffer read position and returns the number of elements moved. // Moves the buffer read position and returns the number of elements moved.
// Positive |element_count| moves the read position towards the write position, // Positive `element_count` moves the read position towards the write position,
// that is, flushing the buffer. Negative |element_count| moves the read // that is, flushing the buffer. Negative `element_count` moves the read
// position away from the the write position, that is, stuffing the buffer. // position away from the the write position, that is, stuffing the buffer.
// Returns number of elements moved. // Returns number of elements moved.
int WebRtc_MoveReadPtr(RingBuffer* handle, int element_count); int WebRtc_MoveReadPtr(RingBuffer* handle, int element_count);

View File

@ -72,9 +72,9 @@ void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation,
size_t dim_cross_correlation, size_t dim_cross_correlation,
int right_shifts, int right_shifts,
int step_seq2) { int step_seq2) {
size_t i = 0; int i = 0;
for (i = 0; i < dim_cross_correlation; i++) { for (i = 0; i < (int)dim_cross_correlation; i++) {
const int16_t* seq1_ptr = seq1; const int16_t* seq1_ptr = seq1;
const int16_t* seq2_ptr = seq2 + (step_seq2 * i); const int16_t* seq2_ptr = seq2 + (step_seq2 * i);

View File

@ -98,8 +98,7 @@ int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
return div; return div;
} }
int32_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
{ {
int16_t approx, tmp_hi, tmp_low, num_hi, num_low; int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
int32_t tmpW32; int32_t tmpW32;
@ -111,8 +110,8 @@ WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1); tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1);
// tmpW32 = den * approx // tmpW32 = den * approx
tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx)) // result in Q30 (tmpW32 = 2.0-(den*approx))
// UBSan: 2147483647 - -2 cannot be represented in type 'int' tmpW32 = (int32_t)((int64_t)0x7fffffffL - tmpW32);
// Store tmpW32 in hi and low format // Store tmpW32 in hi and low format
tmp_hi = (int16_t)(tmpW32 >> 16); tmp_hi = (int16_t)(tmpW32 >> 16);

View File

@ -26,7 +26,7 @@ extern "C" {
// - vector_length : Number of samples used in the dot product // - vector_length : Number of samples used in the dot product
// - scaling : The number of right bit shifts to apply on each term // - scaling : The number of right bit shifts to apply on each term
// during calculation to avoid overflow, i.e., the // during calculation to avoid overflow, i.e., the
// output will be in Q(-|scaling|) // output will be in Q(-`scaling`)
// //
// Return value : The dot product in Q(-scaling) // Return value : The dot product in Q(-scaling)
int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1, int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,

View File

@ -8,9 +8,11 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <arm_neon.h>
#include "common_audio/signal_processing/include/signal_processing_library.h" #include "common_audio/signal_processing/include/signal_processing_library.h"
#include <arm_neon.h> #include "rtc_base/checks.h"
// NEON intrinsics version of WebRtcSpl_DownsampleFast() // NEON intrinsics version of WebRtcSpl_DownsampleFast()
// for ARM 32-bit/64-bit platforms. // for ARM 32-bit/64-bit platforms.
@ -22,19 +24,24 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
size_t coefficients_length, size_t coefficients_length,
int factor, int factor,
size_t delay) { size_t delay) {
size_t i = 0; // Using signed indexes to be able to compute negative i-j that
size_t j = 0; // is used to index data_in.
int i = 0;
int j = 0;
int32_t out_s32 = 0; int32_t out_s32 = 0;
size_t endpos = delay + factor * (data_out_length - 1) + 1; int endpos = delay + factor * (data_out_length - 1) + 1;
size_t res = data_out_length & 0x7; size_t res = data_out_length & 0x7;
size_t endpos1 = endpos - factor * res; int endpos1 = endpos - factor * res;
// Return error if any of the running conditions doesn't meet. // Return error if any of the running conditions doesn't meet.
if (data_out_length == 0 || coefficients_length == 0 if (data_out_length == 0 || coefficients_length == 0
|| data_in_length < endpos) { || (int)data_in_length < endpos) {
return -1; return -1;
} }
RTC_DCHECK_GE(endpos, 0);
RTC_DCHECK_GE(endpos1, 0);
// First part, unroll the loop 8 times, with 3 subcases // First part, unroll the loop 8 times, with 3 subcases
// (factor == 2, 4, others). // (factor == 2, 4, others).
switch (factor) { switch (factor) {
@ -46,7 +53,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
#if defined(WEBRTC_ARCH_ARM64) #if defined(WEBRTC_ARCH_ARM64)
// Unroll the loop 2 times. // Unroll the loop 2 times.
for (j = 0; j < coefficients_length - 1; j += 2) { for (j = 0; j < (int)coefficients_length - 1; j += 2) {
int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]); int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]);
int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32); int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32);
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]);
@ -68,7 +75,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0);
} }
for (; j < coefficients_length; j++) { for (; j < (int)coefficients_length; j++) {
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]);
@ -87,7 +94,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
#else #else
// On ARMv7, the loop unrolling 2 times results in performance // On ARMv7, the loop unrolling 2 times results in performance
// regression. // regression.
for (j = 0; j < coefficients_length; j++) { for (j = 0; j < (int)coefficients_length; j++) {
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]);
@ -114,7 +121,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
int32x4_t out32x4_1 = vdupq_n_s32(2048); int32x4_t out32x4_1 = vdupq_n_s32(2048);
// Unroll the loop 4 times. // Unroll the loop 4 times.
for (j = 0; j < coefficients_length - 3; j += 4) { for (j = 0; j < (int)coefficients_length - 3; j += 4) {
int16x4_t coeff16x4 = vld1_s16(&coefficients[j]); int16x4_t coeff16x4 = vld1_s16(&coefficients[j]);
int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]); int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]);
@ -143,7 +150,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0); out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0);
} }
for (; j < coefficients_length; j++) { for (; j < (int)coefficients_length; j++) {
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]); int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]);
@ -174,7 +181,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
int32x4_t out32x4_0 = vdupq_n_s32(2048); int32x4_t out32x4_0 = vdupq_n_s32(2048);
int32x4_t out32x4_1 = vdupq_n_s32(2048); int32x4_t out32x4_1 = vdupq_n_s32(2048);
for (j = 0; j < coefficients_length; j++) { for (j = 0; j < (int)coefficients_length; j++) {
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]); int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]);
in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1); in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1);
@ -204,7 +211,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
for (; i < endpos; i += factor) { for (; i < endpos; i += factor) {
out_s32 = 2048; // Round value, 0.5 in Q12. out_s32 = 2048; // Round value, 0.5 in Q12.
for (j = 0; j < coefficients_length; j++) { for (j = 0; j < (int)coefficients_length; j++) {
out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32); out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32);
} }

Some files were not shown because too many files have changed in this diff Show More