package org.commcare.views.media;
import android.media.MediaPlayer;
import android.util.Log;
/**
* Audio playback is delegated through this singleton class since only one
* track should play at a time. Audio buttons invoke this controller on button
* presses. When activities that are playing audio are paused or unloaded they
* pause or release the audio through this controller.
*
* @author Phillip Mates (pmates@dimagi.com)
*/
public enum AudioController {
/**
* Singleton instance
*/
INSTANCE;
private static final String TAG = AudioController.class.getSimpleName();
/**
* Only one audio entity should be playing at once, this is that entity.
*/
private MediaEntity currentEntity;
/**
* Button that corresponds to the currentEntity media. Pressing the button
* should trigger playback control methods here.
*/
private AudioPlaybackButtonBase currentAudioButton;
/**
* Set the media to be played and store the playback button attached to
* that media, enableing button display state to mirror playback state.
*
* @param newMedia New media to be controlled
* @param newAudioButton Button that corresponds to the new media, needed so
* we can update the button's display state to mirror
* the media's playback state
*/
public void setCurrentMediaAndButton(MediaEntity newMedia,
final AudioPlaybackButtonBase newAudioButton) {
if (currentAudioButton != null && currentAudioButton != newAudioButton) {
// reset the old button to not be playing
currentAudioButton.resetPlaybackState();
}
currentAudioButton = newAudioButton;
if (newMedia != currentEntity) {
// newMedia is actually new, so release old media
releaseCurrentMediaEntity();
currentEntity = newMedia;
}
registerPlaybackFinishedCallback();
}
private void registerPlaybackFinishedCallback() {
currentEntity.getPlayer().setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseCurrentMediaEntity();
}
});
}
/**
* When a view and its buttons are re-created, we need to re-register the
* button that corresponds with the playing media.
*
* @param button Corresponds with the media that is currently
* loaded/playing
*/
public void registerPlaybackButton(AudioPlaybackButtonBase button) {
currentAudioButton = button;
registerPlaybackFinishedCallback();
}
/**
* Release current media resources.
*/
public void releaseCurrentMediaEntity() {
if (currentAudioButton != null) {
currentAudioButton.endPlaying();
}
if (currentEntity != null) {
MediaPlayer mp = currentEntity.getPlayer();
mp.reset();
mp.release();
}
currentEntity = null;
}
/**
* Start audio playback of current media resource.
*/
public void playCurrentMediaEntity() {
if (currentEntity != null) {
MediaPlayer player = currentEntity.getPlayer();
player.start();
currentEntity.setState(MediaState.Playing);
currentAudioButton.startProgressBar(player.getCurrentPosition(), player.getDuration());
}
}
/**
* Pause playback of current media resource.
*/
public void pauseCurrentMediaEntity() {
if (currentEntity != null) {
if (currentEntity.getState().equals(MediaState.Playing)) {
MediaPlayer mp = currentEntity.getPlayer();
mp.pause();
currentEntity.setState(MediaState.Paused);
}
}
}
/**
* Pauses playback when the controlling activity gets put in the
* background. The pause is specially marked such that when the activity
* resumes and calls playPreviousAudio, playback will resume.
*/
public void systemInducedPause() {
if (currentEntity != null) {
boolean unpauseOnResume =
MediaState.Playing.equals(currentEntity.getState());
pauseCurrentMediaEntity();
if (unpauseOnResume) {
currentEntity.setState(MediaState.PausedForRenewal);
}
}
}
/**
* Play media that was paused due to a system interruption
*/
public void playPreviousAudio() {
if (currentEntity != null) {
switch (currentEntity.getState()) {
case PausedForRenewal:
currentAudioButton.startPlaying();
break;
case Paused:
break;
case Playing:
case Ready:
Log.w(TAG, "State in loadPreviousAudio is invalid");
}
}
}
boolean isMediaLoaded() {
return currentEntity != null;
}
boolean doesCurrentMediaCorrespondToButton(AudioPlaybackButtonBase audioButton) {
return currentEntity != null && currentAudioButton == audioButton;
}
void seekTo(int pos) {
if (currentEntity != null) {
currentEntity.getPlayer().seekTo(pos);
}
}
int getCurrentPosition() {
if (currentEntity == null) {
return -1;
} else {
return currentEntity.getPlayer().getCurrentPosition();
}
}
int getDuration() {
if (currentEntity == null) {
return -1;
} else {
return currentEntity.getPlayer().getDuration();
}
}
ViewId getMediaViewId() {
return currentEntity.getId();
}
String getMediaUri() {
return currentEntity.getSource();
}
MediaState getMediaState() {
return currentEntity.getState();
}
}