/* * Kontalk Android client * Copyright (C) 2017 Kontalk Devteam <devteam@kontalk.org> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.ui; import java.io.File; import java.io.IOException; import android.app.Activity; import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Bundle; import android.os.SystemClock; import android.support.v4.app.Fragment; import org.kontalk.util.SystemUtils; /** * A fragment that handles media recorder and player instances, independently * of its parent activity. * @author Daniele Ricci */ public class AudioFragment extends Fragment implements MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener { private MediaRecorder mRecorder; private MediaPlayer mPlayer; private long mStartTime; /** Message id of the media currently being played. */ private long mMessageId = -1; private OnCompletionListener mOnCompletionListener; private boolean mAudioFocus; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } public MediaRecorder getRecorder() { if (mRecorder == null) { mRecorder = new MediaRecorder(); } return mRecorder; } public void startRecording() throws IOException { mStartTime = SystemClock.uptimeMillis(); MediaRecorder recorder = getRecorder(); recorder.prepare(); recorder.start(); acquireLock(); } public long getElapsedTime() { return mStartTime > 0 ? SystemClock.uptimeMillis() - mStartTime : 0; } public void stopRecording() { // release lock anyway releaseLock(); if (mRecorder != null) { mRecorder.stop(); mRecorder.reset(); mRecorder.release(); mRecorder = null; mStartTime = 0; } } public void preparePlayer(File audioFile) throws IOException { if (mPlayer == null) { mPlayer = new MediaPlayer(); mPlayer.setOnCompletionListener(this); } mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.setDataSource(audioFile.getAbsolutePath()); mPlayer.prepare(); } public int getPlayerDuration() { return mPlayer != null ? mPlayer.getDuration() : -1; } public int getPlayerPosition() { return mPlayer != null ? mPlayer.getCurrentPosition() : -1; } public boolean startPlaying() { if (mPlayer != null) { if (acquireAudioFocus()) { mStartTime = SystemClock.uptimeMillis(); mPlayer.start(); // started, acquire lock acquireLock(); return true; } } return false; } public void pausePlaying() { if (mPlayer != null) { mPlayer.pause(); // paused, release lock releaseLock(); releaseAudioFocus(); } } public void seekPlayerTo(int msec) { if (mPlayer != null) mPlayer.seekTo(msec); } public void resetPlayer() { if (mPlayer != null) mPlayer.reset(); releaseAudioFocus(); } public void setOnCompletionListener(OnCompletionListener listener) { mOnCompletionListener = listener; } interface OnCompletionListener { /** Called on play completion. */ void onCompletion(AudioFragment audio); /** Called when the app loses audio focus. */ void onAudioFocusLost(AudioFragment audio); } @Override public void onCompletion(MediaPlayer mp) { // release any audio focus releaseAudioFocus(); if (mOnCompletionListener != null) { mOnCompletionListener.onCompletion(this); } } public boolean isPlaying() { return mPlayer != null && mPlayer.isPlaying(); } public void setMessageId(long mMessageId) { this.mMessageId = mMessageId; } public long getMessageId() { return mMessageId; } public void finish(boolean release) { if (mPlayer != null && release) mPlayer.release(); finish(); } public void finish() { mPlayer = null; mRecorder = null; mStartTime = 0; mOnCompletionListener = null; releaseLock(); releaseAudioFocus(); } private void acquireLock() { Activity a = getActivity(); if (a != null) SystemUtils.acquireScreenOn(a); } private void releaseLock() { Activity a = getActivity(); if (a != null) SystemUtils.releaseScreenOn(a); } private boolean acquireAudioFocus() { if (!mAudioFocus) { final Context ctx = getContext(); if (ctx != null) { // using the application context so the audio focus is global AudioManager audio = (AudioManager) ctx.getApplicationContext() .getSystemService(Context.AUDIO_SERVICE); if (audio.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { mAudioFocus = true; return true; } } return false; } return true; } private void releaseAudioFocus() { if (mAudioFocus) { final Context ctx = getContext(); if (ctx != null) { // using the application context so the audio focus is global AudioManager audio = (AudioManager) ctx.getApplicationContext() .getSystemService(Context.AUDIO_SERVICE); audio.abandonAudioFocus(this); mAudioFocus = false; } } } @Override public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { mAudioFocus = false; if (mOnCompletionListener != null) { // notify listener that we should stop playing now mOnCompletionListener.onAudioFocusLost(AudioFragment.this); } } } }