Working with Lorin's change

This commit is contained in:
Joe Bowser 2012-07-10 14:37:26 -07:00
commit c030770be7
2 changed files with 258 additions and 167 deletions

25
framework/src/org/apache/cordova/AudioHandler.java Executable file → Normal file
View File

@ -96,6 +96,12 @@ public class AudioHandler extends Plugin {
float f = this.getDurationAudio(args.getString(0), args.getString(1)); float f = this.getDurationAudio(args.getString(0), args.getString(1));
return new PluginResult(status, f); return new PluginResult(status, f);
} }
else if (action.equals("create")) {
String id = args.getString(0);
String src = args.getString(1);
AudioPlayer audio = new AudioPlayer(this, id, src);
this.players.put(id, audio);
}
else if (action.equals("release")) { else if (action.equals("release")) {
boolean b = this.release(args.getString(0)); boolean b = this.release(args.getString(0));
return new PluginResult(status, b); return new PluginResult(status, b);
@ -149,7 +155,7 @@ public class AudioHandler extends Plugin {
// Get all audio players and pause them // Get all audio players and pause them
for (AudioPlayer audio : this.players.values()) { for (AudioPlayer audio : this.players.values()) {
if (audio.getState() == AudioPlayer.MEDIA_RUNNING) { if (audio.getState() == AudioPlayer.STATE.MEDIA_RUNNING.ordinal()) {
this.pausedForPhone.add(audio); this.pausedForPhone.add(audio);
audio.pausePlaying(); audio.pausePlaying();
} }
@ -192,13 +198,12 @@ public class AudioHandler extends Plugin {
* @param file The name of the file * @param file The name of the file
*/ */
public void startRecordingAudio(String id, String file) { public void startRecordingAudio(String id, String file) {
// If already recording, then just return; AudioPlayer audio = this.players.get(id);
if (this.players.containsKey(id)) { if ( audio == null) {
return; audio = new AudioPlayer(this, id, file);
} this.players.put(id, audio);
AudioPlayer audio = new AudioPlayer(this, id); }
this.players.put(id, audio); audio.startRecording(file);
audio.startRecording(file);
} }
/** /**
@ -221,7 +226,7 @@ public class AudioHandler extends Plugin {
public void startPlayingAudio(String id, String file) { public void startPlayingAudio(String id, String file) {
AudioPlayer audio = this.players.get(id); AudioPlayer audio = this.players.get(id);
if (audio == null) { if (audio == null) {
audio = new AudioPlayer(this, id); audio = new AudioPlayer(this, id, file);
this.players.put(id, audio); this.players.put(id, audio);
} }
audio.startPlaying(file); audio.startPlaying(file);
@ -292,7 +297,7 @@ public class AudioHandler extends Plugin {
// If not already open, then open the file // If not already open, then open the file
else { else {
audio = new AudioPlayer(this, id); audio = new AudioPlayer(this, id, file);
this.players.put(id, audio); this.players.put(id, audio);
return (audio.getDuration(file)); return (audio.getDuration(file));
} }

400
framework/src/org/apache/cordova/AudioPlayer.java Executable file → Normal file
View File

@ -31,6 +31,8 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import org.apache.cordova.AudioPlayer.MODE;
/** /**
* This class implements the audio playback and recording capabilities used by Cordova. * This class implements the audio playback and recording capabilities used by Cordova.
* It is called by the AudioHandler Cordova class. * It is called by the AudioHandler Cordova class.
@ -41,15 +43,20 @@ import java.io.IOException;
* sdcard: file name is just sound.mp3 * sdcard: file name is just sound.mp3
*/ */
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener { public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
private static final String LOG_TAG = "AudioPlayer"; // AudioPlayer modes
public enum MODE { NONE, PLAY, RECORD };
// AudioPlayer states // AudioPlayer states
public static int MEDIA_NONE = 0; public enum STATE { MEDIA_NONE,
public static int MEDIA_STARTING = 1; MEDIA_LOADING,
public static int MEDIA_RUNNING = 2; MEDIA_STARTING,
public static int MEDIA_PAUSED = 3; MEDIA_RUNNING,
public static int MEDIA_STOPPED = 4; MEDIA_PAUSED,
MEDIA_STOPPED
};
private static final String LOG_TAG = "AudioPlayer";
// AudioPlayer message ids // AudioPlayer message ids
private static int MEDIA_STATE = 1; private static int MEDIA_STATE = 1;
@ -64,17 +71,20 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
private static int MEDIA_ERR_DECODE = 3; private static int MEDIA_ERR_DECODE = 3;
private static int MEDIA_ERR_NONE_SUPPORTED = 4; private static int MEDIA_ERR_NONE_SUPPORTED = 4;
private AudioHandler handler; // The AudioHandler object private AudioHandler handler; // The AudioHandler object
private String id; // The id of this player (used to identify Media object in JavaScript) private String id; // The id of this player (used to identify Media object in JavaScript)
private int state = MEDIA_NONE; // State of recording or playback private MODE mode = MODE.NONE; // Playback or Recording mode
private String audioFile = null; // File name to play or record to private STATE state = STATE.MEDIA_NONE; // State of recording or playback
private float duration = -1; // Duration of audio
private MediaRecorder recorder = null; // Audio recording object private String audioFile = null; // File name to play or record to
private String tempFile = null; // Temporary recording file name private float duration = -1; // Duration of audio
private MediaRecorder recorder = null; // Audio recording object
private String tempFile = null; // Temporary recording file name
private MediaPlayer mPlayer = null; // Audio player object private MediaPlayer player = null; // Audio player object
private boolean prepareOnly = false; private boolean prepareOnly = true; // playback after file prepare flag
private int seekOnPrepared = 0; // seek to this location once media is prepared
/** /**
* Constructor. * Constructor.
@ -82,14 +92,17 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @param handler The audio handler object * @param handler The audio handler object
* @param id The id of this audio player * @param id The id of this audio player
*/ */
public AudioPlayer(AudioHandler handler, String id) { public AudioPlayer(AudioHandler handler, String id, String file) {
this.handler = handler; this.handler = handler;
this.id = id; this.id = id;
this.audioFile = file;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3"; this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.mp3";
} else { } else {
this.tempFile = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/tmprecording.mp3"; this.tempFile = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/tmprecording.mp3";
} }
} }
/** /**
@ -97,13 +110,13 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/ */
public void destroy() { public void destroy() {
// Stop any play or record // Stop any play or record
if (this.mPlayer != null) { if (this.player != null) {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
this.mPlayer.stop(); this.player.stop();
this.setState(MEDIA_STOPPED); this.setState(STATE.MEDIA_STOPPED);
} }
this.mPlayer.release(); this.player.release();
this.mPlayer = null; this.player = null;
} }
if (this.recorder != null) { if (this.recorder != null) {
this.stopRecording(); this.stopRecording();
@ -118,31 +131,34 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @param file The name of the file * @param file The name of the file
*/ */
public void startRecording(String file) { public void startRecording(String file) {
if (this.mPlayer != null) { switch (this.mode) {
case PLAY:
Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode."); Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
} break;
// Make sure we're not already recording case NONE:
else if (this.recorder == null) { // Make sure we're not already recording
this.audioFile = file; if (this.recorder == null) {
this.recorder = new MediaRecorder(); this.audioFile = file;
this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC); this.recorder = new MediaRecorder();
this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP); this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB); this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
this.recorder.setOutputFile(this.tempFile); this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
try { this.recorder.setOutputFile(this.tempFile);
this.recorder.prepare(); try {
this.recorder.start(); this.recorder.prepare();
this.setState(MEDIA_RUNNING); this.recorder.start();
return; this.setState(STATE.MEDIA_RUNNING);
} catch (IllegalStateException e) { return;
e.printStackTrace(); } catch (IllegalStateException e) {
} catch (IOException e) { e.printStackTrace();
e.printStackTrace(); } catch (IOException e) {
e.printStackTrace();
}
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
} }
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});"); break;
} case RECORD:
else {
Log.d(LOG_TAG, "AudioPlayer Error: Already recording."); Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
} }
@ -171,9 +187,9 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public void stopRecording() { public void stopRecording() {
if (this.recorder != null) { if (this.recorder != null) {
try{ try{
if (this.state == MEDIA_RUNNING) { if (this.state == STATE.MEDIA_RUNNING) {
this.recorder.stop(); this.recorder.stop();
this.setState(MEDIA_STOPPED); this.setState(STATE.MEDIA_STOPPED);
} }
this.moveFile(this.audioFile); this.moveFile(this.audioFile);
} }
@ -183,81 +199,22 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
} }
} }
//==========================================================================
// Playback
//==========================================================================
/** /**
* Start or resume playing audio file. * Start or resume playing audio file.
* *
* @param file The name of the audio file. * @param file The name of the audio file.
*/ */
public void startPlaying(String file) { public void startPlaying(String file) {
if (this.recorder != null) { if (this.readyPlayer(file)) {
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode."); this.player.start();
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});"); this.setState(STATE.MEDIA_RUNNING);
} } else {
//
// If this is a new request to play audio, or stopped this.prepareOnly = false;
else if ((this.mPlayer == null) || (this.state == MEDIA_STOPPED)) {
try {
// If stopped, then reset player
if (this.mPlayer != null) {
this.mPlayer.reset();
}
// Otherwise, create a new one
else {
this.mPlayer = new MediaPlayer();
}
this.audioFile = file;
// If streaming file
if (this.isStreaming(file)) {
this.mPlayer.setDataSource(file);
this.mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
this.setState(MEDIA_STARTING);
this.mPlayer.setOnPreparedListener(this);
this.mPlayer.prepareAsync();
}
// If local file
else {
if (file.startsWith("/android_asset/")) {
String f = file.substring(15);
android.content.res.AssetFileDescriptor fd = this.handler.cordova.getActivity().getAssets().openFd(f);
this.mPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
}
else {
File fp = new File(file);
if (fp.exists()) {
FileInputStream fileInputStream = new FileInputStream(file);
this.mPlayer.setDataSource(fileInputStream.getFD());
}
else {
this.mPlayer.setDataSource("/sdcard/" + file);
}
}
this.setState(MEDIA_STARTING);
this.mPlayer.setOnPreparedListener(this);
this.mPlayer.prepare();
// Get duration
this.duration = getDurationInSeconds();
}
} catch (Exception e) {
e.printStackTrace();
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
}
// If we have already have created an audio player
else {
// If player has been paused, then resume playback
if ((this.state == MEDIA_PAUSED) || (this.state == MEDIA_STARTING)) {
this.mPlayer.start();
this.setState(MEDIA_RUNNING);
}
else {
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
} }
} }
@ -265,11 +222,14 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* Seek or jump to a new time in the track. * Seek or jump to a new time in the track.
*/ */
public void seekToPlaying(int milliseconds) { public void seekToPlaying(int milliseconds) {
if (this.mPlayer != null) { if (this.readyPlayer(this.audioFile)) {
this.mPlayer.seekTo(milliseconds); this.player.seekTo(milliseconds);
Log.d(LOG_TAG, "Send a onStatus update for the new seek"); Log.d(LOG_TAG, "Send a onStatus update for the new seek");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");");
} }
else {
this.seekOnPrepared = milliseconds;
}
} }
/** /**
@ -278,12 +238,12 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public void pausePlaying() { public void pausePlaying() {
// If playing, then pause // If playing, then pause
if (this.state == MEDIA_RUNNING) { if (this.state == STATE.MEDIA_RUNNING) {
this.mPlayer.pause(); this.player.pause();
this.setState(MEDIA_PAUSED); this.setState(STATE.MEDIA_PAUSED);
} }
else { else {
Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state); Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state.ordinal());
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
} }
} }
@ -292,12 +252,12 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* Stop playing the audio file. * Stop playing the audio file.
*/ */
public void stopPlaying() { public void stopPlaying() {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
this.mPlayer.stop(); this.player.stop();
this.setState(MEDIA_STOPPED); this.setState(STATE.MEDIA_STOPPED);
} }
else { else {
Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state); Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state.ordinal());
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
} }
} }
@ -305,10 +265,10 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
/** /**
* Callback to be invoked when playback of a media source has completed. * Callback to be invoked when playback of a media source has completed.
* *
* @param mPlayer The MediaPlayer that reached the end of the file * @param player The MediaPlayer that reached the end of the file
*/ */
public void onCompletion(MediaPlayer mPlayer) { public void onCompletion(MediaPlayer player) {
this.setState(MEDIA_STOPPED); this.setState(STATE.MEDIA_STOPPED);
} }
/** /**
@ -317,8 +277,8 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @return position in msec or -1 if not playing * @return position in msec or -1 if not playing
*/ */
public long getCurrentPosition() { public long getCurrentPosition() {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) { if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
int curPos = this.mPlayer.getCurrentPosition(); int curPos = this.player.getCurrentPosition();
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + curPos / 1000.0f + ");"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + curPos / 1000.0f + ");");
return curPos; return curPos;
} }
@ -359,7 +319,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
} }
// If audio file already loaded and started, then return duration // If audio file already loaded and started, then return duration
if (this.mPlayer != null) { if (this.player != null) {
return this.duration; return this.duration;
} }
@ -377,29 +337,28 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
/** /**
* Callback to be invoked when the media source is ready for playback. * Callback to be invoked when the media source is ready for playback.
* *
* @param mPlayer The MediaPlayer that is ready for playback * @param player The MediaPlayer that is ready for playback
*/ */
public void onPrepared(MediaPlayer mPlayer) { public void onPrepared(MediaPlayer player) {
// Listen for playback completion // Listen for playback completion
this.mPlayer.setOnCompletionListener(this); this.player.setOnCompletionListener(this);
// If start playing after prepared // If start playing after prepared
if (!this.prepareOnly) { if (!this.prepareOnly) {
this.player.start();
// Start playing this.setState(STATE.MEDIA_RUNNING);
this.mPlayer.start(); } else {
this.setState(STATE.MEDIA_STARTING);
// Set player init flag
this.setState(MEDIA_RUNNING);
} }
// Save off duration // Save off duration
this.duration = getDurationInSeconds(); this.duration = getDurationInSeconds();
this.prepareOnly = false; // reset prepare only flag
this.prepareOnly = true;
// seek to any location received while not prepared
this.seekToPlaying(this.seekOnPrepared);
// reset seek location
this.seekOnPrepared = 0;
// Send status notification to JavaScript // Send status notification to JavaScript
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_DURATION + "," + this.duration + ");"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_DURATION + "," + this.duration + ");");
} }
/** /**
@ -408,23 +367,23 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @return length of clip in seconds * @return length of clip in seconds
*/ */
private float getDurationInSeconds() { private float getDurationInSeconds() {
return (this.mPlayer.getDuration() / 1000.0f); return (this.player.getDuration() / 1000.0f);
} }
/** /**
* Callback to be invoked when there has been an error during an asynchronous operation * Callback to be invoked when there has been an error during an asynchronous operation
* (other errors will throw exceptions at method call time). * (other errors will throw exceptions at method call time).
* *
* @param mPlayer the MediaPlayer the error pertains to * @param player the MediaPlayer the error pertains to
* @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED) * @param arg1 the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
* @param arg2 an extra code, specific to the error. * @param arg2 an extra code, specific to the error.
*/ */
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) { public boolean onError(MediaPlayer player, int arg1, int arg2) {
Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")"); Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")");
// TODO: Not sure if this needs to be sent? // TODO: Not sure if this needs to be sent?
this.mPlayer.stop(); this.player.stop();
this.mPlayer.release(); this.player.release();
// Send error notification to JavaScript // Send error notification to JavaScript
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});");
@ -436,21 +395,33 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* *
* @param state * @param state
*/ */
private void setState(int state) { private void setState(STATE state) {
if (this.state != state) { if (this.state != state) {
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + state + ");"); this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + this.state.ordinal() + ");");
} }
this.state = state; this.state = state;
} }
/**
* Set the mode and send it to JavaScript.
*
* @param state
*/
private void setMode(MODE mode) {
if (this.mode != mode) {
//mode is not part of the expected behaviour, so no notification
//this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + mode + ");");
}
this.mode = mode;
}
/** /**
* Get the audio state. * Get the audio state.
* *
* @return int * @return int
*/ */
public int getState() { public int getState() {
return this.state; return this.state.ordinal();
} }
/** /**
@ -459,6 +430,121 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @param volume * @param volume
*/ */
public void setVolume(float volume) { public void setVolume(float volume) {
this.mPlayer.setVolume(volume, volume); this.player.setVolume(volume, volume);
}
/**
* attempts to put the player in play mode
* @return true if in playmode, false otherwise
*/
private boolean playMode() {
switch(this.mode) {
case NONE:
this.setMode(MODE.PLAY);
break;
case PLAY:
break;
case RECORD:
Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
return false; //player is not ready
}
return true;
}
/**
* attempts to initialize the media player for playback
* @param file the file to play
* @return false if player not ready, reports if in wrong mode or state
*/
private boolean readyPlayer(String file) {
if (playMode()) {
switch (this.state) {
case MEDIA_NONE:
if (this.player == null) {
this.player = new MediaPlayer();
}
try {
this.loadAudioFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return false;
case MEDIA_LOADING:
//cordova js is not aware of MEDIA_LOADING, so we send MEDIA_STARTING insntead
Log.d(LOG_TAG, "AudioPlayer Loading: startPlaying() called during media preparation: " + STATE.MEDIA_STARTING.ordinal());
this.prepareOnly = false;
return false;
case MEDIA_STARTING:
case MEDIA_RUNNING:
case MEDIA_PAUSED:
return true;
case MEDIA_STOPPED:
//if we are readying the same file
if (this.audioFile.compareTo(file) == 0) {
//reset the audio file
player.seekTo(0);
player.pause();
return true;
} else {
//reset the player
this.player.reset();
try {
this.loadAudioFile(file);
} catch (Exception e) {
e.printStackTrace();
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
//if we had to prepare= the file, we won't be in the correct state for playback
return false;
}
default:
Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
this.handler.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
}
}
return false;
}
/**
* load audio file
* @throws IOException
* @throws IllegalStateException
* @throws SecurityException
* @throws IllegalArgumentException
*/
private void loadAudioFile(String file) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException {
if (this.isStreaming(file)) {
this.player.setDataSource(file);
this.player.setAudioStreamType(AudioManager.STREAM_MUSIC);
//if it's a streaming file, play mode is implied
this.setMode(MODE.PLAY);
this.setState(STATE.MEDIA_STARTING);
this.player.setOnPreparedListener(this);
this.player.prepareAsync();
}
else {
if (file.startsWith("/android_asset/")) {
String f = file.substring(15);
android.content.res.AssetFileDescriptor fd = this.handler.ctx.getActivity().getAssets().openFd(f);
this.player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
}
else {
File fp = new File(file);
if (fp.exists()) {
FileInputStream fileInputStream = new FileInputStream(file);
this.player.setDataSource(fileInputStream.getFD());
}
else {
this.player.setDataSource("/sdcard/" + file);
}
}
this.setState(STATE.MEDIA_STARTING);
this.player.setOnPreparedListener(this);
this.player.prepare();
// Get duration
this.duration = getDurationInSeconds();
}
} }
} }