diff --git a/apps/fabric-example/ios/Podfile.lock b/apps/fabric-example/ios/Podfile.lock index e0fee10bd..218dc99f0 100644 --- a/apps/fabric-example/ios/Podfile.lock +++ b/apps/fabric-example/ios/Podfile.lock @@ -3216,7 +3216,7 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: c5c4f5280e4ae0f9f4a739c64c4260fe0b3edaf1 ReactCodegen: 096bbbb2498ca55f385e2fbd465bfa0211ee8295 ReactCommon: 25c7f94aee74ddd93a8287756a8ac0830a309544 - RNAudioAPI: d8a5bc076cb04272fbb9eee48d6cce69394b62c0 + RNAudioAPI: c763dbacdb8d89b7ce829484306df54322a7d951 RNGestureHandler: f1dd7f92a0faa2868a919ab53bb9d66eb4ebfcf5 RNReanimated: e4993dd98196c698cbacc1441a4ac5b855ae56dc RNScreens: 833237c48c756d40764540246a501b47dadb2cac diff --git a/packages/audiodocs/docs/core/base-audio-context.mdx b/packages/audiodocs/docs/core/base-audio-context.mdx index 8823f992d..b4d215af8 100644 --- a/packages/audiodocs/docs/core/base-audio-context.mdx +++ b/packages/audiodocs/docs/core/base-audio-context.mdx @@ -226,14 +226,16 @@ Creates [`BiquadFilterNode`](/docs/effects/biquad-filter-node). :::caution Supported file formats: -- aac - flac -- m4a - mp3 -- mp4 - ogg - opus - wav +- aac +- m4a +- mp4 + +Last three formats are decoded with ffmpeg, [see for more info](/docs/other/ffmpeg-info). ::: ### `decodeAudioData` diff --git a/packages/audiodocs/docs/other/ffmpeg-info.mdx b/packages/audiodocs/docs/other/ffmpeg-info.mdx new file mode 100644 index 000000000..8c305b58f --- /dev/null +++ b/packages/audiodocs/docs/other/ffmpeg-info.mdx @@ -0,0 +1,39 @@ +--- +sidebar_position: 5 +--- + +# FFmpeg additional information + +We use [`ffmpeg`](https://github.com/FFmpeg/FFmpeg) for few components: +- [`StreamerNode`](/docs/sources/streamer-node) +- decoding `aac`, `mp4`, `m4a` files + +## Disabling FFmpeg + +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 +binaries in your project, you can easily disable it. Just add one flag in corresponding file. + +## Expo projects + +Add entry in [expo plugin](/docs/fundamentals/getting-started#step-2-add-audio-api-expo-plugin-optional). If not provided, default +value is `false`. + +``` +"disableFFmpeg": true +``` + +## Non expo projects + +### Android + +gradle.properties +``` +disableAudioapiFFmpeg=true +``` + +### iOS + +Podfile +``` +ENV['DISABLE_AUDIOAPI_FFMPEG'] = '1' +``` diff --git a/packages/react-native-audio-api/RNAudioAPI.podspec b/packages/react-native-audio-api/RNAudioAPI.podspec index b86e6b87b..5cfe758ce 100644 --- a/packages/react-native-audio-api/RNAudioAPI.podspec +++ b/packages/react-native-audio-api/RNAudioAPI.podspec @@ -4,12 +4,14 @@ require_relative './scripts/rnaa_utils' package_json = JSON.parse(File.read(File.join(__dir__, "package.json"))) $new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' +$RN_AUDIO_API_FFMPEG_DISABLED = ENV['DISABLE_AUDIOAPI_FFMPEG'].nil? ? false : ENV['DISABLE_AUDIOAPI_FFMPEG'] == '1' # false by default folly_flags = "-DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32" fabric_flags = $new_arch_enabled ? '-DRCT_NEW_ARCH_ENABLED' : '' version_flag = "-DAUDIOAPI_VERSION=#{package_json['version']}" worklets_preprocessor_flag = check_if_worklets_enabled() ? '-DRN_AUDIO_API_ENABLE_WORKLETS=1' : '' +ffmpeg_flag = $RN_AUDIO_API_FFMPEG_DISABLED ? '-DRN_AUDIO_API_FFMPEG_DISABLED=1' : '' Pod::Spec.new do |s| s.name = "RNAudioAPI" @@ -24,6 +26,7 @@ Pod::Spec.new do |s| s.subspec "audioapi" do |ss| ss.source_files = "common/cpp/audioapi/**/*.{cpp,c,h,hpp}" + ss.exclude_files = $RN_AUDIO_API_FFMPEG_DISABLED ? ["common/cpp/audioapi/libs/ffmpeg/**"] : [] ss.header_dir = "audioapi" ss.header_mappings_dir = "common/cpp/audioapi" @@ -57,7 +60,7 @@ Pod::Spec.new do |s| external_dir_relative = "common/cpp/audioapi/external" lib_dir = "$(PROJECT_DIR)/#{rn_audio_dir_relative}/#{external_dir_relative}/$(PLATFORM_NAME)" - s.ios.vendored_frameworks = [ + s.ios.vendored_frameworks = $RN_AUDIO_API_FFMPEG_DISABLED ? [] : [ 'common/cpp/audioapi/external/ffmpeg_ios/libavcodec.xcframework', 'common/cpp/audioapi/external/ffmpeg_ios/libavformat.xcframework', 'common/cpp/audioapi/external/ffmpeg_ios/libavutil.xcframework', @@ -75,10 +78,9 @@ s.pod_target_xcconfig = { $(PODS_TARGET_SRCROOT)/#{external_dir_relative}/include $(PODS_TARGET_SRCROOT)/#{external_dir_relative}/include/opus $(PODS_TARGET_SRCROOT)/#{external_dir_relative}/include/vorbis - $(PODS_TARGET_SRCROOT)/#{external_dir_relative}/ffmpeg_include - ].join(" "), - 'OTHER_CFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag}", - 'OTHER_CPLUSPLUSFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag}", + ].concat($RN_AUDIO_API_FFMPEG_DISABLED ? [] : ["$(PODS_TARGET_SRCROOT)/#{external_dir_relative}/ffmpeg_include"]).join(" "), + 'OTHER_CFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag} #{ffmpeg_flag}", + 'OTHER_CPLUSPLUSFLAGS' => "$(inherited) #{folly_flags} #{fabric_flags} #{version_flag} #{worklets_preprocessor_flag} #{ffmpeg_flag}", } s.user_target_xcconfig = { diff --git a/packages/react-native-audio-api/android/build.gradle b/packages/react-native-audio-api/android/build.gradle index 6ff293ef9..cb82f4b8c 100644 --- a/packages/react-native-audio-api/android/build.gradle +++ b/packages/react-native-audio-api/android/build.gradle @@ -21,6 +21,10 @@ def isNewArchitectureEnabled() { return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" } +def isFFmpegDisabled() { + return rootProject.hasProperty("disableAudioapiFFmpeg") && rootProject.getProperty("disableAudioapiFFmpeg") == "true" +} + apply plugin: "com.android.library" apply plugin: 'org.jetbrains.kotlin.android' @@ -124,6 +128,7 @@ file("$reactNativeRootDir/ReactAndroid/gradle.properties").withInputStream { rea def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME") def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger() def IS_NEW_ARCHITECTURE_ENABLED = isNewArchitectureEnabled() +def IS_RN_AUDIO_API_FFMPEG_DISABLED = isFFmpegDisabled() android { sourceSets { @@ -163,8 +168,9 @@ android { "-DANDROID_TOOLCHAIN=clang", "-DREACT_NATIVE_DIR=${toPlatformFileString(reactNativeRootDir.path)}", "-DRN_AUDIO_API_WORKLETS_ENABLED=${isWorkletsAvailable}", - "-DIS_NEW_ARCHITECTURE_ENABLED=${IS_NEW_ARCHITECTURE_ENABLED}", - "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" + "-DIS_NEW_ARCHITECTURE_ENABLED=${IS_NEW_ARCHITECTURE_ENABLED}", + "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON", + "-DRN_AUDIO_API_FFMPEG_DISABLED=${IS_RN_AUDIO_API_FFMPEG_DISABLED}" ] if (isWorkletsAvailable) { diff --git a/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp b/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp index 348cc2d0e..e8a1db3ae 100644 --- a/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp +++ b/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp @@ -12,8 +12,10 @@ #ifndef AUDIO_API_TEST_SUITE #include +#endif // AUDIO_API_TEST_SUITE +#if !RN_AUDIO_API_FFMPEG_DISABLED #include -#endif +#endif // RN_AUDIO_API_FFMPEG_DISABLED #include #include @@ -73,6 +75,7 @@ std::shared_ptr AudioDecoder::decodeWithFilePath( float sampleRate) { #ifndef AUDIO_API_TEST_SUITE if (AudioDecoder::pathHasExtension(path, {".mp4", ".m4a", ".aac"})) { +#if !RN_AUDIO_API_FFMPEG_DISABLED auto buffer = ffmpegdecoder::decodeWithFilePath(path, static_cast(sampleRate)); if (buffer == nullptr) { __android_log_print( @@ -80,6 +83,14 @@ std::shared_ptr AudioDecoder::decodeWithFilePath( return nullptr; } return buffer; +#else + __android_log_print( + ANDROID_LOG_ERROR, + "AudioDecoder", + "FFmpeg is disabled, cannot decode file: %s", + path.c_str()); + return nullptr; +#endif // RN_AUDIO_API_FFMPEG_DISABLED } ma_decoder decoder; ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, static_cast(sampleRate)); @@ -115,12 +126,18 @@ AudioDecoder::decodeWithMemoryBlock(const void *data, size_t size, float sampleR #ifndef AUDIO_API_TEST_SUITE const AudioFormat format = AudioDecoder::detectAudioFormat(data, size); if (format == AudioFormat::MP4 || format == AudioFormat::M4A || format == AudioFormat::AAC) { +#if !RN_AUDIO_API_FFMPEG_DISABLED auto buffer = ffmpegdecoder::decodeWithMemoryBlock(data, size, static_cast(sampleRate)); if (buffer == nullptr) { __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode with FFmpeg"); return nullptr; } return buffer; +#else + __android_log_print( + ANDROID_LOG_ERROR, "AudioDecoder", "FFmpeg is disabled, cannot decode memory block"); + return nullptr; +#endif // RN_AUDIO_API_FFMPEG_DISABLED } ma_decoder decoder; ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, static_cast(sampleRate)); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp index e61d01bc1..557a8b638 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp @@ -159,11 +159,15 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createOscillator) { } JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createStreamer) { +#if !RN_AUDIO_API_FFMPEG_DISABLED auto streamer = context_->createStreamer(); auto streamerHostObject = std::make_shared(streamer); auto object = jsi::Object::createFromHostObject(runtime, streamerHostObject); object.setExternalMemoryPressure(runtime, StreamerNodeHostObject::getSizeInBytes()); return object; +#else + return jsi::Value::undefined(); +#endif // RN_AUDIO_API_FFMPEG_DISABLED } JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createConstantSource) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp index bee7fc82e..fad23a17e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp @@ -13,10 +13,14 @@ StreamerNodeHostObject::StreamerNodeHostObject(const std::shared_ptr(node_); auto path = args[0].getString(runtime).utf8(runtime); auto result = streamerNode->initialize(path); return {result}; +#else + return false; +#endif } } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp index a3c941216..83e46c753 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.cpp @@ -13,7 +13,9 @@ #include #include #include +#if !RN_AUDIO_API_FFMPEG_DISABLED #include +#endif // RN_AUDIO_API_FFMPEG_DISABLED #include #include #include @@ -121,13 +123,15 @@ std::shared_ptr BaseAudioContext::createConstantSource() { return constantSource; } -#ifndef AUDIO_API_TEST_SUITE std::shared_ptr BaseAudioContext::createStreamer() { +#if !RN_AUDIO_API_FFMPEG_DISABLED auto streamer = std::make_shared(this); nodeManager_->addSourceNode(streamer); return streamer; +#else + return nullptr; +#endif // RN_AUDIO_API_FFMPEG_DISABLED } -#endif std::shared_ptr BaseAudioContext::createGain() { auto gain = std::make_shared(this); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.h index 4f5cd413b..87d8697b2 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/StreamerNode.h @@ -13,7 +13,7 @@ #include #include -#ifndef AUDIO_API_TEST_SUITE +#if !RN_AUDIO_API_FFMPEG_DISABLED extern "C" { #include #include @@ -22,7 +22,7 @@ extern "C" { #include #include } -#endif +#endif // RN_AUDIO_API_FFMPEG_DISABLED #include #include @@ -36,7 +36,7 @@ static constexpr audioapi::channels::spsc::OverflowStrategy STREAMER_NODE_SPSC_O audioapi::channels::spsc::OverflowStrategy::WAIT_ON_FULL; static constexpr audioapi::channels::spsc::WaitStrategy STREAMER_NODE_SPSC_WAIT_STRATEGY = audioapi::channels::spsc::WaitStrategy::ATOMIC_WAIT; -#endif +#endif // AUDIO_API_TEST_SUITE static constexpr bool VERBOSE = false; static constexpr int CHANNEL_CAPACITY = 32; @@ -78,7 +78,7 @@ class StreamerNode : public AudioScheduledSourceNode { int framesToProcess) override; private: -#ifndef AUDIO_API_TEST_SUITE +#if !RN_AUDIO_API_FFMPEG_DISABLED AVFormatContext *fmtCtx_; AVCodecContext *codecCtx_; const AVCodec *decoder_; @@ -149,6 +149,6 @@ class StreamerNode : public AudioScheduledSourceNode { * @return true if successful, false otherwise */ bool setupDecoder(); -#endif // AUDIO_API_TEST_SUITE +#endif // RN_AUDIO_API_FFMPEG_DISABLED }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp b/packages/react-native-audio-api/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp index 01f7a47ba..32c10d691 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp @@ -9,7 +9,9 @@ */ #include +#if !RN_AUDIO_API_FFMPEG_DISABLED #include +#endif // RN_AUDIO_API_FFMPEG_DISABLED #include #include #include diff --git a/packages/react-native-audio-api/common/cpp/test/CMakeLists.txt b/packages/react-native-audio-api/common/cpp/test/CMakeLists.txt index 9671d130d..6248c81c9 100644 --- a/packages/react-native-audio-api/common/cpp/test/CMakeLists.txt +++ b/packages/react-native-audio-api/common/cpp/test/CMakeLists.txt @@ -81,6 +81,7 @@ add_executable( add_compile_definitions(AUDIO_API_TEST_SUITE) add_compile_definitions(RN_AUDIO_API_ENABLE_WORKLETS=0) add_compile_definitions(RN_AUDIO_API_TEST=1) +add_compile_definitions(RN_AUDIO_API_FFMPEG_DISABLED=1) target_link_libraries(tests rnaudioapi diff --git a/packages/react-native-audio-api/ios/audioapi/ios/core/utils/AudioDecoder.mm b/packages/react-native-audio-api/ios/audioapi/ios/core/utils/AudioDecoder.mm index 299148e06..71add3ef4 100644 --- a/packages/react-native-audio-api/ios/audioapi/ios/core/utils/AudioDecoder.mm +++ b/packages/react-native-audio-api/ios/audioapi/ios/core/utils/AudioDecoder.mm @@ -9,7 +9,9 @@ #include #include #include +#if !RN_AUDIO_API_FFMPEG_DISABLED #include +#endif // RN_AUDIO_API_FFMPEG_DISABLED #include #include @@ -67,12 +69,17 @@ float sampleRate) { if (AudioDecoder::pathHasExtension(path, {".mp4", ".m4a", ".aac"})) { +#if !RN_AUDIO_API_FFMPEG_DISABLED auto buffer = ffmpegdecoder::decodeWithFilePath(path, static_cast(sampleRate)); if (buffer == nullptr) { NSLog(@"Failed to decode with FFmpeg: %s", path.c_str()); return nullptr; } return buffer; +#else + NSLog(@"FFmpeg is disabled, cannot decode file: %s", path.c_str()); + return nullptr; +#endif // RN_AUDIO_API_FFMPEG_DISABLED } ma_decoder decoder; ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, static_cast(sampleRate)); @@ -101,12 +108,17 @@ { const AudioFormat format = AudioDecoder::detectAudioFormat(data, size); if (format == AudioFormat::MP4 || format == AudioFormat::M4A || format == AudioFormat::AAC) { +#if !RN_AUDIO_API_FFMPEG_DISABLED auto buffer = ffmpegdecoder::decodeWithMemoryBlock(data, size, static_cast(sampleRate)); if (buffer == nullptr) { NSLog(@"Failed to decode with FFmpeg"); return nullptr; } return buffer; +#else + NSLog(@"FFmpeg is disabled, cannot decode memory block"); + return nullptr; +#endif // RN_AUDIO_API_FFMPEG_DISABLED } ma_decoder decoder; ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 0, static_cast(sampleRate)); diff --git a/packages/react-native-audio-api/src/core/BaseAudioContext.ts b/packages/react-native-audio-api/src/core/BaseAudioContext.ts index 86938d40c..67db66dd5 100644 --- a/packages/react-native-audio-api/src/core/BaseAudioContext.ts +++ b/packages/react-native-audio-api/src/core/BaseAudioContext.ts @@ -185,7 +185,11 @@ export default class BaseAudioContext { } createStreamer(): StreamerNode { - return new StreamerNode(this, this.context.createStreamer()); + const streamer = this.context.createStreamer(); + if (!streamer) { + throw new NotSupportedError('StreamerNode requires FFmpeg build'); + } + return new StreamerNode(this, streamer); } createConstantSource(): ConstantSourceNode { diff --git a/packages/react-native-audio-api/src/interfaces.ts b/packages/react-native-audio-api/src/interfaces.ts index 5c1bc8a0a..62d0ce2d2 100644 --- a/packages/react-native-audio-api/src/interfaces.ts +++ b/packages/react-native-audio-api/src/interfaces.ts @@ -81,7 +81,7 @@ export interface IBaseAudioContext { buffer: IAudioBuffer | undefined, disableNormalization: boolean ) => IConvolverNode; - createStreamer: () => IStreamerNode; + createStreamer: () => IStreamerNode | null; // null when FFmpeg is not enabled } export interface IAudioContext extends IBaseAudioContext { diff --git a/packages/react-native-audio-api/src/plugin/withAudioAPI.ts b/packages/react-native-audio-api/src/plugin/withAudioAPI.ts index 973393f22..c6e7ddaed 100644 --- a/packages/react-native-audio-api/src/plugin/withAudioAPI.ts +++ b/packages/react-native-audio-api/src/plugin/withAudioAPI.ts @@ -4,6 +4,8 @@ import { ConfigPlugin, withInfoPlist, withAndroidManifest, + withGradleProperties, + withPodfile, } from '@expo/config-plugins'; const pkg = require('react-native-audio-api/package.json'); @@ -13,6 +15,7 @@ interface Options { androidPermissions: string[]; androidForegroundService: boolean; androidFSTypes: string[]; + disableFFmpeg: boolean; } const withDefaultOptions = (options: Partial): Options => { @@ -24,6 +27,7 @@ const withDefaultOptions = (options: Partial): Options => { ], androidForegroundService: true, androidFSTypes: ['mediaPlayback'], + disableFFmpeg: false, ...options, }; }; @@ -88,6 +92,59 @@ const withForegroundService: ConfigPlugin = ( }); }; +const withFFmpegConfig: ConfigPlugin = (config, options) => { + const iosConf = withPodfile(config, (mod) => { + let contents = mod.modResults.contents; + const ffmpegRegex = /^.*ENV\['DISABLE_AUDIOAPI_FFMPEG'\].*$/gm; + const podfileString = options.disableFFmpeg + ? `ENV['DISABLE_AUDIOAPI_FFMPEG'] = '1'` + : ''; + // No existing setting + if (contents.search(ffmpegRegex) === -1) { + if (options.disableFFmpeg) { + if (contents.endsWith('\n')) { + contents = `${contents}${podfileString}`; + } else { + contents = `${contents}\n${podfileString}`; + } + mod.modResults.contents = contents; + } + } else { + // Existing setting found, will replace + contents = contents.replace(ffmpegRegex, podfileString); + } + + mod.modResults.contents = contents; + return mod; + }); + + const finalConf = withGradleProperties(iosConf, (mod) => { + const gradleProperties = mod.modResults; + + const existingIndex = gradleProperties.findIndex( + (prop) => prop.type === 'property' && prop.key === 'disableAudioapiFFmpeg' + ); + if (existingIndex !== -1) { + gradleProperties.splice(existingIndex, 1); + } else if (!options.disableFFmpeg) { + // No existing setting and FFmpeg is enabled, do nothing. + return mod; + } + + if (options.disableFFmpeg) { + gradleProperties.push({ + type: 'property', + key: 'disableAudioapiFFmpeg', + value: options.disableFFmpeg ? 'true' : 'false', + }); + } + + return mod; + }); + + return finalConf; +}; + const withAudioAPI: ConfigPlugin = (config, optionsIn) => { const options = withDefaultOptions(optionsIn ?? {}); @@ -105,6 +162,10 @@ const withAudioAPI: ConfigPlugin = (config, optionsIn) => { config = withIosMicrophonePermission(config, options); } + if (options.disableFFmpeg !== undefined) { + config = withFFmpegConfig(config, options); + } + return config; };