From 6f013d85da0a1e28044cb5f2920205029530ccd0 Mon Sep 17 00:00:00 2001 From: shabinder Date: Thu, 2 Sep 2021 18:07:22 +0530 Subject: [PATCH] FFmpeg-android Timeout Impl --- android/build.gradle.kts | 1 - .../com/shabinder/spotiflyer/MainActivity.kt | 36 ---------- common/core-components/build.gradle.kts | 2 - .../file_manager/AndroidFileManager.kt | 4 +- .../media_converter/AndroidMediaConverter.kt | 66 ++++++++++++------- 5 files changed, 45 insertions(+), 64 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 1977d2ca..2a078a5c 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -103,7 +103,6 @@ dependencies { implementation(project(":common:data-models")) implementation(project(":common:core-components")) implementation(project(":common:providers")) - implementation(project(":ffmpeg:android-ffmpeg")) // Koin implementation(Koin.android) diff --git a/android/src/main/java/com/shabinder/spotiflyer/MainActivity.kt b/android/src/main/java/com/shabinder/spotiflyer/MainActivity.kt index d94970ca..9c1c8052 100644 --- a/android/src/main/java/com/shabinder/spotiflyer/MainActivity.kt +++ b/android/src/main/java/com/shabinder/spotiflyer/MainActivity.kt @@ -54,12 +54,10 @@ import com.google.accompanist.insets.statusBarsPadding import com.shabinder.common.core_components.ConnectionLiveData import com.shabinder.common.core_components.analytics.AnalyticsManager import com.shabinder.common.core_components.file_manager.FileManager -import com.shabinder.common.core_components.media_converter.AndroidMediaConverter import com.shabinder.common.core_components.preference_manager.PreferenceManager import com.shabinder.common.di.observeAsState import com.shabinder.common.models.* import com.shabinder.common.models.PlatformActions.Companion.SharedPreferencesKey -import com.shabinder.common.models.event.coroutines.success import com.shabinder.common.providers.FetchPlatformQueryResult import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks @@ -77,7 +75,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.launch -import nl.bravobit.ffmpeg.* import org.koin.android.ext.android.inject import org.koin.core.parameter.parametersOf import java.io.File @@ -108,39 +105,6 @@ class MainActivity : ComponentActivity() { // This app draws behind the system bars, so we want to handle fitting system windows WindowCompat.setDecorFitsSystemWindows(window, false) rootComponent = spotiFlyerRoot(defaultComponentContext()) - val ffmpeg = FFmpeg.getInstance(this@MainActivity) - val ffprobe = FFprobe.getInstance(this@MainActivity) - lifecycleScope.launch { - Log.d("FFmpeg", "init") - FFmpegConfig.versionFFmpeg(this@MainActivity) - FFmpegConfig.codecsFFmpeg(this@MainActivity) - FFmpegConfig.versionFFprobe(this@MainActivity) - Log.d("FFmpeg Support", ffmpeg.isSupported.toString()) - val inputFilePath = "/storage/emulated/0/Music/SpotiFlyer/Playlists/Sing-along_Punjabi/Kya_Baat_Ay.mp3" - val outputFilePath = "/storage/emulated/0/Music/SpotiFlyer/Playlists/Sing-along_Punjabi/Kya_Baat_Ay.temp.mp3" - val kbpsArg = "-b:a 192k" - ffmpeg.execute(arrayOf("-i", inputFilePath, "-y", /*"-acodec", "libmp3lame",*/ "-vn", outputFilePath),object : ExecuteBinaryResponseHandler() { - override fun onSuccess(message: String?) { - Log.d("FFmpeg Command", "Success $message") - } - - override fun onProgress(message: String?) { - Log.d("FFmpeg Command", "Progress $message") - } - - override fun onFailure(message: String?) { - Log.d("FFmpeg Command", "Failed $message") - } - - }) - - /* AndroidMediaConverter().convertAudioFile("/storage/emulated/0/Music/SpotiFlyer/Playlists/Sing-along_Punjabi/Kya_Baat_Ay.mp3","/storage/emulated/0/Music/SpotiFlyer/Playlists/Sing-along_Punjabi/Kya_Baat_Ay.temp.mp3").fold({ - Log.d("FFmpeg Success",it) - }){ - it.printStackTrace() - }*/ - } - /*FFmpeg.testInit()*/ setContent { SpotiFlyerTheme { Surface(contentColor = colorOffWhite) { diff --git a/common/core-components/build.gradle.kts b/common/core-components/build.gradle.kts index 64ff455b..f67ee2c0 100644 --- a/common/core-components/build.gradle.kts +++ b/common/core-components/build.gradle.kts @@ -20,8 +20,6 @@ kotlin { implementation(Extras.mp3agic) implementation(Extras.Android.countly) implementation(project(":ffmpeg:android-ffmpeg")) -// implementation("com.arthenica:ffmpeg-kit-audio:4.4.LTS") - //api(files("$rootDir/libs/mobile-ffmpeg.aar")) } } desktopMain { diff --git a/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt b/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt index deacfd15..e938f683 100644 --- a/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt +++ b/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt @@ -140,19 +140,19 @@ class AndroidFileManager( .setId3v2TagsAndSaveFile(trackDetails, trackDetails.outputFilePath) addToLibrary(trackDetails.outputFilePath) - File(convertedFilePath).delete() }.fold( success = {}, failure = { throw it } ) + File(convertedFilePath).delete() } else throw e } SuspendableEvent.success(trackDetails.outputFilePath) } catch (e: Throwable) { e.printStackTrace() - //if (songFile.exists()) songFile.delete() + if (songFile.exists()) songFile.delete() logger.e { "${songFile.absolutePath} could not be created" } SuspendableEvent.error(e) } diff --git a/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/media_converter/AndroidMediaConverter.kt b/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/media_converter/AndroidMediaConverter.kt index faed068f..fafb2a33 100644 --- a/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/media_converter/AndroidMediaConverter.kt +++ b/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/media_converter/AndroidMediaConverter.kt @@ -1,48 +1,68 @@ package com.shabinder.common.core_components.media_converter +import android.content.Context +import android.util.Log import com.shabinder.common.models.AudioQuality +import com.shabinder.common.models.SpotiFlyerException +import kotlinx.coroutines.delay +import nl.bravobit.ffmpeg.ExecuteBinaryResponseHandler +import nl.bravobit.ffmpeg.FFmpeg import org.koin.dsl.bind import org.koin.dsl.module -class AndroidMediaConverter : MediaConverter() { +class AndroidMediaConverter(private val appContext: Context) : MediaConverter() { + override suspend fun convertAudioFile( inputFilePath: String, outputFilePath: String, audioQuality: AudioQuality, progressCallbacks: (Long) -> Unit, ) = executeSafelyInPool { + var progressing = true + var timeout = 600_000L * 2 // 20 min + val progressDelayCheck = 500L // 192 is Default val audioBitrate = if (audioQuality == AudioQuality.UNKNOWN) 192 else audioQuality.kbps.toIntOrNull() ?: 192 + FFmpeg.getInstance(appContext).execute( + arrayOf( + "-i", + inputFilePath, + "-y", /*"-acodec", "libmp3lame",*/ + "-b:a", + "${audioBitrate}k", + "-vn", + outputFilePath + ), object : ExecuteBinaryResponseHandler() { + override fun onSuccess(message: String?) { + //Log.d("FFmpeg Command", "Success $message") + progressing = false + } - "" - //runTranscode(inputFilePath,outputFilePath,audioBitrate).toString() - /*val kbpsArg = if (audioQuality == AudioQuality.UNKNOWN) { - val mediaInformation = FFprobeKit.getMediaInformation(inputFilePath) - val bitrate = ((mediaInformation.mediaInformation.bitrate).toFloat()/1000).roundToInt() - Log.d("MEDIA-INPUT Bit", bitrate.toString()) - "-b:a ${bitrate}k" - } else "-b:a ${audioQuality.kbps}k" - // -acodec libmp3lame - val session = FFmpegKit.execute( - "-i $inputFilePath -y $kbpsArg -acodec libmp3lame -vn $outputFilePath" - ) + override fun onProgress(message: String?) { + super.onProgress(message) + Log.d("FFmpeg Progress", "Progress $message --- $inputFilePath") + } - when (session.returnCode.value) { - ReturnCode.SUCCESS -> { - //FFMPEG task Completed - outputFilePath - } - ReturnCode.CANCEL -> { - throw SpotiFlyerException.MP3ConversionFailed("FFmpeg Conversion Canceled for $inputFilePath") + override fun onFailure(message: String?) { + Log.d("FFmpeg Command", "Failed $message") + progressing = false + throw SpotiFlyerException.MP3ConversionFailed(message = "Android FFmpeg Failed: $message") + } } - else -> throw SpotiFlyerException.MP3ConversionFailed("FFmpeg Conversion Failed for $inputFilePath") - }*/ + ) + while (progressing) { + if (timeout < 0) throw SpotiFlyerException.MP3ConversionFailed("Conversion Timeout for $inputFilePath") + delay(progressDelayCheck) + timeout -= progressDelayCheck + } + // Return output file path after successful conversion + outputFilePath } } internal actual fun mediaConverterModule() = module { - single { AndroidMediaConverter() } bind MediaConverter::class + single { AndroidMediaConverter(get()) } bind MediaConverter::class } \ No newline at end of file