···1+diff --git a/node_modules/react-native-compressor/android/build.gradle b/node_modules/react-native-compressor/android/build.gradle
2+index 5071139..84bee34 100644
3+--- a/node_modules/react-native-compressor/android/build.gradle
4++++ b/node_modules/react-native-compressor/android/build.gradle
5+@@ -115,7 +115,6 @@ dependencies {
6+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
7+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
8+ implementation 'org.mp4parser:isoparser:1.9.56'
9+- implementation 'com.github.banketree:AndroidLame-kotlin:v0.0.1'
10+ implementation 'javazoom:jlayer:1.0.1'
11+ }
12+13+diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt
14+deleted file mode 100644
15+index 9292d3e..0000000
16+--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt
17++++ /dev/null
18+@@ -1,264 +0,0 @@
19+-package com.reactnativecompressor.Audio
20+-
21+-
22+-import android.annotation.SuppressLint
23+-import com.facebook.react.bridge.Promise
24+-import com.facebook.react.bridge.ReactApplicationContext
25+-import com.facebook.react.bridge.ReadableMap
26+-import com.naman14.androidlame.LameBuilder
27+-import com.naman14.androidlame.WaveReader
28+-import com.reactnativecompressor.Utils.MediaCache
29+-import com.reactnativecompressor.Utils.Utils
30+-import com.reactnativecompressor.Utils.Utils.addLog
31+-import javazoom.jl.converter.Converter
32+-import javazoom.jl.decoder.JavaLayerException
33+-import java.io.BufferedOutputStream
34+-import java.io.File
35+-import java.io.FileNotFoundException
36+-import java.io.FileOutputStream
37+-import java.io.IOException
38+-
39+-class AudioCompressor {
40+- companion object {
41+- val TAG="AudioMain"
42+- private const val OUTPUT_STREAM_BUFFER = 8192
43+-
44+- var outputStream: BufferedOutputStream? = null
45+- var waveReader: WaveReader? = null
46+- @JvmStatic
47+- fun CompressAudio(
48+- fileUrl: String,
49+- optionMap: ReadableMap,
50+- context: ReactApplicationContext,
51+- promise: Promise,
52+- ) {
53+- val realPath = Utils.getRealPath(fileUrl, context)
54+- var _fileUrl=realPath
55+- val filePathWithoutFileUri = realPath!!.replace("file://", "")
56+- try {
57+- var wavPath=filePathWithoutFileUri;
58+- var isNonWav:Boolean=false
59+- if (fileUrl.endsWith(".mp4", ignoreCase = true))
60+- {
61+- addLog("mp4 file found")
62+- val mp3Path= Utils.generateCacheFilePath("mp3", context)
63+- AudioExtractor().genVideoUsingMuxer(fileUrl, mp3Path, -1, -1, true, false)
64+- _fileUrl=Utils.slashifyFilePath(mp3Path)
65+- wavPath= Utils.generateCacheFilePath("wav", context)
66+- try {
67+- val converter = Converter()
68+- converter.convert(mp3Path, wavPath)
69+- } catch (e: JavaLayerException) {
70+- addLog("JavaLayerException error"+e.localizedMessage)
71+- e.printStackTrace();
72+- }
73+- isNonWav=true
74+- }
75+- else if (!fileUrl.endsWith(".wav", ignoreCase = true))
76+- {
77+- addLog("non wav file found")
78+- wavPath= Utils.generateCacheFilePath("wav", context)
79+- try {
80+- val converter = Converter()
81+- converter.convert(filePathWithoutFileUri, wavPath)
82+- } catch (e: JavaLayerException) {
83+- addLog("JavaLayerException error"+e.localizedMessage)
84+- e.printStackTrace();
85+- }
86+- isNonWav=true
87+- }
88+-
89+-
90+- autoCompressHelper(wavPath,filePathWithoutFileUri, optionMap,context) { mp3Path, finished ->
91+- if (finished) {
92+- val returnableFilePath:String="file://$mp3Path"
93+- addLog("finished: " + returnableFilePath)
94+- MediaCache.removeCompletedImagePath(fileUrl)
95+- if(isNonWav)
96+- {
97+- File(wavPath).delete()
98+- }
99+- promise.resolve(returnableFilePath)
100+- } else {
101+- addLog("error: "+mp3Path)
102+- promise.resolve(_fileUrl)
103+- }
104+- }
105+- } catch (e: Exception) {
106+- promise.resolve(_fileUrl)
107+- }
108+- }
109+-
110+- @SuppressLint("WrongConstant")
111+- private fun autoCompressHelper(
112+- fileUrl: String,
113+- actualFileUrl: String,
114+- optionMap: ReadableMap,
115+- context: ReactApplicationContext,
116+- completeCallback: (String, Boolean) -> Unit
117+- ) {
118+-
119+- val options = AudioHelper.fromMap(optionMap)
120+- val quality = options.quality
121+-
122+- var isCompletedCallbackTriggered:Boolean=false
123+- try {
124+- var mp3Path = Utils.generateCacheFilePath("mp3", context)
125+- val input = File(fileUrl)
126+- val output = File(mp3Path)
127+-
128+- val CHUNK_SIZE = 8192
129+- addLog("Initialising wav reader")
130+-
131+- waveReader = WaveReader(input)
132+-
133+- try {
134+- waveReader!!.openWave()
135+- } catch (e: IOException) {
136+- e.printStackTrace()
137+- }
138+-
139+- addLog("Intitialising encoder")
140+-
141+-
142+- // for bitrate
143+- var audioBitrate:Int
144+- if(options.bitrate != -1)
145+- {
146+- audioBitrate= options.bitrate/1000
147+- }
148+- else
149+- {
150+- audioBitrate=AudioHelper.getDestinationBitrateByQuality(actualFileUrl, quality!!)
151+- Utils.addLog("dest bitrate: $audioBitrate")
152+- }
153+-
154+- var androidLame = LameBuilder();
155+- androidLame.setOutBitrate(audioBitrate)
156+-
157+- // for channels
158+- var audioChannels:Int
159+- if(options.channels != -1){
160+- audioChannels= options.channels!!
161+- }
162+- else
163+- {
164+- audioChannels=waveReader!!.channels
165+- }
166+- androidLame.setOutChannels(audioChannels)
167+-
168+- // for sample rate
169+- androidLame.setInSampleRate(waveReader!!.sampleRate)
170+- var audioSampleRate:Int
171+- if(options.samplerate != -1){
172+- audioSampleRate= options.samplerate!!
173+- }
174+- else
175+- {
176+- audioSampleRate=waveReader!!.sampleRate
177+- }
178+- androidLame.setOutSampleRate(audioSampleRate)
179+- val androidLameBuild=androidLame.build()
180+-
181+- try {
182+- outputStream = BufferedOutputStream(FileOutputStream(output), OUTPUT_STREAM_BUFFER)
183+- } catch (e: FileNotFoundException) {
184+- e.printStackTrace()
185+- }
186+-
187+- var bytesRead = 0
188+-
189+- val buffer_l = ShortArray(CHUNK_SIZE)
190+- val buffer_r = ShortArray(CHUNK_SIZE)
191+- val mp3Buf = ByteArray(CHUNK_SIZE)
192+-
193+- val channels = waveReader!!.channels
194+-
195+- addLog("started encoding")
196+- while (true) {
197+- try {
198+- if (channels == 2) {
199+-
200+- bytesRead = waveReader!!.read(buffer_l, buffer_r, CHUNK_SIZE)
201+- addLog("bytes read=$bytesRead")
202+-
203+- if (bytesRead > 0) {
204+-
205+- var bytesEncoded = 0
206+- bytesEncoded = androidLameBuild.encode(buffer_l, buffer_r, bytesRead, mp3Buf)
207+- addLog("bytes encoded=$bytesEncoded")
208+-
209+- if (bytesEncoded > 0) {
210+- try {
211+- addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
212+- outputStream!!.write(mp3Buf, 0, bytesEncoded)
213+- } catch (e: IOException) {
214+- e.printStackTrace()
215+- }
216+-
217+- }
218+-
219+- } else
220+- break
221+- } else {
222+-
223+- bytesRead = waveReader!!.read(buffer_l, CHUNK_SIZE)
224+- addLog("bytes read=$bytesRead")
225+-
226+- if (bytesRead > 0) {
227+- var bytesEncoded = 0
228+-
229+- bytesEncoded = androidLameBuild.encode(buffer_l, buffer_l, bytesRead, mp3Buf)
230+- addLog("bytes encoded=$bytesEncoded")
231+-
232+- if (bytesEncoded > 0) {
233+- try {
234+- addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
235+- outputStream!!.write(mp3Buf, 0, bytesEncoded)
236+- } catch (e: IOException) {
237+- e.printStackTrace()
238+- }
239+-
240+- }
241+-
242+- } else
243+- break
244+- }
245+-
246+-
247+- } catch (e: IOException) {
248+- e.printStackTrace()
249+- }
250+-
251+- }
252+-
253+- addLog("flushing final mp3buffer")
254+- val outputMp3buf = androidLameBuild.flush(mp3Buf)
255+- addLog("flushed $outputMp3buf bytes")
256+- if (outputMp3buf > 0) {
257+- try {
258+- addLog("writing final mp3buffer to outputstream")
259+- outputStream!!.write(mp3Buf, 0, outputMp3buf)
260+- addLog("closing output stream")
261+- outputStream!!.close()
262+- completeCallback(output.absolutePath, true)
263+- isCompletedCallbackTriggered=true
264+- } catch (e: IOException) {
265+- completeCallback(e.localizedMessage, false)
266+- e.printStackTrace()
267+- }
268+- }
269+-
270+- } catch (e: IOException) {
271+- completeCallback(e.localizedMessage, false)
272+- }
273+- if(!isCompletedCallbackTriggered)
274+- {
275+- completeCallback("something went wrong", false)
276+- }
277+- }
278+-
279+-
280+-
281+- }
282+-}
283+diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt
284+deleted file mode 100644
285+index c655182..0000000
286+--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt
287++++ /dev/null
288+@@ -1,112 +0,0 @@
289+-package com.reactnativecompressor.Audio
290+-
291+-import android.annotation.SuppressLint
292+-import android.media.MediaCodec
293+-import android.media.MediaExtractor
294+-import android.media.MediaFormat
295+-import android.media.MediaMetadataRetriever
296+-import android.media.MediaMuxer
297+-import android.util.Log
298+-import java.io.IOException
299+-import java.nio.ByteBuffer
300+-
301+-
302+-class AudioExtractor {
303+- /**
304+- * @param srcPath the path of source video file.
305+- * @param dstPath the path of destination video file.
306+- * @param startMs starting time in milliseconds for trimming. Set to
307+- * negative if starting from beginning.
308+- * @param endMs end time for trimming in milliseconds. Set to negative if
309+- * no trimming at the end.
310+- * @param useAudio true if keep the audio track from the source.
311+- * @param useVideo true if keep the video track from the source.
312+- * @throws IOException
313+- */
314+- @SuppressLint("NewApi", "WrongConstant")
315+- @Throws(IOException::class)
316+- fun genVideoUsingMuxer(srcPath: String?, dstPath: String?, startMs: Int, endMs: Int, useAudio: Boolean, useVideo: Boolean) {
317+- // Set up MediaExtractor to read from the source.
318+- val extractor = MediaExtractor()
319+- extractor.setDataSource(srcPath!!)
320+- val trackCount = extractor.trackCount
321+- // Set up MediaMuxer for the destination.
322+- val muxer: MediaMuxer
323+- muxer = MediaMuxer(dstPath!!, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
324+- // Set up the tracks and retrieve the max buffer size for selected
325+- // tracks.
326+- val indexMap = HashMap<Int, Int>(trackCount)
327+- var bufferSize = -1
328+- for (i in 0 until trackCount) {
329+- val format = extractor.getTrackFormat(i)
330+- val mime = format.getString(MediaFormat.KEY_MIME)
331+- var selectCurrentTrack = false
332+- if (mime!!.startsWith("audio/") && useAudio) {
333+- selectCurrentTrack = true
334+- } else if (mime.startsWith("video/") && useVideo) {
335+- selectCurrentTrack = true
336+- }
337+- if (selectCurrentTrack) {
338+- extractor.selectTrack(i)
339+- val dstIndex = muxer.addTrack(format)
340+- indexMap[i] = dstIndex
341+- if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
342+- val newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
343+- bufferSize = if (newSize > bufferSize) newSize else bufferSize
344+- }
345+- }
346+- }
347+- if (bufferSize < 0) {
348+- bufferSize = DEFAULT_BUFFER_SIZE
349+- }
350+- // Set up the orientation and starting time for extractor.
351+- val retrieverSrc = MediaMetadataRetriever()
352+- retrieverSrc.setDataSource(srcPath)
353+- val degreesString = retrieverSrc.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)
354+- if (degreesString != null) {
355+- val degrees = degreesString.toInt()
356+- if (degrees >= 0) {
357+- muxer.setOrientationHint(degrees)
358+- }
359+- }
360+- if (startMs > 0) {
361+- extractor.seekTo((startMs * 1000).toLong(), MediaExtractor.SEEK_TO_CLOSEST_SYNC)
362+- }
363+- // Copy the samples from MediaExtractor to MediaMuxer. We will loop
364+- // for copying each sample and stop when we get to the end of the source
365+- // file or exceed the end time of the trimming.
366+- val offset = 0
367+- var trackIndex = -1
368+- val dstBuf = ByteBuffer.allocate(bufferSize)
369+- val bufferInfo = MediaCodec.BufferInfo()
370+- muxer.start()
371+- while (true) {
372+- bufferInfo.offset = offset
373+- bufferInfo.size = extractor.readSampleData(dstBuf, offset)
374+- if (bufferInfo.size < 0) {
375+- Log.d(TAG, "Saw input EOS.")
376+- bufferInfo.size = 0
377+- break
378+- } else {
379+- bufferInfo.presentationTimeUs = extractor.sampleTime
380+- if (endMs > 0 && bufferInfo.presentationTimeUs > endMs * 1000) {
381+- Log.d(TAG, "The current sample is over the trim end time.")
382+- break
383+- } else {
384+- bufferInfo.flags = extractor.sampleFlags
385+- trackIndex = extractor.sampleTrackIndex
386+- muxer.writeSampleData(indexMap[trackIndex]!!, dstBuf, bufferInfo)
387+- extractor.advance()
388+- }
389+- }
390+- }
391+- muxer.stop()
392+- muxer.release()
393+- return
394+- }
395+-
396+- companion object {
397+- private const val DEFAULT_BUFFER_SIZE = 1 * 1024 * 1024
398+- private const val TAG = "AudioExtractorDecoder"
399+- }
400+-}
401+diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt
402+deleted file mode 100644
403+index 42040b4..0000000
404+--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt
405++++ /dev/null
406+@@ -1,72 +0,0 @@
407+-package com.reactnativecompressor.Audio
408+-
409+-import android.media.MediaExtractor
410+-import android.media.MediaFormat
411+-import com.facebook.react.bridge.ReadableMap
412+-import com.reactnativecompressor.Utils.Utils
413+-import java.io.File
414+-import java.io.IOException
415+-
416+-
417+-class AudioHelper {
418+-
419+- var quality: String? = "medium"
420+- var bitrate: Int = -1
421+- var samplerate: Int = -1
422+- var channels: Int = -1
423+- var progressDivider: Int? = 0
424+-
425+- companion object {
426+- fun fromMap(map: ReadableMap): AudioHelper {
427+- val options = AudioHelper()
428+- val iterator = map.keySetIterator()
429+- while (iterator.hasNextKey()) {
430+- val key = iterator.nextKey()
431+- when (key) {
432+- "quality" -> options.quality = map.getString(key)
433+- "bitrate" -> {
434+- val bitrate = map.getInt(key)
435+- options.bitrate = if (bitrate > 320000 || bitrate < 64000) 64000 else bitrate
436+- }
437+- "samplerate" -> options.samplerate = map.getInt(key)
438+- "channels" -> options.channels = map.getInt(key)
439+- }
440+- }
441+- return options
442+- }
443+-
444+-
445+- fun getAudioBitrate(path: String): Int {
446+- val file = File(path)
447+- val fileSize = file.length() * 8 // size in bits
448+-
449+- val mex = MediaExtractor()
450+- try {
451+- mex.setDataSource(path)
452+- } catch (e: IOException) {
453+- e.printStackTrace()
454+- }
455+-
456+- val mf = mex.getTrackFormat(0)
457+- val durationUs = mf.getLong(MediaFormat.KEY_DURATION)
458+- val durationSec = durationUs / 1_000_000.0 // convert duration to seconds
459+-
460+- return (fileSize / durationSec).toInt()/1000 // bitrate in bits per second
461+- }
462+- fun getDestinationBitrateByQuality(path: String, quality: String): Int {
463+- val originalBitrate = getAudioBitrate(path)
464+- var destinationBitrate = originalBitrate
465+- Utils.addLog("source bitrate: $originalBitrate")
466+-
467+- when (quality.lowercase()) {
468+- "low" -> destinationBitrate = maxOf(64, (originalBitrate * 0.3).toInt())
469+- "medium" -> destinationBitrate = (originalBitrate * 0.5).toInt()
470+- "high" -> destinationBitrate = minOf(320, (originalBitrate * 0.7).toInt())
471+- else -> Utils.addLog("Invalid quality level. Please enter 'low', 'medium', or 'high'.")
472+- }
473+-
474+- return destinationBitrate
475+- }
476+-
477+- }
478+-}
479+diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt
480+index 446d4fb..f021909 100644
481+--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt
482++++ b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt
483+@@ -11,7 +11,9 @@ class AudioMain(private val reactContext: ReactApplicationContext) {
484+ promise: Promise) {
485+ try {
486+487+- AudioCompressor.CompressAudio(fileUrl,optionMap,reactContext,promise)
488++ // Skip compression on Android to avoid libandroidlame dependency
489++ // Return the original file URL without compression
490++ promise.resolve(fileUrl)
491+ } catch (ex: Exception) {
492+ promise.reject(ex)
493+ }
494+diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt
495+index c14b727..1198908 100644
496+--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt
497++++ b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt
498+@@ -7,7 +7,6 @@ import android.provider.OpenableColumns
499+ import android.util.Log
500+ import com.facebook.react.bridge.Promise
501+ import com.facebook.react.bridge.ReactApplicationContext
502+-import com.reactnativecompressor.Audio.AudioCompressor
503+ import com.reactnativecompressor.Video.VideoCompressor.CompressionListener
504+ import com.reactnativecompressor.Video.VideoCompressor.VideoCompressorClass
505+ import java.io.FileNotFoundException
506+@@ -152,10 +151,6 @@ object Utils {
507+ }
508+ }
509+510+- fun addLog(log: String) {
511+- Log.d(AudioCompressor.TAG, log)
512+- }
513+-
514+ val exifAttributes = arrayOf(
515+ "FNumber",
516+ "ApertureValue",
+5
patches/react-native-compressor+1.13.0.patch.md
···00000
···1+# react-native-compressor
2+3+Patch file taken from https://github.com/numandev1/react-native-compressor/pull/355#issuecomment-3180870738
4+5+This patch removes the audio compression feature on Android from the library. This is because `libandroidlame.so`, the native dependency, does not support 16kb page sizes, and the Play Store has made this mandatory as of 1st Nov 2025.