Skip to content

Commit dbe1b8e

Browse files
authored
feat: option to disable ffmpeg by flag (#813)
* feat: added flag * fix: test * feat: reverted streamer file * feat: expo plugin * feat: better expo plugin * fix: small typo in flag
1 parent 28d882e commit dbe1b8e

File tree

16 files changed

+179
-21
lines changed

16 files changed

+179
-21
lines changed

apps/fabric-example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3216,7 +3216,7 @@ SPEC CHECKSUMS:
32163216
ReactAppDependencyProvider: c5c4f5280e4ae0f9f4a739c64c4260fe0b3edaf1
32173217
ReactCodegen: 096bbbb2498ca55f385e2fbd465bfa0211ee8295
32183218
ReactCommon: 25c7f94aee74ddd93a8287756a8ac0830a309544
3219-
RNAudioAPI: d8a5bc076cb04272fbb9eee48d6cce69394b62c0
3219+
RNAudioAPI: c763dbacdb8d89b7ce829484306df54322a7d951
32203220
RNGestureHandler: f1dd7f92a0faa2868a919ab53bb9d66eb4ebfcf5
32213221
RNReanimated: e4993dd98196c698cbacc1441a4ac5b855ae56dc
32223222
RNScreens: 833237c48c756d40764540246a501b47dadb2cac

packages/audiodocs/docs/core/base-audio-context.mdx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,16 @@ Creates [`WorkletProcessingNode`](/docs/worklets/worklet-processing-node).
225225

226226
:::caution
227227
Supported file formats:
228-
- aac
229228
- flac
230-
- m4a
231229
- mp3
232-
- mp4
233230
- ogg
234231
- opus
235232
- wav
233+
- aac
234+
- m4a
235+
- mp4
236+
237+
Last three formats are decoded with ffmpeg, [see for more info](/docs/other/ffmpeg-info).
236238
:::
237239

238240
### `decodeAudioData`
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
sidebar_position: 5
3+
---
4+
5+
# FFmpeg additional information
6+
7+
We use [`ffmpeg`](https://github.com/FFmpeg/FFmpeg) for few components:
8+
- [`StreamerNode`](/docs/sources/streamer-node)
9+
- decoding `aac`, `mp4`, `m4a` files
10+
11+
## Disabling FFmpeg
12+
13+
The ffmpeg usage is enabled by default, however if you would like not to use it, f.e. there are some name clashes with other ffmpeg
14+
binaries in your project, you can easily disable it. Just add one flag in corresponding file.
15+
16+
## Expo projects
17+
18+
Add entry in [expo plugin](/docs/fundamentals/getting-started#step-2-add-audio-api-expo-plugin-optional). If not provided, default
19+
value is `false`.
20+
21+
```
22+
"disableFFmpeg": true
23+
```
24+
25+
## Non expo projects
26+
27+
### Android
28+
29+
gradle.properties
30+
```
31+
disableAudioapiFFmpeg=true
32+
```
33+
34+
### iOS
35+
36+
Podfile
37+
```
38+
ENV['DISABLE_AUDIOAPI_FFMPEG'] = '1'
39+
```

packages/react-native-audio-api/RNAudioAPI.podspec

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ require_relative './scripts/rnaa_utils'
44
package_json = JSON.parse(File.read(File.join(__dir__, "package.json")))
55

66
$new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
7+
$RN_AUDIO_API_FFMPEG_DISABLED = ENV['DISABLE_AUDIOAPI_FFMPEG'].nil? ? false : ENV['DISABLE_AUDIOAPI_FFMPEG'] == '1' # false by default
78

89
folly_flags = "-DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32"
910
fabric_flags = $new_arch_enabled ? '-DRCT_NEW_ARCH_ENABLED' : ''
1011
version_flag = "-DAUDIOAPI_VERSION=#{package_json['version']}"
1112

1213
worklets_preprocessor_flag = check_if_worklets_enabled() ? '-DRN_AUDIO_API_ENABLE_WORKLETS=1' : ''
14+
ffmpeg_flag = $RN_AUDIO_API_FFMPEG_DISABLED ? '-DRN_AUDIO_API_FFMPEG_DISABLED=1' : ''
1315

1416
Pod::Spec.new do |s|
1517
s.name = "RNAudioAPI"
@@ -24,6 +26,7 @@ Pod::Spec.new do |s|
2426

2527
s.subspec "audioapi" do |ss|
2628
ss.source_files = "common/cpp/audioapi/**/*.{cpp,c,h,hpp}"
29+
ss.exclude_files = $RN_AUDIO_API_FFMPEG_DISABLED ? ["common/cpp/audioapi/libs/ffmpeg/**"] : []
2730
ss.header_dir = "audioapi"
2831
ss.header_mappings_dir = "common/cpp/audioapi"
2932

@@ -57,7 +60,7 @@ Pod::Spec.new do |s|
5760
external_dir_relative = "common/cpp/audioapi/external"
5861
lib_dir = "$(PROJECT_DIR)/#{rn_audio_dir_relative}/#{external_dir_relative}/$(PLATFORM_NAME)"
5962

60-
s.ios.vendored_frameworks = [
63+
s.ios.vendored_frameworks = $RN_AUDIO_API_FFMPEG_DISABLED ? [] : [
6164
'common/cpp/audioapi/external/ffmpeg_ios/libavcodec.xcframework',
6265
'common/cpp/audioapi/external/ffmpeg_ios/libavformat.xcframework',
6366
'common/cpp/audioapi/external/ffmpeg_ios/libavutil.xcframework',
@@ -75,10 +78,9 @@ s.pod_target_xcconfig = {
7578
$(PODS_TARGET_SRCROOT)/#{external_dir_relative}/include
7679
$(PODS_TARGET_SRCROOT)/#{external_dir_relative}/include/opus
7780
$(PODS_TARGET_SRCROOT)/#{external_dir_relative}/include/vorbis
78-
$(PODS_TARGET_SRCROOT)/#{external_dir_relative}/ffmpeg_include
79-
].join(" "),
80-
'OTHER_CFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag}",
81-
'OTHER_CPLUSPLUSFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag}",
81+
].concat($RN_AUDIO_API_FFMPEG_DISABLED ? [] : ["$(PODS_TARGET_SRCROOT)/#{external_dir_relative}/ffmpeg_include"]).join(" "),
82+
'OTHER_CFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag} #{ffmpeg_flag}",
83+
'OTHER_CPLUSPLUSFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag} #{ffmpeg_flag}",
8284
}
8385

8486
s.user_target_xcconfig = {

packages/react-native-audio-api/android/build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def isNewArchitectureEnabled() {
2121
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
2222
}
2323

24+
def isFFmpegDisabled() {
25+
return rootProject.hasProperty("disableAudioapiFFmpeg") && rootProject.getProperty("disableAudioapiFFmpeg") == "true"
26+
}
27+
2428
apply plugin: "com.android.library"
2529
apply plugin: 'org.jetbrains.kotlin.android'
2630

@@ -124,6 +128,7 @@ file("$reactNativeRootDir/ReactAndroid/gradle.properties").withInputStream { rea
124128
def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME")
125129
def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger()
126130
def IS_NEW_ARCHITECTURE_ENABLED = isNewArchitectureEnabled()
131+
def IS_RN_AUDIO_API_FFMPEG_DISABLED = isFFmpegDisabled()
127132

128133
android {
129134
sourceSets {
@@ -163,8 +168,9 @@ android {
163168
"-DANDROID_TOOLCHAIN=clang",
164169
"-DREACT_NATIVE_DIR=${toPlatformFileString(reactNativeRootDir.path)}",
165170
"-DRN_AUDIO_API_WORKLETS_ENABLED=${isWorkletsAvailable}",
166-
"-DIS_NEW_ARCHITECTURE_ENABLED=${IS_NEW_ARCHITECTURE_ENABLED}",
167-
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
171+
"-DIS_NEW_ARCHITECTURE_ENABLED=${IS_NEW_ARCHITECTURE_ENABLED}",
172+
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON",
173+
"-DRN_AUDIO_API_FFMPEG_DISABLED=${IS_RN_AUDIO_API_FFMPEG_DISABLED}"
168174
]
169175

170176
if (isWorkletsAvailable) {

packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212

1313
#ifndef AUDIO_API_TEST_SUITE
1414
#include <android/log.h>
15+
#endif // AUDIO_API_TEST_SUITE
16+
#if !RN_AUDIO_API_FFMPEG_DISABLED
1517
#include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
16-
#endif
18+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
1719

1820
#include <memory>
1921
#include <string>
@@ -73,13 +75,22 @@ std::shared_ptr<AudioBuffer> AudioDecoder::decodeWithFilePath(
7375
float sampleRate) {
7476
#ifndef AUDIO_API_TEST_SUITE
7577
if (AudioDecoder::pathHasExtension(path, {".mp4", ".m4a", ".aac"})) {
78+
#if !RN_AUDIO_API_FFMPEG_DISABLED
7679
auto buffer = ffmpegdecoder::decodeWithFilePath(path, static_cast<int>(sampleRate));
7780
if (buffer == nullptr) {
7881
__android_log_print(
7982
ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode with FFmpeg: %s", path.c_str());
8083
return nullptr;
8184
}
8285
return buffer;
86+
#else
87+
__android_log_print(
88+
ANDROID_LOG_ERROR,
89+
"AudioDecoder",
90+
"FFmpeg is disabled, cannot decode file: %s",
91+
path.c_str());
92+
return nullptr;
93+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
8394
}
8495
ma_decoder decoder;
8596
ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, static_cast<int>(sampleRate));
@@ -115,12 +126,18 @@ AudioDecoder::decodeWithMemoryBlock(const void *data, size_t size, float sampleR
115126
#ifndef AUDIO_API_TEST_SUITE
116127
const AudioFormat format = AudioDecoder::detectAudioFormat(data, size);
117128
if (format == AudioFormat::MP4 || format == AudioFormat::M4A || format == AudioFormat::AAC) {
129+
#if !RN_AUDIO_API_FFMPEG_DISABLED
118130
auto buffer = ffmpegdecoder::decodeWithMemoryBlock(data, size, static_cast<int>(sampleRate));
119131
if (buffer == nullptr) {
120132
__android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode with FFmpeg");
121133
return nullptr;
122134
}
123135
return buffer;
136+
#else
137+
__android_log_print(
138+
ANDROID_LOG_ERROR, "AudioDecoder", "FFmpeg is disabled, cannot decode memory block");
139+
return nullptr;
140+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
124141
}
125142
ma_decoder decoder;
126143
ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, static_cast<int>(sampleRate));

packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,15 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createOscillator) {
159159
}
160160

161161
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createStreamer) {
162+
#if !RN_AUDIO_API_FFMPEG_DISABLED
162163
auto streamer = context_->createStreamer();
163164
auto streamerHostObject = std::make_shared<StreamerNodeHostObject>(streamer);
164165
auto object = jsi::Object::createFromHostObject(runtime, streamerHostObject);
165166
object.setExternalMemoryPressure(runtime, StreamerNodeHostObject::getSizeInBytes());
166167
return object;
168+
#else
169+
return jsi::Value::undefined();
170+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
167171
}
168172

169173
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createConstantSource) {

packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ StreamerNodeHostObject::StreamerNodeHostObject(const std::shared_ptr<StreamerNod
1313
}
1414

1515
JSI_HOST_FUNCTION_IMPL(StreamerNodeHostObject, initialize) {
16+
#if !RN_AUDIO_API_FFMPEG_DISABLED
1617
auto streamerNode = std::static_pointer_cast<StreamerNode>(node_);
1718
auto path = args[0].getString(runtime).utf8(runtime);
1819
auto result = streamerNode->initialize(path);
1920
return {result};
21+
#else
22+
return false;
23+
#endif
2024
}
2125

2226
} // namespace audioapi

packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#include <audioapi/core/sources/ConstantSourceNode.h>
1414
#include <audioapi/core/sources/OscillatorNode.h>
1515
#include <audioapi/core/sources/RecorderAdapterNode.h>
16+
#if !RN_AUDIO_API_FFMPEG_DISABLED
1617
#include <audioapi/core/sources/StreamerNode.h>
18+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
1719
#include <audioapi/core/sources/WorkletSourceNode.h>
1820
#include <audioapi/core/utils/AudioDecoder.h>
1921
#include <audioapi/core/utils/AudioNodeManager.h>
@@ -121,13 +123,15 @@ std::shared_ptr<ConstantSourceNode> BaseAudioContext::createConstantSource() {
121123
return constantSource;
122124
}
123125

124-
#ifndef AUDIO_API_TEST_SUITE
125126
std::shared_ptr<StreamerNode> BaseAudioContext::createStreamer() {
127+
#if !RN_AUDIO_API_FFMPEG_DISABLED
126128
auto streamer = std::make_shared<StreamerNode>(this);
127129
nodeManager_->addSourceNode(streamer);
128130
return streamer;
131+
#else
132+
return nullptr;
133+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
129134
}
130-
#endif
131135

132136
std::shared_ptr<GainNode> BaseAudioContext::createGain() {
133137
auto gain = std::make_shared<GainNode>(this);

packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include <audioapi/core/sources/AudioScheduledSourceNode.h>
1414
#include <audioapi/utils/AudioBus.h>
1515

16-
#ifndef AUDIO_API_TEST_SUITE
16+
#if !RN_AUDIO_API_FFMPEG_DISABLED
1717
extern "C" {
1818
#include <libavcodec/avcodec.h>
1919
#include <libavformat/avformat.h>
@@ -22,7 +22,7 @@ extern "C" {
2222
#include <libavutil/samplefmt.h>
2323
#include <libswresample/swresample.h>
2424
}
25-
#endif
25+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
2626

2727
#include <atomic>
2828
#include <cmath>
@@ -36,7 +36,7 @@ static constexpr audioapi::channels::spsc::OverflowStrategy STREAMER_NODE_SPSC_O
3636
audioapi::channels::spsc::OverflowStrategy::WAIT_ON_FULL;
3737
static constexpr audioapi::channels::spsc::WaitStrategy STREAMER_NODE_SPSC_WAIT_STRATEGY =
3838
audioapi::channels::spsc::WaitStrategy::ATOMIC_WAIT;
39-
#endif
39+
#endif // AUDIO_API_TEST_SUITE
4040

4141
static constexpr bool VERBOSE = false;
4242
static constexpr int CHANNEL_CAPACITY = 32;
@@ -78,7 +78,7 @@ class StreamerNode : public AudioScheduledSourceNode {
7878
int framesToProcess) override;
7979

8080
private:
81-
#ifndef AUDIO_API_TEST_SUITE
81+
#if !RN_AUDIO_API_FFMPEG_DISABLED
8282
AVFormatContext *fmtCtx_;
8383
AVCodecContext *codecCtx_;
8484
const AVCodec *decoder_;
@@ -149,6 +149,6 @@ class StreamerNode : public AudioScheduledSourceNode {
149149
* @return true if successful, false otherwise
150150
*/
151151
bool setupDecoder();
152-
#endif // AUDIO_API_TEST_SUITE
152+
#endif // RN_AUDIO_API_FFMPEG_DISABLED
153153
};
154154
} // namespace audioapi

0 commit comments

Comments
 (0)