I'm trying to implement a service to play a stream in background using mediaplayer class.. anyway in some phone (galaxy tab and some LG model) when my app is in background, the sound chops when I open another application... why this? following some tutorial I implemented the service in this way:
import com.somafm.api.PlayListFile;
import com.somafm.api.Playlist;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
public class PlayerBackgroundService extends Service {
static MediaPlayer.OnPreparedListener prepared_listener;
static MediaPlayer.OnBufferingUpdateListener buffering_listener;
static MediaPlayer.OnCompletionListener completion_listener;
static MediaPlayer.OnErrorListener error_listener;
private static Playlist playlist;
private static PlayerController player;
private static StreamProxy proxy;
private static MediaPlayer mp = new MediaPlayer();
static boolean canPlay;
static boolean clean;
static boolean cancelRequest;
static boolean buffering;
static boolean isPlaying;
private static PowerManager.WakeLock powerLock;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate()
{
super.onCreate();
init();
}
public void init()
{
PowerManager pM = (PowerManager) getSystemService(Context.POWER_SERVICE);
powerLock = pM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Prevent sleeping");
powerLock.acquire();
prepared_listener = new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
canPlay = true;
clean = true;
}
};
error_listener = new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.i("!!MEDIAERROR!!", "WHAT " + what + " - " + extra);
canPlay = true;
clean = false;
isPlaying = false;
return true;
}
};
buffering_listener = new MediaPlayer.OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
Log.i("BUFFERING", "" + percent);
if(percent > 0)
{
if(mp.isPlaying() && !buffering)
{
player.notifyAllBuffering();
buffering = true;
}
}
else
{
if(buffering)
{
player.notifyAllNotBuffering();
buffering = false;
}
}
}
};
completion_listener = new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
//stop();
Log.i("COMPLETED", "COMPLETED");
}
};
}
public synchronized static void start(){
mp.start();
isPlaying = true;
}
public synchronized static void prepare(){
canPlay = false;
clean = true;
proxy = new StreamProxy();
proxy.init();
proxy.start();
if (playlist == null)
{
clean = false;
proxy.stop();
return;
}
int i = 0;
String proxyUrl = "";
playlist.fetchContent();
PlayListFile[] urlsToPlay = playlist.getFiles();
if (urlsToPlay == null)
{
clean = false;
proxy.stop();
return;
}
if (urlsToPlay.length == 0)
{
clean = false;
proxy.stop();
return;
}
do{
try{
proxyUrl = String.format("http://127.0.0.1:%d/%s", proxy
.getPort(), Uri.parse(urlsToPlay[i].getUrl()));
i++;
Log.i("Trying link", "" + urlsToPlay.length);
mp = new MediaPlayer();
mp.setOnPreparedListener(prepared_listener);
mp.setOnBufferingUpdateListener(buffering_listener);
mp.setOnErrorListener(error_listener);
mp.setOnCompletionListener(completion_listener);
mp.setDataSource(proxyUrl);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
}catch(Exception ex)
{
clean = false;
ex.printStackTrace();
}
if(cancelRequest == true)
{
clean = true;
return;
}
if(i >= urlsToPlay.length)
canPlay = true;
}while(canPlay == false);
if(clean == false && proxy != null)
proxy.stop();
}
public synchronized static void stop() {
if(proxy != null)
proxy.stop();
if(mp != null)
mp.stop();
isPlaying = false;
}
public synchronized static void loadPlaylist(Playlist playlist) {
PlayerBackgroundService.playlist = playlist;
}
public synchronized static void registerPlayer(PlayerController player) {
PlayerBackgroundService.player = player;
}
#Override
public void onDestroy() {
super.onDestroy();
if (powerLock != null && powerLock.isHeld())
powerLock.release();
}
}
And launch it in this way:
this.startService(new Intent(appcontext, PlayerBackgroundService.class));
maybe my class is wrong.. can you help me?
Thanks in advance
You need to manually stop and resume the audio which has been played in Media player using pause and resume Method of activity , take a look at this,
#Override
protected void onResume() {
super.onResume();
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
protected void onPause() {
super.onPause();
if (mediaPlayer != null) {
mediaPlayer.pause();
if (isFinishing()) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
Related
i am working on a app where user can record audio,pause it if api level is above 23.And user can listen to the paused recording.
But what i found is, user is unable to listen to paused audio. But what i want is user can listen to paused audio
When recording is stopped it is playable as it is stored in a local path.
I also checked android documentation and many answers on stack overflow like how to play paused audio but i can't find any particular links.
i am sharing my question here. if you have any solution or find any link how to solve my problem it is highly appreciated.
Please let me know even if i need to share my code. As i didn't find it necessary to share code. because when user stops the recording, it should be playable.
Below is my code
public class AudioRecordingActivity extends BaseActivity
implements AppDialog.IYesListener,
AppDialog.IDiscardRecordingListener, AppDialog.ICancelRecordingListener,
PlayAudioManager.IVoiceCompleteListener,
MediaRecorder.OnInfoListener {
private static final Logger LOGGER = LoggerFactory.createLogger(AudioRecordingActivity.class);
private TaskDetailsViewModel mViewModel;
private ActivityAudioRecordingBinding mBinding;
private AssignmentIdsModel mAssignmentIdModel;
private long mStartTime = 0;
private long mPauseTime=0;
private MediaRecorder mRecorder;
private File mOutputFile;
public final ObservableField<Integer> mAudioState = new ObservableField<>(0);
private String mAudioPath;
private int mMaxAudioTime;
private int[] amplitudes = new int[100];
private int i = 0;
private Handler mHandler = new Handler();
private PlayAudioManager mAudioManager;
private Runnable mTickExecutor = new Runnable() {
#Override
public void run() {
tick();
mHandler.postDelayed(mTickExecutor, 1000);
}
};
#Override
protected void onCreatingBase(Bundle savedInstanceState, Intent intent) {
mViewModel = ViewModelProviders.of(this).get(TaskDetailsViewModel.class);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_audio_recording);
mAudioManager = new PlayAudioManager();
mAssignmentIdModel = intent.getParcelableExtra(AppConstants.AppExtras.EXTRA_ASSIGNMENT_MODEL);
mMaxAudioTime = Integer.parseInt(intent.getStringExtra(AppConstants.AppExtras.EXTRA_DURATION));
mAudioPath = MediaUtils.getAudioPath(this, mAssignmentIdModel);
mBinding.ivBack.setOnClickListener(this);
mBinding.rlRecording.setOnClickListener(this);
mBinding.ivPlayAudio.setOnClickListener(this);
mBinding.ivAudioDelete.setOnClickListener(this);
mBinding.tvSave.setOnClickListener(this);
setPlayIconClickable(false);
setSaveButtonClickable(false);
setCrossIconClickable(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_back:
onBackPressed();
break;
case R.id.rl_recording:
startStopRecording();
break;
case R.id.iv_play_audio:
playStopMediaPlayer();
break;
case R.id.iv_audio_delete:
AppDialog.showDeleteAudioDialog(this, this);
break;
case R.id.tv_save:
saveRecording();
break;
}
}
private void saveRecording() {
mViewModel.saveMediaResponse(mAssignmentIdModel, mAudioPath);
finish();
}
private void playStopMediaPlayer() {
if (mAudioManager.isMediaPlayerPlaying()) {
mBinding.ivPlayAudio.setImageResource(R.drawable.play_after_recording_icon);
setSaveButtonClickable(true);
setCrossIconClickable(true);
setPlayIconClickable(true);
mAudioManager.killMediaPlayer();
mBinding.rlRecording.setClickable(true);
mBinding.rippleBackground.stopRippleAnimation();
} else {
playRecording();
}
}
private void startStopRecording() {
switch (mAudioState.get()) {
case AudioRecordingEnum.AUDIO_IDLE_STATE:
hasAudioPermission();
break;
case AudioRecordingEnum.AUDIO_RECORDING_STATE:
pauseStopRecording();
break;
case AudioRecordingEnum.AUDIO_PAUSE_STATE:
resumeRecording();
break;
case AudioRecordingEnum.AUDIO_STOP_STATE:
AppDialog.showNewRecordingDialog(this, this);
break;
}
}
private void hasAudioPermission() {
if (PermissionUtils.hasPermissions(this, PermissionUtils.RC_REQUEST_PERMISSION_RECORD_AUDIO,
Manifest.permission.RECORD_AUDIO)) {
startRecording();
}
}
private void tick() {
long time = (mStartTime < 0) ? 0 : (SystemClock.elapsedRealtime() - mStartTime);
int minutes = (int) (time / 60000);
int seconds = (int) (time / 1000) % 60;
int milliseconds = (int) (time / 100) % 10;
mBinding.tvTimer.setText((minutes < 10 ? "0" + minutes : "00") + ":" + (seconds < 10 ? "0" + seconds : seconds));
if (mRecorder != null) {
amplitudes[i] = mRecorder.getMaxAmplitude();
LOGGER.debug("Voice Recorder", "amplitude: " + (amplitudes[i] * 100 / 32767));
if (i >= amplitudes.length - 1) {
i = 0;
} else {
++i;
}
}
}
private void deleteRecording() {
AppUtils.deleteFile(mAudioPath);
mAudioState.set(AudioRecordingEnum.AUDIO_IDLE_STATE);
setPlayIconClickable(false);
setCrossIconClickable(false);
setSaveButtonClickable(false);
mStartTime = 0;
mBinding.tvTimer.setText("00:00");
mBinding.tvStartRecording.setText(getResources().getString(R.string.txt_start_recording));
mBinding.rlRecording.setClickable(true);
}
private void playRecording() {
try {
Uri videoUri = FileProvider.getUriForFile(this,
this.getApplicationContext().getPackageName() + ".provider",
mOutputFile);
mAudioManager.playAudio(this, this, videoUri);
mBinding.ivPlayAudio.setImageResource(R.drawable.pauseicon_small);
setSaveButtonClickable(false);
setCrossIconClickable(false);
setPlayIconClickable(true);
mBinding.rlRecording.setClickable(false);
mBinding.rippleBackground.startRippleAnimation();
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
}
#TargetApi(Build.VERSION_CODES.N)
private void pauseRecording() {
if (mRecorder == null) {
return;
}
try {
mRecorder.pause();
mPauseTime=SystemClock.elapsedRealtime();
mAudioState.set(AudioRecordingEnum.AUDIO_PAUSE_STATE);
mBinding.tvStartRecording.setText(getResources().getString(R.string.txt_recording_is_paused));
mHandler.removeCallbacks(mTickExecutor);
whenRecordingIsPausedOrStopped();
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
}
#TargetApi(Build.VERSION_CODES.N)
private void resumeRecording() {
if (mRecorder == null) {
return;
}
try {
mRecorder.resume();
mStartTime = (SystemClock.elapsedRealtime() - mPauseTime) + mStartTime;
mHandler.postDelayed(mTickExecutor, 1000);
mAudioState.set(AudioRecordingEnum.AUDIO_RECORDING_STATE);
mBinding.tvStartRecording.setText(getResources().getString(R.string.txt_recording));
whenRecordingIsInStartState();
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
}
private boolean isBuildVersionIsGreaterOrEqualN() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
return true;
} else {
return false;
}
}
private void pauseStopRecording() {
if (isBuildVersionIsGreaterOrEqualN()) {
pauseRecording();
} else {
stopRecording();
}
}
private void startRecording() {
whenRecordingIsInStartState();
mOutputFile = getOutputFile();
mOutputFile.getParentFile().mkdirs();
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(mOutputFile.getAbsolutePath());
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setAudioEncodingBitRate(48000);
mRecorder.setAudioSamplingRate(16000);
mRecorder.setMaxDuration((mMaxAudioTime * 1000));
mRecorder.setOnInfoListener(this);
try {
mRecorder.prepare();
mRecorder.start();
mStartTime = SystemClock.elapsedRealtime();
mHandler.postDelayed(mTickExecutor, 1000);
LOGGER.debug("Voice Recorder", "started recording to " + mOutputFile.getAbsolutePath());
} catch (IOException e) {
LOGGER.error("Voice Recorder", "prepare() failed " + e.getMessage());
}
}
private void whenRecordingIsInStartState() {
mAudioState.set(AudioRecordingEnum.AUDIO_RECORDING_STATE);
setPlayIconClickable(false);
setCrossIconClickable(false);
mBinding.tvStartRecording.setText(getResources().getString(R.string.txt_recording));
mBinding.ivRecord.setImageResource(R.drawable.pauseicon);
setSaveButtonClickable(false);
}
private void setSaveButtonClickable(boolean isClickable) {
if (isClickable) {
mBinding.tvSave.setAlpha(1.0f);
mBinding.tvSave.setClickable(true);
mBinding.tvSave.setTextColor(ContextCompat.getColor(this, R.color.colorAccent));
} else {
mBinding.tvSave.setAlpha(0.5f);
mBinding.tvSave.setClickable(false);
mBinding.tvSave.setTextColor(ContextCompat.getColor(this, R.color.colorMediumText));
}
}
private File getOutputFile() {
return new File(mAudioPath);
}
protected void stopRecording() {
mAudioState.set(AudioRecordingEnum.AUDIO_STOP_STATE);
mBinding.tvStartRecording.setText(getResources().getString(R.string.txt_recording_is_stopped));
whenRecordingIsPausedOrStopped();
mRecorder.stop();
mRecorder.release();
mStartTime = 0;
mPauseTime=0;
mRecorder = null;
mHandler.removeCallbacks(mTickExecutor);
}
private void whenRecordingIsPausedOrStopped() {
setPlayIconClickable(true);
setCrossIconClickable(true);
mBinding.ivRecord.setImageResource(R.drawable.audio_recording);
setSaveButtonClickable(true);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
AppUtils.showShortSnackBar(mBinding.tvSave, R.string.err_permission_denied);
return;
}
}
switch (requestCode) {
case PermissionUtils.RC_REQUEST_PERMISSION_RECORD_AUDIO:
startRecording();
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void setPlayIconClickable(boolean isVisible) {
if (isVisible) {
mBinding.ivPlayAudio.setClickable(true);
mBinding.ivPlayAudio.setAlpha(1.0f);
} else {
mBinding.ivPlayAudio.setAlpha(0.5f);
mBinding.ivPlayAudio.setClickable(false);
}
}
private void setCrossIconClickable(boolean isVisible) {
if (isVisible) {
mBinding.ivAudioDelete.setClickable(true);
mBinding.ivAudioDelete.setAlpha(1.0f);
} else {
mBinding.ivAudioDelete.setAlpha(0.5f);
mBinding.ivAudioDelete.setClickable(false);
}
}
#Override
public void onYesClicked() {
deleteRecording();
}
#Override
public void onVoiceComplete() {
mBinding.ivPlayAudio.setImageResource(R.drawable.play_after_recording_icon);
setCrossIconClickable(true);
setSaveButtonClickable(true);
setPlayIconClickable(true);
mBinding.rlRecording.setClickable(true);
mBinding.rippleBackground.stopRippleAnimation();
}
#Override
public void onBackPressed() {
if (mAudioState.get() == AudioRecordingEnum.AUDIO_RECORDING_STATE) {
mAudioManager.killMediaPlayer();
finish();
} else if (mAudioState.get() == AudioRecordingEnum.AUDIO_STOP_STATE) {
AppDialog.showCancelRecordingDialog(this, this);
} else {
finish();
}
}
#Override
public void onInfo(MediaRecorder mediaRecorder, int i, int i1) {
if (i == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
LOGGER.debug("AUDIOCAPTURE", "Maximum Duration Reached");
stopRecording();
}
}
#Override
protected void onPause() {
if (mAudioManager.isPlaying()) {
//PlayAudioManager.killMediaPlayer();
}
super.onPause();
}
#Override
public void onYesDiscardClicked() {
startRecording();
}
#Override
public void onDeleteRecording() {
AppUtils.deleteFile(mAudioPath);
finish();
}
/**
* this method will be called when any interrupt happens or home button is pressed
*/
#Override
protected void onUserLeaveHint() {
if (mRecorder != null && mAudioState.get() == AudioRecordingEnum.AUDIO_RECORDING_STATE) {
stopRecording();
}
if (mAudioManager.isPlaying()) {
//PlayAudioManager.killMediaPlayer();
}
super.onUserLeaveHint();
}
}
Below is Audio Playing class
public class PlayAudioManager {
private MediaPlayer mediaPlayer;
private IVoiceCompleteListener iVoiceCompleteListener;
public PlayAudioManager() {
}
public void playAudio(IVoiceCompleteListener listener, final Context context, Uri uri) throws Exception {
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(context, uri);
}
iVoiceCompleteListener = listener;
mediaPlayer.setOnCompletionListener(
mp -> killMediaPlayer());
mediaPlayer.start();
}
public void pauseMediaPlayer() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void playMediaPlayer() {
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
public void killMediaPlayer() {
if (mediaPlayer != null) {
try {
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
} catch (Exception e) {
e.printStackTrace();
}
}
if (iVoiceCompleteListener != null) {
iVoiceCompleteListener.onVoiceComplete();
}
}
public boolean isPlaying() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
killMediaPlayer();
return true;
}
return false;
}
public boolean isMediaPlayerPlaying() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
return true;
}
return false;
}
public interface IVoiceCompleteListener {
void onVoiceComplete();
}
}
I'm trying to make a simple audio recorder. The problem with the audio recorder is that,every time the progress bar gets faster. It would run fine on the first turn, but if you cancel the audio and want to go the second time, it gets faster.
recordButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (recorder == null) {
recorder = new MediaRecorder();
}
stopped=false;
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile("/sdcard/sample.3gp");
recorder.setMaxDuration(MAX_DURATION);
//Progressbar
pb.setMax(MAX_DURATION);
pb.setProgressTintList(ColorStateList.valueOf(Color.WHITE));
new CountDownTimer(MAX_DURATION, 250) {
public void onTick(long millisUntilFinished) {
pb.setProgress(pb.getProgress() + 250);
}
public void onFinish() {
}
}.start();
All of this is happening within a dialog, so how do I clear the dialog's contents so that the progress bar goes back to its default value.
long timestamp = DateUtils.getCurrentTimeMillis();
String imagePath = Environment.getExternalStorageDirectory() + "/testing/" + timestamp + "_D_FM_" + "John" + ".mp3";
MediaRecorder mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setOutputFile(imagePath);
mRecorder.setAudioEncodingBitRate(16);
mRecorder.setAudioSamplingRate(44100);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
// Starting record time
recordTime = 0;
// Show TextView that displays record time
try {
mRecorder.prepare();
mRecorder.start();
// Change isRecroding flag to true
isRecording = true;
handler.post(UpdateRecordTime);
} catch (IOException e) {
FRLog.e("LOG_TAG", "prepare failed", e);
}
When click audio playing:
private MediaPlayer mPlayer;
private void playAudio(final SeekBar audioSeekbar, int position, final ImageButton audioplayImgBtn, String fileName) {
seekBar = audioSeekbar;
if (audio_playing && audio_position == position) {
if (isPaused) {
mPlayer.start();
handler.post(UpdatePlayTime);
audioplayImgBtn.setImageResource(R.drawable.ic_pause);
isPaused = false;
} else {
mPlayer.pause();
audioplayImgBtn.setImageResource(R.drawable.ic_messages_audio_play);
isPaused = true;
}
} else {
if (audio_playing && audio_position != position) {
mPlayer.pause();
audioplayImgBtn.setImageResource(R.drawable.ic_messages_audio_play);
isPaused = true;
}
audio_position = position;
audioSeekbar.setProgress(0);
audioplayImgBtn.setImageResource(R.drawable.ic_pause);
if (mPlayer != null) {
if (mPlayer.isPlaying()) {
mPlayer.stop();
mPlayer.reset();
mPlayer.release();
mPlayer = null;
} else {
mPlayer.reset();
mPlayer.release();
mPlayer = null;
}
}
mPlayer = new MediaPlayer();
playTime = 0;
handler = new Handler();
// Reset max and progress of the SeekBar
try {
// Initialize the player and start playing the audio
mPlayer.setDataSource(Environment.getExternalStorageDirectory() + "/testing/" + fileName);
mPlayer.prepare();
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
audioSeekbar.setMax(mPlayer.getDuration());
mPlayer.start();
audio_playing = true;
handler.post(UpdatePlayTime);
}
});
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
audioplayImgBtn.setImageResource(R.drawable.ic_messages_audio_play);
audioSeekbar.setProgress(0);
audio_playing = false;
handler.removeCallbacksAndMessages(null);
}
});
// Post the play progress
// updated code by manikandan
audioSeekbar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (mPlayer.isPlaying()) {
SeekBar sb = (SeekBar) v;
mPlayer.seekTo(sb.getProgress());
}
return false;
}
});
audioSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean fromUser) {
if (mPlayer != null && fromUser) {
mPlayer.seekTo(seekBar.getProgress());
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mPlayer != null) {
if (mPlayer.isPlaying()) {
mPlayer.seekTo(seekBar.getProgress());
}
}
}
});
} catch (IOException e) {
FRLog.e("LOG_TAG", "prepare failed", e);
}
}
}
Runnable UpdatePlayTime = new Runnable() {
public void run() {
if (mPlayer != null) {
if (mPlayer.isPlaying()) {
seekBar.setProgress(mPlayer.getCurrentPosition());
handler.postDelayed(this, 500);
}
}
}
};
As the javafxports Media is not yet implemented I'm looking to use the Android Native MediaPlayer instead. Does anyone know how to do this.
If you have a look at the GoNative sample here (docs and code), you'll find a way to add Android native code to your JavaFX project.
This is a simple example of adding android.media.MediaPlayer to a JavaFX project using the Gluon plugin.
Based on a Single View project, let's add first an interface with the required audio method signatures:
public interface NativeAudioService {
void play();
void pause();
void resume();
void stop();
}
Now in our View we can create the buttons to call those methods based on an instance of AndroidNativeAudio class that implements the NativeAudioService interface:
public class BasicView extends View {
private NativeAudioService service;
private boolean pause;
public BasicView(String name) {
super(name);
try {
service = (NativeAudioService) Class.forName("com.gluonhq.nativeaudio.AndroidNativeAudio").newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
System.out.println("Error " + ex);
}
if (service != null) {
final HBox hBox = new HBox(10,
MaterialDesignIcon.PLAY_ARROW.button(e -> service.play()),
MaterialDesignIcon.PAUSE.button(e -> {
if (!pause) {
service.pause();
pause = true;
} else {
service.resume();
pause = false;
}
}),
MaterialDesignIcon.STOP.button(e -> service.stop()));
hBox.setAlignment(Pos.CENTER);
setCenter(new StackPane(hBox));
} else {
setCenter(new StackPane(new Label("Only for Android")));
}
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MUSIC_NOTE.button());
appBar.setTitleText("Native Audio");
}
}
Now, we create the native class under the Android folder. It will make use of the android API. It will try to find the audio file audio.mp3 that we have to place under the /src/android/assets folder:
package com.gluonhq.nativeaudio;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import java.io.IOException;
import javafxports.android.FXActivity;
public class AndroidNativeAudio implements NativeAudioService {
private MediaPlayer mp;
private int currentPosition;
public AndroidNativeAudio() { }
#Override
public void play() {
currentPosition = 0;
try {
if (mp != null) {
stop();
}
mp = new MediaPlayer();
AssetFileDescriptor afd = FXActivity.getInstance().getAssets().openFd("audio.mp3");
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.setAudioStreamType(AudioManager.STREAM_RING);
mp.setOnCompletionListener(mp -> stop());
mp.prepare();
mp.start();
} catch (IOException e) {
System.out.println("Error playing audio resource " + e);
}
}
#Override
public void stop() {
if (mp != null) {
if (mp.isPlaying()) {
mp.stop();
}
mp.release();
mp = null;
}
}
#Override
public void pause() {
if (mp != null) {
mp.pause();
currentPosition = mp.getCurrentPosition();
}
}
#Override
public void resume() {
if (mp != null) {
mp.start();
mp.seekTo(currentPosition);
}
}
}
Finally, we can deploy the project to an Android device running gradlew androidInstall.
The native audio player was used in the following example:
https://gist.github.com/bgmf/d87a2bac0a5623f359637a3da334f980
Beside some prerequisites, the code looks like this:
package my.application;
import my.application.Constants;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import org.robovm.apple.avfoundation.AVAudioPlayer;
import org.robovm.apple.foundation.NSErrorException;
import org.robovm.apple.foundation.NSURL;
import org.robovm.apple.foundation.NSURLScheme;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
public class NativeAudioServiceIOS extends PathHelperIOS implements NativeAudioService {
private static final Logger LOG = Logger.getLogger(NativeAudioServiceIOS.class.getName());
private static final String DIR_NAME = Constants.OBJECTS_BASE_PATH;
private final ReadOnlyObjectWrapper<Status> status = new ReadOnlyObjectWrapper<>(this, "status", Status.STOP);
private String filename = null;
private AVAudioPlayer player = null;
public NativeAudioServiceIOS() {
super();
}
#Override
public void init(String filename) throws NativeServiceException {
this.filename = filename.startsWith("/") ? filename.substring(1) : filename;
LOG.warning("Called with file: " + filename);
status.set(Status.STOP);
try {
if(!filename.startsWith("/")) filename = "/" + filename;
File fullfile = new File(pathBase.getAbsolutePath() + filename);
if(fullfile.exists()) {
NSURL fullurl = new NSURL(NSURLScheme.File, "", fullfile.getAbsolutePath());
LOG.log(Level.SEVERE, "Loading URL: " + fullurl);
// Create audio player object and initialize with URL to sound
player = new AVAudioPlayer(fullurl);
LOG.log(Level.SEVERE, "Player initialized: " + player);
status.set(Status.STOP);
} else {
LOG.log(Level.WARNING, String.format("Audiofile doesn't exist: %s (%s / %s)",
fullfile.getAbsolutePath(),
pathBase.getAbsolutePath(),
filename));
player = null;
status.set(Status.ERROR);
}
} catch(NSErrorException error) {
LOG.log(Level.SEVERE, "Audio Setup Failed: " + error.toString(), error);
status.set(Status.ERROR);
}
}
#Override
public void play() throws NativeServiceException {
if(player == null) return;
player.play();
status.set(Status.PLAY);
}
#Override
public void pause() throws NativeServiceException {
if(player == null) return;
player.pause();
status.set(Status.PAUSE);
}
#Override
public void resume() throws NativeServiceException {
if(player == null) return;
player.play();
status.set(Status.PLAY);
}
#Override
public void stop() throws NativeServiceException {
if(player == null) return;
player.stop();
player.setCurrentTime(0.0);
status.set(Status.STOP);
}
#Override
public ReadOnlyObjectProperty<Status> statusProperty() {
return status.getReadOnlyProperty();
}
#Override
public Status getStatus() {
return status.get();
}
}
I use media player in service and activity with a button(play/stop stream).
I'm trying to do such a one thing:
start serice only once when activity starts, and than use UI part to operate with media player in service (start, stop streaming). I'm using for it Service Binder.
But when i click on button to start media player, it causes errors:
E/MediaPlayer: start called in state 1
E/MediaPlayer: error (-38, 0)
Than i added the flag isPrepared to onPrepared() and on play stream button click check the flag. Flag is always false.
It seems that onPrepare() is not called or smth like that. Why? What's wrong?
UPDATED
Activity:
public class MainActivity extends AppCompatActivity {
String url = "http://62.80.190.246:8000/ProstoRadiO128";
Button mPlayPauseButton;
boolean musicPlaying = false;
Intent serviceIntent;
MyService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initListeners();
}
#Override
protected void onStart() {
super.onStart();
serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("url", url);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
startService(serviceIntent);
musicPlaying = true;
mPlayPauseButton.setBackgroundResource(R.drawable.pause);
Log.d("", "mConnection: " + mConnection);
}
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyServiceBinder binder = (MyService.MyServiceBinder) service;
mService = binder.getService();
mBound = true;
Log.d("", "in onServiceConnected: mBound = " + mBound);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
private void initViews() {
mPlayPauseButton = (Button) findViewById(R.id.btn_play_pause);
mPlayPauseButton.setBackgroundResource(R.drawable.play);
}
private void initListeners() {
mPlayPauseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playPauseClick();
}
});
}
private void playPauseClick() {
if (musicPlaying == false) { //mBound &&
Log.d("", "mBound: " + mBound);
mService.startStream();
mPlayPauseButton.setBackgroundResource(R.drawable.pause);
musicPlaying = true;
}
else if (musicPlaying == true) { //!mBound
mService.stopStream();
mPlayPauseButton.setBackgroundResource(R.drawable.play);
musicPlaying = false;
}
}
}
UPDATED
Service:
public class MyService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener{
String TAG = "PlayerService__Log";
String url;
MediaPlayer mediaPlayer;
private final IBinder mBinder = new MyServiceBinder();
boolean isPrepared;
public class MyServiceBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
Log.v(TAG, "Creating Service");
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
url = intent.getStringExtra("url");
Log.d(TAG, "url: " + url);
if (!mediaPlayer.isPlaying()) {
try {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, e.getClass().getName() + " " + e.getMessage());
}
}
return START_STICKY;
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
Log.d(TAG, "media player prepared");
isPrepared = true;
}
#Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "onCompletion");
}
#Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
public void startStream() {
if (!mediaPlayer.isPlaying() ) { //&& isPrepared == true
mediaPlayer.start();
Log.d(TAG, "media player started");
}
else {
Log.d(TAG, "media player is not prepared");
//isPrepared = false;
}
}
public void stopStream() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
Log.d(TAG, "media player stoped");
}
}
}
You forgot to start the service. Call:
startService(serviceIntent);
Please read this as you will need to stop the service too.
and for pausing, rather than stop, call:
mediaPlayer.pause();
Familiarise yourself with the state diagram and invalid states in the docs.
onPrepared() is called when the player is successfully prepared/initialised.
But as the Error is indicating, something goes wrong during this phase and (probably) therfore onPrepared never gets called.
You could try to override onError, to get notified like this:
#Override
public boolean onError(MediaPlayer mediaPlayer, int what, int why) {
Log.e(TAG, "onError");
setPlayerState(PlayerState.ERROR);
if (MediaPlayer.MEDIA_ERROR_UNKNOWN == what) {
Log.d(TAG, "MEDIA_ERROR_UNKNOWN");
if (MediaPlayer.MEDIA_ERROR_IO == why) {
Log.e(TAG, "MEDIA_ERROR_IO");
if (this.playbackPosition > 0) { //we could play this video in the past, but cannot resume. start all over again.
Log.e(TAG, "Probably we requested a content range, but server didn't support that. (responded with 200), restarting!");
this.playbackPosition = 0;
start(this.playbackPosition);
} else {
callbacks.onUnrecoverableError(what, why);
}
}
if (MediaPlayer.MEDIA_ERROR_MALFORMED == why) {
Log.e(TAG, "MEDIA_ERROR_MALFORMED");
callbacks.onUnrecoverableError(what, why);
}
if (MediaPlayer.MEDIA_ERROR_UNSUPPORTED == why) {
Log.e(TAG, "MEDIA_ERROR_UNSUPPORTED");
callbacks.onUnrecoverableError(what, why);
}
if (MediaPlayer.MEDIA_ERROR_TIMED_OUT == why) {
Log.e(TAG, "MEDIA_ERROR_TIMED_OUT");
callbacks.onUnrecoverableError(what, why);
}
} else if (MediaPlayer.MEDIA_ERROR_SERVER_DIED == what) {
Log.e(TAG, "MEDIA_ERROR_SERVER_DIED");
callbacks.onUnrecoverableError(what, why);
}
return true;
}
I am recording audio using AudioRecord class.I want to record audio into a particular file in my asset folder or resource folder.I think there is no problem in recording.but while reading buffer it is showing some problem(it is throwing NullPointerException).Can anyone suggest what may be the problem?
You can not save file inside Asset folder. Assets folder is read only instead of it you will have to save it in the internal or external storage of your device
Below there is a core to record the media file.
package com.example.media.record;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MediaRecorderActivity extends Activity implements OnClickListener {
Button btnPlay;
Button btnRecord;
ProgressBar progress;
MediaPlayer mPlayer;
MediaRecorder mRecorder;
String mFileName;
boolean mStartRecording = true;
boolean mStartPlaying = true;
Thread mThreadProgress;
int duration = 1;
private void onRecord(boolean start) {
if(start) {
startRecording();
}else {
stopRecording();
}
}
private void onPlay(boolean start) {
if(start) {
startPlaying();
}else {
stopPlaying();
}
}
private void startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFile(mFileName);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOnErrorListener(errorListenerForRecorder);
try {
mRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
mRecorder.start();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error :: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
private void stopRecording() {
if(mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
private void startPlaying() {
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mFileName);
mPlayer.setOnCompletionListener(completionListener);
mPlayer.setOnErrorListener(errorListenerForPlayer);
mPlayer.prepare();
mPlayer.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void stopPlaying() {
if(mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}
OnCompletionListener completionListener = new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
btnRecord.setEnabled(true);
btnPlay.setText("Start playing");
mStartPlaying = !mStartPlaying;
}
};
OnErrorListener errorListenerForPlayer = new OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Toast.makeText(getApplicationContext(), "Error during playing file", 3000).show();
return false;
}
};
android.media.MediaRecorder.OnErrorListener errorListenerForRecorder = new android.media.MediaRecorder.OnErrorListener() {
#Override
public void onError(MediaRecorder mr, int what, int extra) {
Toast.makeText(getApplicationContext(), "Error during recoding file", 3000).show();
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnPlay = (Button)findViewById(R.id.btnPlay);
btnRecord = (Button)findViewById(R.id.btnRecord);
progress = (ProgressBar)findViewById(R.id.progressRecorder);
mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
mFileName += "/audiorecordtest.3gp";
File file = new File(mFileName);
if(!file.exists()) btnPlay.setEnabled(false);
btnPlay.setOnClickListener(this);
btnRecord.setOnClickListener(this);
}
#Override
protected void onPause() {
super.onPause();
if(mRecorder != null) {
mRecorder.stop();
}
if(mPlayer != null) {
mPlayer.pause();
}
}
#Override
protected void onResume() {
super.onResume();
if(mRecorder != null) {
mRecorder.start();
}
if(mPlayer != null) {
mPlayer.start();
}
}
#Override
protected void onStop() {
super.onStop();
if(mRecorder != null) {
mRecorder.stop();
}
if(mPlayer != null) {
mPlayer.stop();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(mRecorder != null) {
mRecorder.release();
mRecorder = null;
}
if(mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
}
#Override
public void onClick(View v) {
if(v == btnPlay) {
onPlay(mStartPlaying);
if(mStartPlaying) {
duration = mPlayer.getDuration();
mThreadProgress = new ThreadProgress();
mThreadProgress.start();
((Button)v).setText("Stop Playing");
btnRecord.setEnabled(false);
}
else {
((Button)v).setText("Start Playing");
btnRecord.setEnabled(true);
if(mThreadProgress != null && !mThreadProgress.isAlive()) mThreadProgress.stop();
// t.interrupt();
}
mStartPlaying = !mStartPlaying;
} else if(v == btnRecord) {
onRecord(mStartRecording);
if(mStartRecording) {
mThreadProgress = new ThreadProgress();
mThreadProgress.start();
((Button)v).setText("Stop Recording");
btnPlay.setEnabled(false);
// t.start();
}
else {
((Button)v).setText("Start Recording");
btnPlay.setEnabled(true);
// t.interrupt();
if(mThreadProgress != null && !mThreadProgress.isAlive()) mThreadProgress.stop();
}
mStartRecording = !mStartRecording;
}
}
Handler handler = new Handler(new Callback() {
#Override
public boolean handleMessage(final Message msg) {
if(msg.what == 0) {
runOnUiThread(new Runnable() {
public void run() {
progress.setProgress(msg.arg1);
}
});
}
return false;
}
});
public class ThreadProgress extends Thread implements Runnable {
public int i = 0;
#Override
public void run() {
while((!this.isInterrupted() && mPlayer != null && mPlayer.isPlaying()) || (!this.isInterrupted() && mRecorder != null)) {
try {
if(duration == 1) i+=1;
else i += 100000 /duration;
Message message = new Message();
message.what = 0;
message.arg1 = i;
handler.sendMessage(message);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
This is the example you can record audio as well as play audio
You can store recorded file in following places
1) File directory of your app
2) External directory(SD card)
3) Network