diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..4abdea1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "audio_mixer/src/main/cpp/oboe"]
+ path = audio_mixer/src/main/cpp/oboe
+ url = https://github.com/google/oboe
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index ba01ea0..99a25fd 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -4,10 +4,10 @@
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index a5f05cd..851ab99 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -21,5 +21,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7bfef59..7af94e4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,13 @@
-
+
+
+
+
+
+
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..e2ca0ed 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bf591b6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Rakibul Hasan Rajib
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/app/build.gradle b/app/build.gradle
index 95c8fa6..24d504a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,8 +1,7 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 29
- buildToolsVersion "29.0.3"
+ compileSdkVersion 32
defaultConfig {
applicationId "zeroonezero.android.audiomixer"
@@ -29,11 +28,11 @@ android {
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ implementation 'androidx.appcompat:appcompat:1.5.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation project(":audio_mixer")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 53de23d..9f0ee82 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,7 +13,8 @@
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
-
+
diff --git a/app/src/main/java/zeroonezero/android/audiomixer/MainActivity.java b/app/src/main/java/zeroonezero/android/audiomixer/MainActivity.java
index 72d7ce8..6bdd1f8 100644
--- a/app/src/main/java/zeroonezero/android/audiomixer/MainActivity.java
+++ b/app/src/main/java/zeroonezero/android/audiomixer/MainActivity.java
@@ -9,7 +9,9 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
+import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -18,6 +20,7 @@
import android.view.View;
import android.widget.Toast;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -53,6 +56,13 @@ public void onClick(View v) {
}
});
+ findViewById(R.id.add_video_audio_btn).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openVideoChooser();
+ }
+ });
+
findViewById(R.id.mix_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -76,6 +86,19 @@ public void onClick(View v) {
}
});
+ findViewById(R.id.play_btn).setOnClickListener(v -> {
+ File file=new File(outputPath);
+ MediaPlayer mediaPlayer = new MediaPlayer();
+ mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ try {
+ mediaPlayer.setDataSource(getApplicationContext(), Uri.fromFile(file));
+ mediaPlayer.prepare();
+ mediaPlayer.start();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+
checkPermission();
}
@@ -109,7 +132,7 @@ private void startMixing(){
}catch (Exception e){
e.printStackTrace();
}
- //audioMixer.setSampleRate(44100); // optional
+ audioMixer.setSampleRate(48000); // optional
//audioMixer.setBitRate(128000); // optional
//audioMixer.setChannelCount(2); // 1 or 2 // optional
//audioMixer.setLoopingEnabled(true); // Only works for parallel mixing
@@ -163,6 +186,14 @@ public void openChooser(){
startActivityForResult(intent, AUDIO_CHOOSE_REQUEST_CODE);
}
+ public void openVideoChooser(){
+ Intent intent = new Intent();
+ intent.setType("video/*");
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ startActivityForResult(intent, AUDIO_CHOOSE_REQUEST_CODE);
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@@ -207,9 +238,10 @@ private boolean checkPermission() {
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
- if ( grantResults.length > 1
+ if (grantResults.length > 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 3e7f29b..a8a92ac 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -11,6 +11,12 @@
android:orientation="vertical"
android:layout_centerInParent="true">
+
+
+
+
\ No newline at end of file
diff --git a/audio_mixer/build.gradle b/audio_mixer/build.gradle
index f8954fa..ba898c9 100644
--- a/audio_mixer/build.gradle
+++ b/audio_mixer/build.gradle
@@ -1,17 +1,23 @@
-apply plugin: 'com.android.library'
-
+plugins {
+ id 'com.android.library'
+ id 'maven-publish'
+}
android {
- compileSdkVersion 29
- buildToolsVersion "29.0.3"
+ compileSdkVersion 32
defaultConfig {
minSdkVersion 18
- targetSdkVersion 29
+ targetSdkVersion 32
versionCode 1
- versionName "1.0"
-
+ versionName "1.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
+ externalNativeBuild {
+ cmake {
+ cppFlags ""
+ arguments "-DRESAMPLER_OUTER_NAMESPACE=zeroonezero.android.audio_mixer -Wc++17-extensions"
+ }
+ }
}
buildTypes {
@@ -19,19 +25,53 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
+ debug {
+ minifyEnabled false
+ }
}
compileOptions{
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+ externalNativeBuild {
+ cmake {
+ path file('src/main/cpp/CMakeLists.txt')
+ version '3.18.1'
+ }
+ }
+ publishing {
+ singleVariant('release') {
+ }
+ singleVariant('debug') {
+ }
+ }
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation 'androidx.appcompat:appcompat:1.1.0'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ implementation 'androidx.appcompat:appcompat:1.5.0'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+
+}
+
+repositories {
+ mavenLocal()
+}
-}
\ No newline at end of file
+apply from: '../maven-publish-helper.gradle'
+
+publishing {
+ publications {
+ release(MavenPublication) {
+ groupId 'zeroonezero.android.audio_mixer'
+ artifactId = 'android_audio_mixer'
+ }
+ debug(MavenPublication) {
+ groupId 'zeroonezero.android.audio_mixer'
+ artifactId = 'android_audio_mixer-debug'
+ }
+ }
+}
diff --git a/audio_mixer/src/main/cpp/CMakeLists.txt b/audio_mixer/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..a80ea5d
--- /dev/null
+++ b/audio_mixer/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,78 @@
+
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.18.1)
+
+# Declares and names the project.
+
+project("libaudio_mixer")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
+
+set (OBOE_DIR ./oboe)
+set (OBOE_SOURCES
+ ${OBOE_DIR}/src/flowgraph/resampler/IntegerRatio.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/LinearResampler.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/MultiChannelResampler.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/PolyphaseResampler.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/SincResampler.cpp
+ ${OBOE_DIR}/src/flowgraph/resampler/SincResamplerStereo.cpp)
+
+
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+add_library( # Sets the name of the library.
+ libaudio_mixer
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # Provides a relative path to your source file(s).
+ audio_mixer.cpp
+ ${OBOE_SOURCES}
+ )
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+find_library( # Sets the name of the path variable.
+ log-lib
+
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ log )
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+# Add the Oboe library as a subdirectory in your project.
+# add_subdirectory tells CMake to look in this directory to
+# compile oboe source files using oboe's CMake file.
+# ./oboe specifies where the compiled binaries will be stored
+#add_subdirectory (${OBOE_DIR} ./oboe)
+
+# Specify the path to the Oboe header files.
+# This allows targets compiled with this CMake (application code)
+# to see public Oboe headers, in order to access its API.
+#include_directories (${OBOE_DIR}/include)
+
+
+target_link_libraries( # Specifies the target library.
+ libaudio_mixer
+
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib}
+ #oboe
+ )
diff --git a/audio_mixer/src/main/cpp/audio_mixer.cpp b/audio_mixer/src/main/cpp/audio_mixer.cpp
new file mode 100644
index 0000000..b9f7213
--- /dev/null
+++ b/audio_mixer/src/main/cpp/audio_mixer.cpp
@@ -0,0 +1,102 @@
+#include "oboe/src/flowgraph/resampler/MultiChannelResampler.h"
+#include
+#include
+#include
+#include
+#include
+#define LOG_TAG "resampler"
+#define ALOG(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
+
+
+long long createResampler(int channelCount,int inputSampleRate,int outputSampleRate){
+ oboe::resampler::MultiChannelResampler *resampler = oboe::resampler::MultiChannelResampler::make(
+ channelCount, // channel count
+ inputSampleRate, // input sampleRate
+ outputSampleRate, // output sampleRate
+ oboe::resampler::MultiChannelResampler::Quality::Best);
+ return (long long) resampler;
+}
+
+void deleteResampler(long long resamplerPointer){
+ oboe::resampler::MultiChannelResampler *resampler= (oboe::resampler::MultiChannelResampler*) resamplerPointer;
+ delete resampler;
+}
+
+int resample(long long resamplerPointer,int channelCount, float* inputBuffer,float* outputBuffer,int numInputFrames){
+ //ALOG("Resample c++ Called!!!!!\n");
+ oboe::resampler::MultiChannelResampler *resampler = (oboe::resampler::MultiChannelResampler*) resamplerPointer;
+
+ //ALOG("Created Resampler with following Settings: Input SampleRate:%d, Output SampleRate: %d, Channels: %d, Num of Input Samples: %d",inputSampleRate,outputSampleRate,channelCount,numInputFrames);
+ int numOutputFrames = 0;
+ int inputFramesLeft = numInputFrames/channelCount;
+ while (inputFramesLeft > -1) {
+ //ALOG("%d Frames Left",inputFramesLeft);d
+ if(resampler->isWriteNeeded()) {
+ if(inputFramesLeft>0) {
+ resampler->writeNextFrame(inputBuffer);
+ inputBuffer += channelCount;
+ }
+ inputFramesLeft--;
+ } else {
+ resampler->readNextFrame(outputBuffer);
+ outputBuffer += channelCount;
+ numOutputFrames++;
+ }
+ }
+ //ALOG("num Output frames:%d",numOutputFrames);
+ return numOutputFrames * channelCount;
+}
+
+extern "C"
+JNIEXPORT jint JNICALL
+Java_zeroonezero_android_audio_1mixer_resample_DifferentSampleRateResampler_resampleCBuffer(JNIEnv *env,
+ jobject thiz,
+ jlong resamplerPointer,
+ jint channel_count,
+ jobject input_buffer,
+ jobject output_buffer,
+ jint num_input_frames) {
+ //ALOG("Starting Conversion");
+
+ //ALOG("Input Capicity send%d, real %lld",num_input_frames,env->GetDirectBufferCapacity(input_buffer));
+ //jfloat *inputBuffer= (jfloat *)(env->GetDirectBufferAddress(input_buffer));
+ jshort *inputShort=(jshort *)(env->GetDirectBufferAddress(input_buffer));
+ float inputBuffer[num_input_frames];
+ std::transform(inputShort, inputShort + num_input_frames, inputBuffer, [](int f){
+ return f;
+ });
+ //jfloat* outputBuffer= (jfloat *)(env->GetDirectBufferAddress(output_buffer));
+ jshort *outputShort= (jshort *)(env->GetDirectBufferAddress(output_buffer));
+ float outputBuffer[env->GetDirectBufferCapacity(output_buffer)];
+ //ALOG("Finished Conversion, starting Resample");
+ int outputLength=resample(resamplerPointer,channel_count, inputBuffer, outputBuffer, num_input_frames);
+ //ALOG("Finished Resample, starting Conversion");
+ std::transform(outputBuffer, outputBuffer + outputLength, outputShort, [](float f){
+ short x= std::round(f);
+ //ALOG("Float %f to Short %d",f,x);
+ return x;
+ });
+ return outputLength;
+}
+/*extern "C"
+JNIEXPORT void JNICALL
+Java_zeroonezero_android_audio_1mixer_resample_DifferentSampleRateResampler_test(JNIEnv *env,
+ jclass thiz) {
+ //ALOG("Successfully initialised audio_mixer.cpp");
+}
+*/
+extern "C"
+JNIEXPORT jlong JNICALL
+Java_zeroonezero_android_audio_1mixer_resample_DifferentSampleRateResampler_createResampler(
+ JNIEnv *env, jobject thiz, jint channel_count, jint input_sample_rate,
+ jint output_sample_rate) {
+ return createResampler(channel_count,input_sample_rate,output_sample_rate);
+}
+
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_zeroonezero_android_audio_1mixer_resample_DifferentSampleRateResampler_deleteResampler(
+ JNIEnv *env, jobject thiz, jlong resampler_pointer) {
+ deleteResampler(resampler_pointer);
+}
\ No newline at end of file
diff --git a/audio_mixer/src/main/cpp/oboe b/audio_mixer/src/main/cpp/oboe
new file mode 160000
index 0000000..574c882
--- /dev/null
+++ b/audio_mixer/src/main/cpp/oboe
@@ -0,0 +1 @@
+Subproject commit 574c8824c9ce5109d6128922ad7e4d35aab379ed
diff --git a/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/AudioResampler.java b/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/AudioResampler.java
index a0b8b88..1bc17a9 100644
--- a/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/AudioResampler.java
+++ b/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/AudioResampler.java
@@ -5,8 +5,8 @@
import java.nio.ShortBuffer;
/**
- * Resamples audio data. See {@link UpsampleAudioResampler} or
- * {@link DownsampleAudioResampler} for concrete implementations.
+ * Resamples audio data. See {@link DifferentSampleRateResampler} or
+ * {@link PassThroughAudioResampler} for concrete implementations.
*/
public interface AudioResampler {
@@ -21,9 +21,5 @@ public interface AudioResampler {
*/
void resample(@NonNull final ShortBuffer inputBuffer, int inputSampleRate, @NonNull final ShortBuffer outputBuffer, int outputSampleRate, int channels);
- AudioResampler DOWNSAMPLE = new DownsampleAudioResampler();
-
- AudioResampler UPSAMPLE = new UpsampleAudioResampler();
-
AudioResampler PASSTHROUGH = new PassThroughAudioResampler();
}
diff --git a/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DefaultAudioResampler.java b/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DefaultAudioResampler.java
index 88b7837..20c8058 100644
--- a/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DefaultAudioResampler.java
+++ b/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DefaultAudioResampler.java
@@ -3,6 +3,9 @@
import androidx.annotation.NonNull;
import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
/**
* An {@link AudioResampler} that delegates to appropriate classes
@@ -10,13 +13,30 @@
*/
public class DefaultAudioResampler implements AudioResampler {
+
+ private static class AudioResamplerBuffer{
+ private final HashMap resamplers;
+ private AudioResamplerBuffer(int maxItems){
+ resamplers=new HashMap<>(maxItems);
+ }
+ private AudioResampler getResampler(int inputSampleRate, int outputSampleRate, int channelCount){
+ String hashString=inputSampleRate+":"+outputSampleRate+":"+channelCount;
+ AudioResampler r=resamplers.get(hashString);
+ if(r == null){
+ r=new DifferentSampleRateResampler(inputSampleRate,outputSampleRate,channelCount);
+ resamplers.put(hashString,r);
+ }
+ return r;
+ }
+ }
+
+ AudioResamplerBuffer buffer= new AudioResamplerBuffer(1);
+
@Override
public void resample(@NonNull ShortBuffer inputBuffer, int inputSampleRate, @NonNull ShortBuffer outputBuffer, int outputSampleRate, int channels) {
- if (inputSampleRate < outputSampleRate) {
- UPSAMPLE.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels);
- } else if (inputSampleRate > outputSampleRate) {
- DOWNSAMPLE.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels);
- } else {
+ if (inputSampleRate != outputSampleRate) {
+ buffer.getResampler(inputSampleRate,outputSampleRate,channels).resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels);
+ }else {
PASSTHROUGH.resample(inputBuffer, inputSampleRate, outputBuffer, outputSampleRate, channels);
}
}
diff --git a/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DifferentSampleRateResampler.java b/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DifferentSampleRateResampler.java
new file mode 100644
index 0000000..c0943df
--- /dev/null
+++ b/audio_mixer/src/main/java/zeroonezero/android/audio_mixer/resample/DifferentSampleRateResampler.java
@@ -0,0 +1,58 @@
+package zeroonezero.android.audio_mixer.resample;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+/**
+ * An {@link AudioResampler} that upsamples/downsamples from a lower/higher sample rate to a higher/lower sample rate.
+ */
+public class DifferentSampleRateResampler implements AudioResampler {
+ long resamplerPointer;
+
+ public DifferentSampleRateResampler(int inputSampleRate, int outputSampleRate,int channelCount){
+ resamplerPointer=createResampler(channelCount,inputSampleRate,outputSampleRate);
+
+ }
+ static {
+ try {
+ System.loadLibrary("libaudio_mixer");
+ Log.i("resampler","Successfully loaded native libaudio_mixer.so");
+ //test();
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+
+
+ @Override
+ public void resample(@NonNull ShortBuffer inputBuffer, int inputSampleRate, @NonNull ShortBuffer outputBuffer, int outputSampleRate, int channels) {
+ try {
+ inputBuffer.rewind();
+ int remaining=inputBuffer.remaining();
+ int oldPosition=outputBuffer.position();//8 hours of Debugging to add this line, before that nothing worked
+ int newPosition=resampleCBuffer(resamplerPointer,channels, inputBuffer, outputBuffer, remaining) + oldPosition;
+ outputBuffer.position(newPosition);//8 hours of Debugging to add this line, before that nothing worked
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ native int resampleCBuffer(long resamplerPointer,int channelCount, ShortBuffer inputBuffer, ShortBuffer outputBuffer, int numInputBufferSamples);
+
+ native long createResampler(int channelCount, int inputSampleRate, int outputSampleRate);
+
+ native void deleteResampler(long resamplerPointer);
+
+ @Override
+ protected void finalize() throws Throwable {
+ deleteResampler(resamplerPointer);
+ super.finalize();
+ }
+
+ //native static void test();
+}
diff --git a/build.gradle b/build.gradle
index da807a2..8f8a149 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,10 +2,10 @@
buildscript {
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath "com.android.tools.build:gradle:4.0.0"
+ classpath 'com.android.tools.build:gradle:7.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -15,7 +15,7 @@ buildscript {
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 10d2b11..78050f0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
diff --git a/maven-publish-helper.gradle b/maven-publish-helper.gradle
new file mode 100644
index 0000000..b64fe4c
--- /dev/null
+++ b/maven-publish-helper.gradle
@@ -0,0 +1,78 @@
+/**
+ * Maven Publish Helper
+ *
+ * Requires Android Gradle plugin 3.6.0 or higher (available since Android Studio 3.6).
+ * See also: https://developer.android.com/studio/build/maven-publish-plugin
+ *
+ * @Author Robert Pösel
+ * @Author hlvs-apps
+ * @Version 1.5
+ * @Date 3.3.2020
+ */
+
+apply plugin: 'maven-publish'
+
+
+// To build to Maven Local ./gradlew build publishToMavenLocal
+
+task androidJavadocs(type: Javadoc) {
+ source = android.sourceSets.main.java.srcDirs
+ classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+ android.libraryVariants.all { variant ->
+ if (variant.name == 'release' || variant.name == 'debug') {
+ owner.classpath += variant.javaCompileProvider.get().classpath
+ }
+ }
+ exclude '**/R.html', '**/R.*.html', '**/index.html'
+}
+
+tasks.withType(Javadoc) {
+ failOnError false
+ options.addStringOption('Xdoclint:none', '-quiet')
+ options.addStringOption('encoding', 'UTF-8')
+ options.addStringOption('charSet', 'UTF-8')
+}
+
+task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
+ archiveClassifier.set('javadoc')
+ from androidJavadocs.destinationDir
+}
+
+task androidSourcesJar(type: Jar) {
+ archiveClassifier.set('sources')
+ from android.sourceSets.main.java.srcDirs
+}
+
+// Because the components are created only during the afterEvaluate phase, you must
+// configure your publications using the afterEvaluate() lifecycle method.
+afterEvaluate {
+ publishing {
+ publications {
+ // Creates a Maven publication called "release".
+ release(MavenPublication) {
+ // Applies the component for the release build variant.
+ from components.release
+
+ // Adds javadocs and sources as separate jars.
+ artifact androidJavadocsJar
+ artifact androidSourcesJar
+
+ // You can customize attributes of the publication here or in module's build.gradle file.
+ //groupId = 'com.example'
+ //artifactId = 'custom-artifact'
+ version = android.defaultConfig.versionName
+ }
+ debug(MavenPublication) {
+ from components.debug
+ // Adds javadocs and sources as separate jars.
+ artifact androidJavadocsJar
+ artifact androidSourcesJar
+
+ // You can customize attributes of the publication here or in module's build.gradle file.
+ //groupId = 'com.example'
+ //artifactId = 'custom-artifact'
+ version = android.defaultConfig.versionName // or just '1.0'
+ }
+ }
+ }
+}
\ No newline at end of file