Merge branch 'format_error_toast'
diff --git a/samples/build.gradle b/samples/build.gradle
index 46ff563..9570cc6 100644
--- a/samples/build.gradle
+++ b/samples/build.gradle
@@ -27,7 +27,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.0.0'
+        classpath 'com.android.tools.build:gradle:4.0.1'
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
diff --git a/samples/drumthumper/build.gradle b/samples/drumthumper/build.gradle
index cb049b7..79697a7 100644
--- a/samples/drumthumper/build.gradle
+++ b/samples/drumthumper/build.gradle
@@ -10,8 +10,8 @@
         // however, this sample will be published on the Google Play Store which will not allow an
         // applicationId starting with "com.google" as this is reserved for official Google
         // products. The current owner of Oboe sample apps on Google Play is Phil Burk, who
-        // publishes using the application Id prefix of "com.mobileer".
-        applicationId "com.mobileer.drumthumper"
+        // publishes using the application Id prefix of "com.plausiblesoftware".
+        applicationId "com.plausiblesoftware.drumthumper"
         minSdkVersion 26
         targetSdkVersion 29
         versionCode 1
diff --git a/samples/drumthumper/playstore/DrumSetFeatureImage.png b/samples/drumthumper/playstore/DrumSetFeatureImage.png
new file mode 100644
index 0000000..b4ec3c0
--- /dev/null
+++ b/samples/drumthumper/playstore/DrumSetFeatureImage.png
Binary files differ
diff --git a/samples/drumthumper/playstore/ScreenShotPhone.png b/samples/drumthumper/playstore/ScreenShotPhone.png
new file mode 100644
index 0000000..cb07df6
--- /dev/null
+++ b/samples/drumthumper/playstore/ScreenShotPhone.png
Binary files differ
diff --git a/samples/drumthumper/playstore/ScreenShotWithMix.png b/samples/drumthumper/playstore/ScreenShotWithMix.png
new file mode 100644
index 0000000..627993a
--- /dev/null
+++ b/samples/drumthumper/playstore/ScreenShotWithMix.png
Binary files differ
diff --git a/samples/drumthumper/playstore/drumset.jpg b/samples/drumthumper/playstore/drumset.jpg
new file mode 100644
index 0000000..7511be6
--- /dev/null
+++ b/samples/drumthumper/playstore/drumset.jpg
Binary files differ
diff --git a/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp b/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
index 1a2fbbf..5ae41f7 100644
--- a/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
+++ b/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
@@ -45,11 +45,11 @@
  * Native (JNI) implementation of DrumPlayer.setupAudioStreamNative()
  */
 JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_setupAudioStreamNative(
-        JNIEnv* env, jobject, jint numChannels, jint sampleRate) {
+        JNIEnv* env, jobject, jint sampleRate, jint numChannels) {
     __android_log_print(ANDROID_LOG_INFO, TAG, "%s", "init()");
 
     // we know in this case that the sample buffers are all 1-channel, 41K
-    sDTPlayer.setupAudioStream(numChannels, sampleRate);
+    sDTPlayer.setupAudioStream(sampleRate, numChannels);
 }
 
 /**
@@ -68,7 +68,8 @@
 /**
  * Native (JNI) implementation of DrumPlayer.loadWavAssetNative()
  */
-JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_loadWavAssetNative(JNIEnv* env, jobject, jbyteArray bytearray, jint index, jfloat pan) {
+JNIEXPORT jboolean JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_loadWavAssetNative(
+        JNIEnv* env, jobject, jbyteArray bytearray, jint index, jfloat pan, jint rate, jint channels) {
     int len = env->GetArrayLength (bytearray);
 
     unsigned char* buf = new unsigned char[len];
@@ -79,6 +80,9 @@
     WavStreamReader reader(&stream);
     reader.parse();
 
+    jboolean isFormatValid =
+            (reader.getSampleRate() == rate) && (reader.getNumChannels() == channels);
+
     SampleBuffer* sampleBuffer = new SampleBuffer();
     sampleBuffer->loadSampleData(&reader);
 
@@ -86,6 +90,8 @@
     sDTPlayer.addSampleSource(source, sampleBuffer);
 
     delete[] buf;
+
+    return isFormatValid;
 }
 
 /**
diff --git a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
index cbcf323..8d50510 100644
--- a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
+++ b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
@@ -22,10 +22,11 @@
 class DrumPlayer {
     companion object {
         // Sample attributes
-        val NUM_CHANNELS: Int = 2       // The number of channels in the player Stream.
+        val NUM_PLAY_CHANNELS: Int = 2  // The number of channels in the player Stream.
                                         // Stereo Playback, set to 1 for Mono playback
                                         // This IS NOT the channel format of the source samples
                                         // (which must be mono).
+        val NUM_SAMPLE_CHANNELS: Int = 1;   // All WAV resource must be mono
         val SAMPLE_RATE: Int = 44100    // All the input samples are assumed to BE 44.1K
                                         // All the input samples are assumed to be mono.
 
@@ -54,7 +55,7 @@
     }
 
     fun setupAudioStream() {
-        setupAudioStreamNative(NUM_CHANNELS, SAMPLE_RATE)
+        setupAudioStreamNative(SAMPLE_RATE, NUM_PLAY_CHANNELS)
     }
 
     fun teardownAudioStream() {
@@ -62,39 +63,46 @@
     }
 
     // asset-based samples
-    fun loadWavAssets(assetMgr: AssetManager) {
-        loadWavAsset(assetMgr, "KickDrum.wav", BASSDRUM, PAN_BASSDRUM)
-        loadWavAsset(assetMgr, "SnareDrum.wav", SNAREDRUM, PAN_SNAREDRUM)
-        loadWavAsset(assetMgr, "CrashCymbal.wav", CRASHCYMBAL, PAN_CRASHCYMBAL)
-        loadWavAsset(assetMgr, "RideCymbal.wav", RIDECYMBAL, PAN_RIDECYMBAL)
-        loadWavAsset(assetMgr, "MidTom.wav", MIDTOM, PAN_MIDTOM)
-        loadWavAsset(assetMgr, "LowTom.wav", LOWTOM, PAN_LOWTOM)
-        loadWavAsset(assetMgr, "HiHat_Open.wav", HIHATOPEN, PAN_HIHATOPEN)
-        loadWavAsset(assetMgr, "HiHat_Closed.wav", HIHATCLOSED, PAN_HIHATCLOSED)
+    fun loadWavAssets(assetMgr: AssetManager): Boolean {
+        var allAssetsCorrect = true
+        allAssetsCorrect = loadWavAsset(assetMgr, "KickDrum.wav", BASSDRUM, PAN_BASSDRUM) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "SnareDrum.wav", SNAREDRUM, PAN_SNAREDRUM) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "CrashCymbal.wav", CRASHCYMBAL, PAN_CRASHCYMBAL) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "RideCymbal.wav", RIDECYMBAL, PAN_RIDECYMBAL) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "MidTom.wav", MIDTOM, PAN_MIDTOM) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "LowTom.wav", LOWTOM, PAN_LOWTOM) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "HiHat_Open.wav", HIHATOPEN, PAN_HIHATOPEN) && allAssetsCorrect
+        allAssetsCorrect = loadWavAsset(assetMgr, "HiHat_Closed.wav", HIHATCLOSED, PAN_HIHATCLOSED) && allAssetsCorrect
+
+        return allAssetsCorrect
     }
 
     fun unloadWavAssets() {
         unloadWavAssetsNative()
     }
 
-    fun loadWavAsset(assetMgr: AssetManager, assetName: String, index: Int, pan: Float) {
+    fun loadWavAsset(assetMgr: AssetManager, assetName: String, index: Int, pan: Float) : Boolean {
+        var returnVal = false
         try {
             val assetFD = assetMgr.openFd(assetName)
             val dataStream = assetFD.createInputStream();
             var dataLen = assetFD.getLength().toInt()
             var dataBytes: ByteArray = ByteArray(dataLen)
             dataStream.read(dataBytes, 0, dataLen)
-            loadWavAssetNative(dataBytes, index, pan)
+            returnVal = loadWavAssetNative(dataBytes, index, pan, SAMPLE_RATE, NUM_SAMPLE_CHANNELS)
             assetFD.close()
         } catch (ex: IOException) {
             Log.i(TAG, "IOException" + ex)
         }
+
+        return returnVal
     }
 
-    external fun setupAudioStreamNative(numChannels: Int, sampleRate: Int)
+    external fun setupAudioStreamNative(sampleRate: Int, numChannels: Int)
     external fun teardownAudioStreamNative()
 
-    external fun loadWavAssetNative(wavBytes: ByteArray, index: Int, pan: Float)
+    external fun loadWavAssetNative(
+            wavBytes: ByteArray, index: Int, pan: Float, rate: Int, channels: Int) : Boolean
     external fun unloadWavAssetsNative()
 
     external fun trigger(drumIndex: Int)
diff --git a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt
index 98a899d..eb90cb8 100644
--- a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt
+++ b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumThumperActivity.kt
@@ -162,7 +162,15 @@
         mAudioMgr = getSystemService(Context.AUDIO_SERVICE) as AudioManager
 
         // mDrumPlayer.allocSampleData()
-        mDrumPlayer.loadWavAssets(getAssets())
+        var allAssetsValid = mDrumPlayer.loadWavAssets(getAssets())
+
+        if (!allAssetsValid) {
+            // show toast
+            val toast = Toast.makeText(this,
+                    "One or more audio assets has an incorrect format and may not play correctly",
+                    Toast.LENGTH_LONG)
+            toast.show()
+        }
     }
 
     override fun onStart() {
diff --git a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
index 5c1a681..6110b29 100644
--- a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
+++ b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
@@ -117,7 +117,7 @@
     return true;
 }
 
-void SimpleMultiPlayer::setupAudioStream(int32_t channelCount, int32_t sampleRate) {
+void SimpleMultiPlayer::setupAudioStream(int32_t sampleRate, int32_t channelCount) {
     __android_log_print(ANDROID_LOG_INFO, TAG, "setupAudioStream()");
     mChannelCount = channelCount;
     mSampleRate = sampleRate;
diff --git a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
index 455bc57..3e0a1c7 100644
--- a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
+++ b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
@@ -41,7 +41,7 @@
     virtual void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
     virtual void onErrorBeforeClose(oboe::AudioStream * oboeStream, oboe::Result error) override;
 
-    void setupAudioStream(int32_t channelCount, int32_t sampleRate);
+    void setupAudioStream(int32_t sampleRate, int32_t channelCount);
     void teardownAudioStream();
 
     bool openStream();