From bafcfbcb393572ac1fddb57874dd44d2ebd09a1a Mon Sep 17 00:00:00 2001 From: chrisws Date: Fri, 27 Sep 2024 19:10:52 +0930 Subject: [PATCH] Fix issue with playing an audio file on android #231 --- configure.ac | 2 +- src/platform/android/app/build.gradle | 6 +- .../android/app/src/main/assets/main.bas | 2 +- .../sourceforge/smallbasic/MainActivity.java | 77 ++++++++++++++----- src/platform/android/build.gradle | 2 +- src/platform/android/jni/runtime.cpp | 2 +- src/platform/android/webui/package.json | 26 +++---- 7 files changed, 78 insertions(+), 39 deletions(-) diff --git a/configure.ac b/configure.ac index 25594cea..674d3ef4 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ dnl This program is distributed under the terms of the GPL v2.0 dnl Download the GNU Public License (GPL) from www.gnu.org dnl -AC_INIT([smallbasic], [12.27]) +AC_INIT([smallbasic], [12.28]) AC_CONFIG_SRCDIR([configure.ac]) AC_CANONICAL_TARGET diff --git a/src/platform/android/app/build.gradle b/src/platform/android/app/build.gradle index 20565d2e..4598232b 100644 --- a/src/platform/android/app/build.gradle +++ b/src/platform/android/app/build.gradle @@ -7,10 +7,10 @@ android { // can override some attributes in main/AndroidManifest.xml defaultConfig { applicationId 'net.sourceforge.smallbasic' - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 34 - versionCode 63 - versionName '12.27' + versionCode 64 + versionName '12.28' resourceConfigurations += ['en'] } diff --git a/src/platform/android/app/src/main/assets/main.bas b/src/platform/android/app/src/main/assets/main.bas index 561ec9fa..0c549761 100644 --- a/src/platform/android/app/src/main/assets/main.bas +++ b/src/platform/android/app/src/main/assets/main.bas @@ -222,7 +222,7 @@ sub do_setup() rect x, y, w * 2, h + y * 2.5 frm.inputs(0).label = "Extension modules:" frm.inputs(1).value = "Ignore|Load" - frm.inputs(1).selectedIndex = iff(loadModules == 1, 1, 0) + frm.inputs(1).selectedIndex = iff(loadModules >= 1, 1, 0) frm = form(frm) while 1 frm.doEvents() diff --git a/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java index ddee08fd..dac767e8 100644 --- a/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java @@ -18,7 +18,6 @@ import android.location.Criteria; import android.location.Location; import android.location.LocationManager; -import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; @@ -105,6 +104,7 @@ public class MainActivity extends NativeActivity { private final Queue _sounds = new ConcurrentLinkedQueue<>(); private final Handler _keypadHandler = new Handler(Looper.getMainLooper()); private final Map permittedHost = new ConcurrentHashMap<>(); + private final Object _mediaPlayerLock = new Object(); private String[] _options = null; private MediaPlayer _mediaPlayer = null; private LocationAdapter _locationAdapter = null; @@ -210,10 +210,7 @@ public void clearSoundQueue() { for (Sound sound : _sounds) { sound.setSilent(true); } - if (_mediaPlayer != null) { - _mediaPlayer.release(); - _mediaPlayer = null; - } + releaseMediaPlayer(); } public boolean closeLibHandlers() { @@ -454,19 +451,35 @@ public void playAudio(final byte[] pathBytes) { new Thread(new Runnable() { public void run() { try { - Uri uri = Uri.parse("file://" + new String(pathBytes, CP1252)); - if (_mediaPlayer == null) { - _mediaPlayer = new MediaPlayer(); - } else { - _mediaPlayer.reset(); + synchronized (_mediaPlayerLock) { + if (_mediaPlayer == null) { + _mediaPlayer = new MediaPlayer(); + _mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + Log.e(TAG, "MediaPlayer error: " + what + ", " + extra); + releaseMediaPlayer(); + return true; + } + }); + _mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + releaseMediaPlayer(); + } + }); + } else { + _mediaPlayer.reset(); + } + String path = _storage.findPath(new String(pathBytes, CP1252)); + _mediaPlayer.setDataSource(getApplicationContext(), Uri.parse("file://" + path)); + _mediaPlayer.prepare(); + _mediaPlayer.start(); } - _mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - _mediaPlayer.setDataSource(getApplicationContext(), uri); - _mediaPlayer.prepare(); - _mediaPlayer.start(); } - catch (IOException e) { + catch (Exception e) { Log.i(TAG, "playAudio failed: ", e); + releaseMediaPlayer(); } } }).start(); @@ -691,10 +704,7 @@ protected void onResume() { @Override protected void onStop() { super.onStop(); - if (_mediaPlayer != null) { - _mediaPlayer.release(); - _mediaPlayer = null; - } + releaseMediaPlayer(); if (_tts != null) { _tts.close(); _tts = null; @@ -894,6 +904,15 @@ private String readLine(InputStream inputReader) throws IOException { return b == -1 ? null : out.size() == 0 ? "" : out.toString(); } + private void releaseMediaPlayer() { + synchronized (_mediaPlayerLock) { + if (_mediaPlayer != null) { + _mediaPlayer.release(); + _mediaPlayer = null; + } + } + } + private void requestHostPermission(String remoteHost) { final Activity activity = this; runOnUiThread(new Runnable() { @@ -984,6 +1003,26 @@ private Storage() { this._media = media; } + public String findPath(String file) { + String result; + if (file.startsWith("/")) { + result = file; + } + else { + result = getExternal() + "/" + file; + if (!new File(result).canRead()) { + result = getInternal() + "/" + file; + if (!new File(result).canRead()) { + result = getMedia() + "/" + file; + if (!new File(result).canRead()) { + result = file; + } + } + } + } + return result; + } + public String getExternal() { return _external != null ? _external : ""; } diff --git a/src/platform/android/build.gradle b/src/platform/android/build.gradle index 03ed2056..6582791d 100644 --- a/src/platform/android/build.gradle +++ b/src/platform/android/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.3.2' + classpath 'com.android.tools.build:gradle:8.5.2' } } diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 0e27f679..788e499c 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -573,7 +573,7 @@ void Runtime::loadConfig() { } s = settings.get(LOAD_MODULES_KEY); if (s && s->toInteger() == 1) { - if (getBoolean("loadModules")) { + if (getBoolean(LOAD_MODULES_KEY)) { systemLog("Extension modules loaded\n"); settings.put(LOAD_MODULES_KEY, "2"); } else { diff --git a/src/platform/android/webui/package.json b/src/platform/android/webui/package.json index dab6935d..456a5eac 100644 --- a/src/platform/android/webui/package.json +++ b/src/platform/android/webui/package.json @@ -4,22 +4,22 @@ "private": true, "type": "module", "dependencies": { - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@mui/icons-material": "^5.15.15", - "@mui/material": "^5.15.15", - "@mui/x-data-grid": "^6.19.10", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^6.1.1", + "@mui/material": "^6.1.1", + "@mui/x-data-grid": "^7.18.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "vite-plugin-eslint": "^1.8.1" }, "devDependencies": { - "@vitejs/plugin-react": "^4.2.1", - "eslint": "^8.57.0", - "eslint-plugin-react": "^7.34.1", - "npm-check-updates": "^16.14.18", - "vite": "^5.2.8", - "vite-tsconfig-paths": "^4.3.2" + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^8.57.1", + "eslint-plugin-react": "^7.37.0", + "npm-check-updates": "^17.1.3", + "vite": "^5.4.8", + "vite-tsconfig-paths": "^5.0.1" }, "scripts": { "start": "vite --host",