Skip to content

Commit

Permalink
fix: audio wav and mp4 audio and bypass if fail
Browse files Browse the repository at this point in the history
  • Loading branch information
numandev1 committed Oct 1, 2023
1 parent 0f6e56b commit 0c326d2
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ Video.cancelCompression(cancellationVideoId);
import { Audio } from 'react-native-compressor';

const result = await Audio.compress(
'file://path_of_file/file_example_MP3_2MG.mp3',
'file://path_of_file/file_example_MP3_2MG.wav', // recommended wav file but can be use mp3 file
{ quality: 'medium' }
);
```
Expand Down Expand Up @@ -395,6 +395,7 @@ await clearCache(); // this will clear cache of thumbnails cache directory
## Audio

- ###### `compress(url: string, options?: audioCompresssionType): Promise<string>`
Android: recommended to use `wav` file as we convert mp3 to wav then apply bitrate

### audioCompresssionType

Expand Down
1 change: 0 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation "com.googlecode.mp4parser:isoparser:1.0.6"

implementation 'io.github.lizhangqu:coreprogress:1.0.2'
implementation 'com.github.banketree:AndroidLame-kotlin:v0.0.1'
implementation 'javazoom:jlayer:1.0.1'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.reactnativecompressor.Utils.MediaCache
import com.reactnativecompressor.Utils.Utils
import com.reactnativecompressor.Utils.Utils.addLog
import javazoom.jl.converter.Converter
import javazoom.jl.decoder.JavaLayerException
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileNotFoundException
Expand All @@ -30,16 +31,38 @@ class AudioCompressor {
context: ReactApplicationContext,
promise: Promise,
) {
var _fileUrl=fileUrl
try {
val filePath = fileUrl.replace("file://", "")
var wavPath=filePath;
var isNonWav:Boolean=false
if (!fileUrl.endsWith(".waw", ignoreCase = true))
if (fileUrl.endsWith(".mp4", ignoreCase = true))
{
addLog("mp3 file found")
addLog("mp4 file found")
val mp3Path= Utils.generateCacheFilePath("mp3", context)
AudioExtractor().genVideoUsingMuxer(fileUrl, mp3Path, -1, -1, true, false)
_fileUrl="file:/"+mp3Path
wavPath= Utils.generateCacheFilePath("wav", context)
try {
val converter = Converter()
converter.convert(mp3Path, wavPath)
} catch (e: JavaLayerException) {
addLog("JavaLayerException error"+e.localizedMessage)
e.printStackTrace();
}
isNonWav=true
}
else if (!fileUrl.endsWith(".wav", ignoreCase = true))
{
addLog("non wav file found")
wavPath= Utils.generateCacheFilePath("wav", context)
try {
val converter = Converter()
converter.convert(filePath, wavPath)
} catch (e: JavaLayerException) {
addLog("JavaLayerException error"+e.localizedMessage)
e.printStackTrace();
}
isNonWav=true
}

Expand All @@ -56,11 +79,11 @@ class AudioCompressor {
promise.resolve(returnableFilePath)
} else {
addLog("error: "+mp3Path)
promise.resolve(fileUrl)
promise.resolve(_fileUrl)
}
}
} catch (e: Exception) {
promise.resolve(fileUrl)
promise.resolve(_fileUrl)
}
}

Expand All @@ -80,6 +103,7 @@ class AudioCompressor {
context: ReactApplicationContext,
completeCallback: (String, Boolean) -> Unit
) {
var isCompletedCallbackTriggered:Boolean=false
try {
var mp3Path = Utils.generateCacheFilePath("mp3", context)
val input = File(fileUrl)
Expand Down Expand Up @@ -180,14 +204,14 @@ class AudioCompressor {
addLog("flushing final mp3buffer")
val outputMp3buf = androidLame.flush(mp3Buf)
addLog("flushed $outputMp3buf bytes")

if (outputMp3buf > 0) {
try {
addLog("writing final mp3buffer to outputstream")
outputStream!!.write(mp3Buf, 0, outputMp3buf)
addLog("closing output stream")
outputStream!!.close()
completeCallback(output.absolutePath, true)
isCompletedCallbackTriggered=true
} catch (e: IOException) {
completeCallback(e.localizedMessage, false)
e.printStackTrace()
Expand All @@ -197,6 +221,10 @@ class AudioCompressor {
} catch (e: IOException) {
completeCallback(e.localizedMessage, false)
}
if(!isCompletedCallbackTriggered)
{
completeCallback("something went wrong", false)
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.reactnativecompressor.Audio

import android.annotation.SuppressLint
import android.media.MediaCodec
import android.media.MediaExtractor
import android.media.MediaFormat
import android.media.MediaMetadataRetriever
import android.media.MediaMuxer
import android.util.Log
import java.io.IOException
import java.nio.ByteBuffer


class AudioExtractor {
/**
* @param srcPath the path of source video file.
* @param dstPath the path of destination video file.
* @param startMs starting time in milliseconds for trimming. Set to
* negative if starting from beginning.
* @param endMs end time for trimming in milliseconds. Set to negative if
* no trimming at the end.
* @param useAudio true if keep the audio track from the source.
* @param useVideo true if keep the video track from the source.
* @throws IOException
*/
@SuppressLint("NewApi", "WrongConstant")
@Throws(IOException::class)
fun genVideoUsingMuxer(srcPath: String?, dstPath: String?, startMs: Int, endMs: Int, useAudio: Boolean, useVideo: Boolean) {
// Set up MediaExtractor to read from the source.
val extractor = MediaExtractor()
extractor.setDataSource(srcPath!!)
val trackCount = extractor.trackCount
// Set up MediaMuxer for the destination.
val muxer: MediaMuxer
muxer = MediaMuxer(dstPath!!, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
// Set up the tracks and retrieve the max buffer size for selected
// tracks.
val indexMap = HashMap<Int, Int>(trackCount)
var bufferSize = -1
for (i in 0 until trackCount) {
val format = extractor.getTrackFormat(i)
val mime = format.getString(MediaFormat.KEY_MIME)
var selectCurrentTrack = false
if (mime!!.startsWith("audio/") && useAudio) {
selectCurrentTrack = true
} else if (mime.startsWith("video/") && useVideo) {
selectCurrentTrack = true
}
if (selectCurrentTrack) {
extractor.selectTrack(i)
val dstIndex = muxer.addTrack(format)
indexMap[i] = dstIndex
if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
val newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
bufferSize = if (newSize > bufferSize) newSize else bufferSize
}
}
}
if (bufferSize < 0) {
bufferSize = DEFAULT_BUFFER_SIZE
}
// Set up the orientation and starting time for extractor.
val retrieverSrc = MediaMetadataRetriever()
retrieverSrc.setDataSource(srcPath)
val degreesString = retrieverSrc.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)
if (degreesString != null) {
val degrees = degreesString.toInt()
if (degrees >= 0) {
muxer.setOrientationHint(degrees)
}
}
if (startMs > 0) {
extractor.seekTo((startMs * 1000).toLong(), MediaExtractor.SEEK_TO_CLOSEST_SYNC)
}
// Copy the samples from MediaExtractor to MediaMuxer. We will loop
// for copying each sample and stop when we get to the end of the source
// file or exceed the end time of the trimming.
val offset = 0
var trackIndex = -1
val dstBuf = ByteBuffer.allocate(bufferSize)
val bufferInfo = MediaCodec.BufferInfo()
muxer.start()
while (true) {
bufferInfo.offset = offset
bufferInfo.size = extractor.readSampleData(dstBuf, offset)
if (bufferInfo.size < 0) {
Log.d(TAG, "Saw input EOS.")
bufferInfo.size = 0
break
} else {
bufferInfo.presentationTimeUs = extractor.sampleTime
if (endMs > 0 && bufferInfo.presentationTimeUs > endMs * 1000) {
Log.d(TAG, "The current sample is over the trim end time.")
break
} else {
bufferInfo.flags = extractor.sampleFlags
trackIndex = extractor.sampleTrackIndex
muxer.writeSampleData(indexMap[trackIndex]!!, dstBuf, bufferInfo)
extractor.advance()
}
}
}
muxer.stop()
muxer.release()
return
}

companion object {
private const val DEFAULT_BUFFER_SIZE = 1 * 1024 * 1024
private const val TAG = "AudioExtractorDecoder"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class AudioMain(private val reactContext: ReactApplicationContext) {
val options = AudioHelper.fromMap(optionMap)
val quality = options.quality
val realPath = Utils.getRealPath(fileUrl, reactContext)
Utils.addLog(fileUrl + "testPath" + realPath)
Utils.addLog(fileUrl + "\n realPath= " + realPath)
AudioCompressor.CompressAudio(realPath!!, quality!!,reactContext,promise)
} catch (ex: Exception) {
promise.reject(ex)
Expand Down

0 comments on commit 0c326d2

Please sign in to comment.