package info.guardianproject.odkparser.widgets; import info.guardianproject.odkparser.Constants.Logger; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import android.content.Context; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnInfoListener; import android.media.MediaRecorder; import android.os.Handler; import android.util.AttributeSet; import android.util.Base64; import android.util.Log; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; public class ODKSeekBar extends SeekBar implements OnSeekBarChangeListener, OnInfoListener { public MediaPlayer mp; public MediaRecorder mr; public java.io.File recordingFile; Context c; Handler h = new Handler(); public boolean isPlaying = false; public boolean isRecording = false; public boolean canPlay = false; public boolean canRecord = false; public byte[] rawAudioData = null; private boolean hasPlayedOnce = false; private final static String LOG = Logger.UI; public interface OnMediaRecorderStopListener { public void onMediaRecorderStop(); } public void start(Context c) { this.c = c; mr = new MediaRecorder(); initMediaRecorder(); setOnSeekBarChangeListener(this); setProgress(0); } public ODKSeekBar(Context context) { super(context); start(context); } public ODKSeekBar(Context context, AttributeSet attrs) { super(context, attrs); start(context); } private void initMediaRecorder() { mr.setAudioSource(MediaRecorder.AudioSource.MIC); mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); } public void saveAudio() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gos = new GZIPOutputStream(baos); java.io.FileInputStream fis = new java.io.FileInputStream(recordingFile); byte[] buf = new byte[1024]; int b; while((b = fis.read(buf)) > 0) { gos.write(buf, 0, b); } fis.close(); gos.finish(); gos.close(); baos.flush(); baos.close(); rawAudioData = Base64.encode(baos.toByteArray(), Base64.DEFAULT); } catch (IOException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } } private void processAudio() { mp.stop(); mp.reset(); try { mp.setDataSource(recordingFile.getAbsolutePath()); mp.prepare(); setMax(mp.getDuration()/1000); } catch (IllegalArgumentException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (SecurityException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (IllegalStateException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (IOException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } } public void reInit(java.io.File recordingFile) { reInit(recordingFile, null); } public void reInit(java.io.File recordingFile, final OnCompletionListener ocl) { mr.reset(); this.recordingFile.delete(); initMediaRecorder(); init(recordingFile, ocl); } public void init(java.io.File recordingFile) { init(recordingFile, null); } public void init(java.io.File recordingFile, final OnCompletionListener ocl) { this.recordingFile = recordingFile; mr.setOutputFile(recordingFile.getAbsolutePath()); mp = new MediaPlayer(); mp.setOnInfoListener(this); h.post(new Runnable() { @Override public void run() { if(isPlaying) { if(mp.getCurrentPosition() >= mp.getDuration()) { pause(); mp.seekTo(0); return; } setProgress(mp.getCurrentPosition()/1000); } h.postDelayed(this, 1000L); } }); if(ocl != null) { mp.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if(hasPlayedOnce) { ocl.onCompletion(mp); } } }); } } public void setRawAudioData(byte[] rawAudioData) { this.rawAudioData = rawAudioData; rawAudioData = null; // b64-decode, unzip audio bytes and dump it in public try { java.io.FileOutputStream fos = new java.io.FileOutputStream(recordingFile); GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(Base64.decode(this.rawAudioData, Base64.DEFAULT))); byte[] buf = new byte[1024]; int b; while((b = gzip.read(buf)) > 0) { fos.write(buf, 0, b); } fos.flush(); fos.close(); processAudio(); } catch (IllegalArgumentException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (SecurityException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (IllegalStateException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (IOException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } } public void shutDown() { mp.release(); mr.release(); recordingFile.delete(); } public void play() { Log.d(LOG, "request PLAY"); canRecord = false; mp.start(); isPlaying = true; if(!hasPlayedOnce) { hasPlayedOnce = true; } } public void pause() { Log.d(LOG, "request PAUSE"); canRecord = true; mp.pause(); isPlaying = false; } public void record() { Log.d(LOG, "request RECORD"); try { mr.prepare(); mr.start(); isRecording = true; canPlay = false; } catch (IllegalStateException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } catch (IOException e) { Log.e(LOG, e.toString()); e.printStackTrace(); } } public void stop() { Log.d(LOG, "request STOP"); canPlay = true; mr.stop(); mr.release(); isRecording = false; try { ((OnMediaRecorderStopListener) c).onMediaRecorderStop(); //return; } catch(ClassCastException e) { Log.e(LOG, e.toString()); } catch(NullPointerException e) { Log.e(LOG, e.toString()); } saveAudio(); processAudio(); } @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { return true; } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if(fromUser) { mp.seekTo(progress * 1000); } } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) {} }