diff --git a/app/build.gradle b/app/build.gradle index e92996b..6246bdc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { minSdkVersion 21 targetSdkVersion 30 versionCode 1 - versionName "1.8" - + versionName "2.1.3" + project.archivesBaseName = "Amplituda" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' diff --git a/app/consumer-rules.pro b/app/consumer-rules.pro index e69de29..f2aa9cc 100644 --- a/app/consumer-rules.pro +++ b/app/consumer-rules.pro @@ -0,0 +1,23 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-keep class linc.com.amplituda.** { *; } diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index 9475d8d..bc4b065 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -366,9 +366,9 @@ Java_linc_com_amplituda_Amplituda_amplitudesFromAudioJNI( // read frames from the file while (av_read_frame(fmt_ctx, pkt) >= 0) { - + bool is_audio_stream = pkt->stream_index == audio_stream_idx; // check if the packet belongs to a stream we are interested in, otherwise skip it - if (pkt->stream_index == audio_stream_idx) { + if (is_audio_stream) { ret = decode_packet(audio_dec_ctx, pkt, &temp_data, &errors_data); // compress data when current_frame_idx is compression_divider @@ -396,7 +396,11 @@ Java_linc_com_amplituda_Amplituda_amplitudesFromAudioJNI( current_progress = progress; } } - current_frame_idx++; + + // Count only audio stream frames (this will prevent +100% progress for video processing) + if(is_audio_stream) { + current_frame_idx++; + } } // make one last progress listener call diff --git a/app/src/main/java/linc/com/amplituda/Amplituda.java b/app/src/main/java/linc/com/amplituda/Amplituda.java index e936090..a6a0287 100644 --- a/app/src/main/java/linc/com/amplituda/Amplituda.java +++ b/app/src/main/java/linc/com/amplituda/Amplituda.java @@ -4,6 +4,7 @@ import android.webkit.URLUtil; import java.io.File; +import java.io.InputStream; import linc.com.amplituda.exceptions.*; import linc.com.amplituda.exceptions.io.*; @@ -41,6 +42,14 @@ public AmplitudaProcessingOutput processAudio(final int audio) { return processAudio(audio, null, null); } + public AmplitudaProcessingOutput processAudio(final InputStream audio) { + return processAudio(audio, null, null); + } + + public AmplitudaProcessingOutput processAudio(final byte[] audio) { + return processAudio(audio, null, null); + } + /** Audio file + compress params */ public AmplitudaProcessingOutput processAudio(final File audio, final Compress compressParams) { @@ -55,6 +64,14 @@ public AmplitudaProcessingOutput processAudio(final int audio, final Co return processAudio(audio, compressParams, null); } + public AmplitudaProcessingOutput processAudio(final InputStream audio, final Compress compressParams) { + return processAudio(audio, compressParams, null); + } + + public AmplitudaProcessingOutput processAudio(final byte[] audio, final Compress compressParams) { + return processAudio(audio, compressParams, null); + } + /** Audio file + progress listener */ public AmplitudaProcessingOutput processAudio(final File audio, final AmplitudaProgressListener listener) { @@ -69,6 +86,14 @@ public AmplitudaProcessingOutput processAudio(final int audio, final Am return processAudio(audio, null, listener); } + public AmplitudaProcessingOutput processAudio(final InputStream audio, final AmplitudaProgressListener listener) { + return processAudio(audio, null, listener); + } + + public AmplitudaProcessingOutput processAudio(final byte[] audio, final AmplitudaProgressListener listener) { + return processAudio(audio, null, listener); + } + public AmplitudaProcessingOutput processAudio( final File audio, final Compress compress, @@ -195,6 +220,68 @@ public AmplitudaProcessingOutput processAudio( } } + /** + * Calculate amplitudes from file + * @param audio - uri source file + */ + public AmplitudaProcessingOutput processAudio( + final InputStream audio, + final Compress compress, + final AmplitudaProgressListener listener + ) { + startProgress(listener); + InputAudio inputAudio = new InputAudio<>(audio, InputAudio.Type.INPUT_STREAM); + try { + updateProgressOperation(listener, ProgressOperation.DECODING); + File audioFile = fileManager.getUriFile(audio, listener); + AmplitudaProcessingOutput output = new AmplitudaProcessingOutput<>( + processFileJNI( + audioFile, + inputAudio, + getValidCompression(compress), + listener + ), + inputAudio + ); + fileManager.deleteFile(audioFile); + return output; + } catch (AmplitudaException exception) { + // Handle processing error + return errorOutput(exception, inputAudio, listener); + } + } + + /** + * Calculate amplitudes from file + * @param audio - uri source file + */ + public AmplitudaProcessingOutput processAudio( + final byte[] audio, + final Compress compress, + final AmplitudaProgressListener listener + ) { + startProgress(listener); + InputAudio inputAudio = new InputAudio<>(audio, InputAudio.Type.BYTE_ARRAY); + try { + updateProgressOperation(listener, ProgressOperation.DECODING); + File audioFile = fileManager.getByteArrayFile(audio, listener); + AmplitudaProcessingOutput output = new AmplitudaProcessingOutput<>( + processFileJNI( + audioFile, + inputAudio, + getValidCompression(compress), + listener + ), + inputAudio + ); + fileManager.deleteFile(audioFile); + return output; + } catch (AmplitudaException exception) { + // Handle processing error + return errorOutput(exception, inputAudio, listener); + } + } + /** * Calculate amplitudes from file * @param audio - source file @@ -210,10 +297,6 @@ private AmplitudaResultJNI processFileJNI( throw new FileNotFoundException(); } - if(!fileManager.isAudioFile(audio.getPath())) { - throw new FileOpenException(); - } - // Save start time long startTime = System.currentTimeMillis(); diff --git a/app/src/main/java/linc/com/amplituda/FileManager.java b/app/src/main/java/linc/com/amplituda/FileManager.java index 54030a0..a9cdb0e 100644 --- a/app/src/main/java/linc/com/amplituda/FileManager.java +++ b/app/src/main/java/linc/com/amplituda/FileManager.java @@ -2,7 +2,7 @@ import android.content.Context; import android.content.res.Resources; -import android.media.MediaMetadataRetriever; +import android.net.Uri; import android.webkit.MimeTypeMap; import java.io.BufferedInputStream; @@ -12,7 +12,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Locale; @@ -20,7 +19,7 @@ final class FileManager { - static final String RAW_TEMP = "amplituda_tmp_raw"; + static final String AMPLITUDA_INTERNAL_TEMP = "amplituda_internal_temp"; private final Resources resources; private final String cache; @@ -29,23 +28,6 @@ final class FileManager { cache = context.getCacheDir().getPath() + File.separator; } - /** - * Validate audio file - * @param path - audio file path - * @return true when file with path is audio file. - */ - synchronized boolean isAudioFile(final String path) { - try { - MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); - mediaMetadataRetriever.setDataSource(path); - return mediaMetadataRetriever.extractMetadata( - MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO - ).equalsIgnoreCase("yes"); - } catch (Exception ignored) { - return false; - } - } - /** * Delete local storage file */ @@ -61,7 +43,7 @@ synchronized void deleteFile(final File file) { * @return raw file from local storage */ synchronized File getRawFile(final int resource, final AmplitudaProgressListener listener) { - File temp = new File(cache, RAW_TEMP); + File temp = new File(cache, AMPLITUDA_INTERNAL_TEMP); try { InputStream inputStream = resources.openRawResource(resource); streamToFile(inputStream, temp, 1024 * 4, inputStream.available(), listener); @@ -77,14 +59,7 @@ synchronized File getRawFile(final int resource, final AmplitudaProgressListener * @return audio file from local storage */ synchronized File getUrlFile(final String audioUrl, final AmplitudaProgressListener listener) { - File temp = new File(String.format( - Locale.US, - "%s%s.%s", - cache, - RAW_TEMP, - MimeTypeMap.getFileExtensionFromUrl(audioUrl) - )); - + File temp = new File(cache, AMPLITUDA_INTERNAL_TEMP); try { URL url = new URL(audioUrl); URLConnection connection = url.openConnection(); @@ -103,6 +78,38 @@ synchronized File getUrlFile(final String audioUrl, final AmplitudaProgressListe return temp; } + /** + * Copy audio from Uri to local storage + * @param audioStream - audio file stream + * @return audio file from local storage + */ + synchronized File getUriFile(final InputStream audioStream, final AmplitudaProgressListener listener) { + File temp = new File(cache, AMPLITUDA_INTERNAL_TEMP); + try { + streamToFile(audioStream, temp, 1024 * 4, audioStream.available(), listener); + return temp; + } catch (Resources.NotFoundException | IOException ignored) { + return null; + } + } + + /** + * Copy audio from Uri to local storage + * @param audioByteArray - audio file stream + * @return audio file from local storage + */ + synchronized File getByteArrayFile(final byte[] audioByteArray, final AmplitudaProgressListener listener) { + File temp = new File(cache, AMPLITUDA_INTERNAL_TEMP); + try (FileOutputStream outputStream = new FileOutputStream(temp)) { + listener.onProgressInternal(0); + outputStream.write(audioByteArray); + listener.onProgressInternal(100); + return temp; + } catch (IOException ignored) { + return null; + } + } + /** * Copy audio from URL to local storage * @param inputStream - audio file input stream diff --git a/app/src/main/java/linc/com/amplituda/InputAudio.java b/app/src/main/java/linc/com/amplituda/InputAudio.java index 01d889f..3a762d4 100644 --- a/app/src/main/java/linc/com/amplituda/InputAudio.java +++ b/app/src/main/java/linc/com/amplituda/InputAudio.java @@ -46,6 +46,6 @@ void setType(Type type) { } public enum Type { - FILE, PATH, URL, RESOURCE + FILE, PATH, URL, RESOURCE, INPUT_STREAM, BYTE_ARRAY } } diff --git a/example/build.gradle b/example/build.gradle index 6d0ac91..72a2b81 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -31,12 +31,4 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.2.0' implementation project(":app") - - - - // ReactiveX -// def rx_version = "3.0.0" -// implementation "io.reactivex.rxjava3:rxandroid:$rx_version" -// implementation "io.reactivex.rxjava3:rxjava:$rx_version" - } diff --git a/example/proguard-rules.pro b/example/proguard-rules.pro index 481bb43..8d7c051 100644 --- a/example/proguard-rules.pro +++ b/example/proguard-rules.pro @@ -18,4 +18,6 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-keep class linc.com.amplituda.** { *; } \ No newline at end of file diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml index c29ee95..23c9cf5 100644 --- a/example/src/main/AndroidManifest.xml +++ b/example/src/main/AndroidManifest.xml @@ -3,7 +3,6 @@ package="linc.com.example"> - { printResult(result); - }, exception -> { exception.printStackTrace(); }); + ).get(result -> printResult(result), exception -> exception.printStackTrace()); } private void printResult(AmplitudaResult result) {