diff --git a/src/android/AudioHandler.java b/src/android/AudioHandler.java index 4c8a29c7..d1bb2892 100644 --- a/src/android/AudioHandler.java +++ b/src/android/AudioHandler.java @@ -130,38 +130,86 @@ else if (action.equals("resumeRecordingAudio")) { this.resumeRecordingAudio(args.getString(0)); } else if (action.equals("startPlayingAudio")) { + String id = args.getString(0); String target = args.getString(1); - String fileUriStr; - try { - Uri targetUri = resourceApi.remapUri(Uri.parse(target)); - fileUriStr = targetUri.toString(); - } catch (IllegalArgumentException e) { - fileUriStr = target; - } - this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(fileUriStr)); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + String fileUriStr; + try { + Uri targetUri = resourceApi.remapUri(Uri.parse(target)); + fileUriStr = targetUri.toString(); + } catch (IllegalArgumentException e) { + fileUriStr = target; + } + + startPlayingAudio(id, FileHelper.stripFileProtocol(fileUriStr)); + } + }); } else if (action.equals("seekToAudio")) { - this.seekToAudio(args.getString(0), args.getInt(1)); + String id = args.getString(0); + int positionMs = args.getInt(1); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + seekToAudio(id, positionMs); + } + }); } else if (action.equals("pausePlayingAudio")) { - this.pausePlayingAudio(args.getString(0)); + String id = args.getString(0); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + pausePlayingAudio(id); + } + }); } else if (action.equals("stopPlayingAudio")) { - this.stopPlayingAudio(args.getString(0)); + String id = args.getString(0); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + stopPlayingAudio(id); + } + }); } else if (action.equals("setVolume")) { - try { - this.setVolume(args.getString(0), Float.parseFloat(args.getString(1))); - } catch (NumberFormatException nfe) { - //no-op - } + String id = args.getString(0); + String volume = args.getString(1); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + setVolume(id, Float.parseFloat(volume)); + } catch (NumberFormatException nfe) { + //no-op + } + } + }); } else if (action.equals("getCurrentPositionAudio")) { - float f = this.getCurrentPositionAudio(args.getString(0)); - callbackContext.sendPluginResult(new PluginResult(status, f)); + String id = args.getString(0); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + float f = getCurrentPositionAudio(id); + callbackContext.sendPluginResult(new PluginResult(status, f)); + } + }); + return true; } else if (action.equals("getDurationAudio")) { - float f = this.getDurationAudio(args.getString(0), args.getString(1)); - callbackContext.sendPluginResult(new PluginResult(status, f)); + String id = args.getString(0); + String file = args.getString(1); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + float f = getDurationAudio(id, file); + callbackContext.sendPluginResult(new PluginResult(status, f)); + } + }); + return true; } else if (action.equals("create")) { @@ -170,20 +218,42 @@ else if (action.equals("create")) { getOrCreatePlayer(id, src); } else if (action.equals("release")) { - boolean b = this.release(args.getString(0)); - callbackContext.sendPluginResult(new PluginResult(status, b)); + String id = args.getString(0); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + boolean b = release(id); + callbackContext.sendPluginResult(new PluginResult(status, b)); + } + }); + return true; } else if (action.equals("messageChannel")) { messageChannel = callbackContext; return true; } else if (action.equals("getCurrentAmplitudeAudio")) { - float f = this.getCurrentAmplitudeAudio(args.getString(0)); - callbackContext.sendPluginResult(new PluginResult(status, f)); + String id = args.getString(0); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + float f = getCurrentAmplitudeAudio(id); + callbackContext.sendPluginResult(new PluginResult(status, f)); + } + }); + return true; } else if (action.equals("setRate")) { - this.setRate(args.getString(0), Float.parseFloat(args.getString(1))); + String id = args.getString(0); + String rate = args.getString(1); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + setRate(id, Float.parseFloat(rate)); + } + }); + return true; } else { // Unrecognized action. @@ -403,7 +473,7 @@ else if (output == 1) { audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL); } else { - LOG.e(TAG1," Unknown output device"); + LOG.e(TAG1," Unknown output device"); } } @@ -427,8 +497,8 @@ public void resumeAllGainedFocus() { * Get the the audio focus */ private OnAudioFocusChangeListener focusChangeListener = new OnAudioFocusChangeListener() { - public void onAudioFocusChange(int focusChange) { - switch (focusChange) { + public void onAudioFocusChange(int focusChange) { + switch (focusChange) { case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) : case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) : case (AudioManager.AUDIOFOCUS_LOSS) : @@ -439,17 +509,17 @@ public void onAudioFocusChange(int focusChange) { break; default: break; - } } - }; + } + }; public void getAudioFocus() { String TAG2 = "AudioHandler.getAudioFocus(): Error : "; AudioManager am = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE); int result = am.requestAudioFocus(focusChangeListener, - AudioManager.STREAM_MUSIC, - AudioManager.AUDIOFOCUS_GAIN); + AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN); if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { LOG.e(TAG2,result + " instead of " + AudioManager.AUDIOFOCUS_REQUEST_GRANTED); @@ -490,13 +560,13 @@ public void setVolume(String id, float volume) { if (audio != null) { audio.setVolume(volume); } else { - LOG.e(TAG3,"Unknown Audio Player " + id); + LOG.e(TAG3,"Unknown Audio Player " + id); } } /** * Set the playback rate of an audio file - * + * * @param id The id of the audio player * @param rate The playback rate */ @@ -509,7 +579,7 @@ public void setRate(String id, float rate) { LOG.e(TAG3, "Unknown Audio Player " + id); } } - + private void onFirstPlayerCreated() { origVolumeStream = cordova.getActivity().getVolumeControlStream(); @@ -589,4 +659,11 @@ public float getCurrentAmplitudeAudio(String id) { } return 0; } -} + + /** + * Obtains cordova threadPool + */ + public java.util.concurrent.ExecutorService getThreadPool() { + return cordova.getThreadPool(); + } +} \ No newline at end of file diff --git a/src/android/AudioPlayer.java b/src/android/AudioPlayer.java index e19689fd..344a46ca 100644 --- a/src/android/AudioPlayer.java +++ b/src/android/AudioPlayer.java @@ -57,12 +57,12 @@ public enum MODE { NONE, PLAY, RECORD }; // AudioPlayer states public enum STATE { MEDIA_NONE, - MEDIA_STARTING, - MEDIA_RUNNING, - MEDIA_PAUSED, - MEDIA_STOPPED, - MEDIA_LOADING - }; + MEDIA_STARTING, + MEDIA_RUNNING, + MEDIA_PAUSED, + MEDIA_STOPPED, + MEDIA_LOADING + }; private static final String LOG_TAG = "AudioPlayer"; @@ -120,12 +120,12 @@ public AudioPlayer(AudioHandler handler, String id, String file) { */ private String createAudioFilePath(String fileName) { File dir = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) - ? context.getExternalFilesDir(null) - : context.getCacheDir(); + ? context.getExternalFilesDir(null) + : context.getCacheDir(); fileName = (fileName == null || fileName.isEmpty()) - ? String.format("tmprecording-%d.3gp", System.currentTimeMillis()) - : fileName; + ? String.format("tmprecording-%d.3gp", System.currentTimeMillis()) + : fileName; return dir.getAbsolutePath() + File.separator + fileName; } @@ -160,34 +160,34 @@ public void destroy() { public void startRecording(String file) { String errorMessage; switch (this.mode) { - case PLAY: - errorMessage = "AudioPlayer Error: Can't record in play mode."; - sendErrorStatus(MEDIA_ERR_ABORTED, errorMessage); - break; - case NONE: - this.audioFile = file; - this.recorder = new MediaRecorder(); - this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC); - this.recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS); // RAW_AMR); - this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //AMR_NB); - this.tempFile = createAudioFilePath(null); - this.recorder.setOutputFile(this.tempFile); - try { - this.recorder.prepare(); - this.recorder.start(); - this.setState(STATE.MEDIA_RUNNING); - return; - } catch (IllegalStateException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } + case PLAY: + errorMessage = "AudioPlayer Error: Can't record in play mode."; + sendErrorStatus(MEDIA_ERR_ABORTED, errorMessage); + break; + case NONE: + this.audioFile = file; + this.recorder = new MediaRecorder(); + this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC); + this.recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS); // RAW_AMR); + this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //AMR_NB); + this.tempFile = createAudioFilePath(null); + this.recorder.setOutputFile(this.tempFile); + try { + this.recorder.prepare(); + this.recorder.start(); + this.setState(STATE.MEDIA_RUNNING); + return; + } catch (IllegalStateException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } - sendErrorStatus(MEDIA_ERR_ABORTED, null); - break; - case RECORD: - errorMessage = "AudioPlayer Error: Already recording."; - sendErrorStatus(MEDIA_ERR_ABORTED, errorMessage); + sendErrorStatus(MEDIA_ERR_ABORTED, null); + break; + case RECORD: + errorMessage = "AudioPlayer Error: Already recording."; + sendErrorStatus(MEDIA_ERR_ABORTED, errorMessage); } } @@ -228,7 +228,7 @@ public void moveFile(String file) { copy(inputStream, outputStream, false); } catch (Exception e) { LOG.e(LOG_TAG, e.getLocalizedMessage(), e); - } finally { + } finally { if (inputStream != null) try { inputStream.close(); inputFile.delete(); @@ -251,42 +251,42 @@ public void moveFile(String file) { } // more than one file so the user must have pause recording. We'll need to concat files. else { - FileOutputStream outputStream = null; - try { - outputStream = new FileOutputStream(new File(file)); - FileInputStream inputStream = null; - File inputFile = null; - for (int i = 0; i < size; i++) { - try { - inputFile = new File(this.tempFiles.get(i)); - inputStream = new FileInputStream(inputFile); - copy(inputStream, outputStream, (i>0)); - } catch(Exception e) { - LOG.e(LOG_TAG, e.getLocalizedMessage(), e); - } finally { - if (inputStream != null) try { - inputStream.close(); - inputFile.delete(); - inputFile = null; - } catch (Exception e) { - LOG.e(LOG_TAG, e.getLocalizedMessage(), e); - } - } - } - } catch(Exception e) { - e.printStackTrace(); - } finally { - if (outputStream != null) try { - outputStream.close(); - } catch (Exception e) { - LOG.e(LOG_TAG, e.getLocalizedMessage(), e); - } - } + FileOutputStream outputStream = null; + try { + outputStream = new FileOutputStream(new File(file)); + FileInputStream inputStream = null; + File inputFile = null; + for (int i = 0; i < size; i++) { + try { + inputFile = new File(this.tempFiles.get(i)); + inputStream = new FileInputStream(inputFile); + copy(inputStream, outputStream, (i>0)); + } catch(Exception e) { + LOG.e(LOG_TAG, e.getLocalizedMessage(), e); + } finally { + if (inputStream != null) try { + inputStream.close(); + inputFile.delete(); + inputFile = null; + } catch (Exception e) { + LOG.e(LOG_TAG, e.getLocalizedMessage(), e); + } + } + } + } catch(Exception e) { + e.printStackTrace(); + } finally { + if (outputStream != null) try { + outputStream.close(); + } catch (Exception e) { + LOG.e(LOG_TAG, e.getLocalizedMessage(), e); + } + } } } private static long copy(InputStream from, OutputStream to, boolean skipHeader) - throws IOException { + throws IOException { byte[] buf = new byte[8096]; long total = 0; if (skipHeader) { @@ -409,7 +409,7 @@ public void stopPlaying() { * Resume playing. */ public void resumePlaying() { - this.startPlaying(this.audioFile); + this.startPlaying(this.audioFile); } /** @@ -455,13 +455,13 @@ public boolean isStreaming(String file) { } /** - * Get the duration of the audio file. - * - * @param file The name of the audio file. - * @return The duration in msec. - * -1=can't be determined - * -2=not allowed - */ + * Get the duration of the audio file. + * + * @param file The name of the audio file. + * @return The duration in msec. + * -1=can't be determined + * -2=not allowed + */ public float getDuration(String file) { // Can't get duration of recording @@ -493,26 +493,33 @@ public float getDuration(String file) { public void onPrepared(MediaPlayer player) { // Listen for playback completion this.player.setOnCompletionListener(this); - // seek to any location received while not prepared - this.seekToPlaying(this.seekOnPrepared); - // apply any playback rate received while not prepared - if (setRateOnPrepared >= 0) - this.player.setPlaybackParams (this.player.getPlaybackParams().setSpeed(setRateOnPrepared)); - // If start playing after prepared - if (!this.prepareOnly) { - this.player.start(); - this.setState(STATE.MEDIA_RUNNING); - this.seekOnPrepared = 0; //reset only when played - } else { - this.setState(STATE.MEDIA_STARTING); - } - // Save off duration - this.duration = getDurationInSeconds(); - // reset prepare only flag - this.prepareOnly = true; - // Send status notification to JavaScript - sendStatusChange(MEDIA_DURATION, null, this.duration, null); + this.handler.getThreadPool().execute(new Runnable() { + public void run() { + // seek to any location received while not prepared + seekToPlaying(seekOnPrepared); + // apply any playback rate received while not prepared + if (setRateOnPrepared >= 0) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + player.setPlaybackParams (player.getPlaybackParams().setSpeed(setRateOnPrepared)); + } + // If start playing after prepared + if (!prepareOnly) { + player.start(); + setState(STATE.MEDIA_RUNNING); + seekOnPrepared = 0; //reset only when played + } else { + setState(STATE.MEDIA_STARTING); + } + // Save off duration + duration = getDurationInSeconds(); + // reset prepare only flag + prepareOnly = true; + + // Send status notification to JavaScript + sendStatusChange(MEDIA_DURATION, null, duration, null); + } + }); } /** @@ -599,15 +606,15 @@ public void setVolume(float volume) { */ private boolean playMode() { switch(this.mode) { - case NONE: - this.setMode(MODE.PLAY); - break; - case PLAY: - break; - case RECORD: - String errorMessage = "AudioPlayer Error: Can't play in record mode."; - sendErrorStatus(MEDIA_ERR_ABORTED, errorMessage); - return false; //player is not ready + case NONE: + this.setMode(MODE.PLAY); + break; + case PLAY: + break; + case RECORD: + String errorMessage = "AudioPlayer Error: Can't play in record mode."; + sendErrorStatus(MEDIA_ERR_ABORTED, errorMessage); + return false; //player is not ready } return true; } @@ -657,7 +664,7 @@ private boolean readyPlayer(String file) { return false;//we´re not ready yet } else { - //reset the audio file + //reset the audio file player.seekTo(0); player.pause(); return true; @@ -715,13 +722,13 @@ private void loadAudioFile(String file) throws IllegalArgumentException, Securit this.player.setDataSource(createAudioFilePath(file)); } } - this.setState(STATE.MEDIA_STARTING); - this.player.setOnPreparedListener(this); - this.player.prepare(); + this.setState(STATE.MEDIA_STARTING); + this.player.setOnPreparedListener(this); + this.player.prepare(); - // Get duration - this.duration = getDurationInSeconds(); - } + // Get duration + this.duration = getDurationInSeconds(); + } } private void sendErrorStatus(int errorCode, String errorMessage) { @@ -807,4 +814,4 @@ public void setRate(float rate) { setRateOnPrepared = rate; } } -} +} \ No newline at end of file