/* * Copyright 2013 Elina Vartiainen and Simon Robinson * * This file is part of Com-Me. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ac.robinson.mediaphonejavame.form; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.Timer; import java.util.TimerTask; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.media.Manager; import javax.microedition.media.Player; import javax.microedition.media.PlayerListener; import javax.microedition.media.control.RecordControl; import ac.robinson.mediaphonejavame.MediaPhone; import ac.robinson.mediaphonejavame.localization.L10nConstants; import ac.robinson.mediaphonejavame.util.StringUtilities; import com.sun.lwuit.Command; import com.sun.lwuit.Form; import com.sun.lwuit.TextArea; import com.sun.lwuit.events.ActionEvent; import com.sun.lwuit.events.ActionListener; import com.sun.lwuit.layouts.BorderLayout; /** * Records, plays back and saves a voice recording. */ public class AudioForm extends Form implements ActionListener, PlayerListener { private FrameEditorForm mFrameEditorForm; private Player mRecordingPlayer; private Player mPlaybackPlayer; private RecordControl mRecordControl; private ByteArrayOutputStream mRecordingOutput; private int mRecordingDuration; private Timer mTimer; private TextArea mStatusText; // TODO: load previous audio here, allow selecting from library, and allow deletion public AudioForm(FrameEditorForm frameEditorForm) { super(MediaPhone.getString(L10nConstants.keys.TITLE_AUDIO)); mFrameEditorForm = frameEditorForm; setLayout(new BorderLayout()); setScrollable(false); mStatusText = new TextArea(MediaPhone.getString(L10nConstants.keys.HINT_START_RECORDING)); mStatusText.setEditable(false); addComponent(BorderLayout.CENTER, mStatusText); addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_CANCEL), MediaPhone.id.button_cancel_audio)); addCommandListener(this); initialiseRecorder(); } private void createRecorder() { try { mRecordingPlayer = Manager.createPlayer("capture://audio?encoding=audio/amr"); mRecordingPlayer.realize(); mRecordControl = (RecordControl) (mRecordingPlayer.getControl("RecordControl")); } catch (Exception e) { } } private void initialiseRecorder() { try { createRecorder(); if (mRecordControl != null) { addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_START), MediaPhone.id.button_start_audio)); // recordControl.setRecordSizeLimit(300000); mRecordingPlayer.start(); } else { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.ERROR_AUDIO_RECORDING_NOT_SUPPORTED)); } } catch (Exception e) { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.ERROR_AUDIO_RECORDING_NOT_SUPPORTED)); } } private void releaseRecorder() { if (mRecordingPlayer != null) { mRecordingPlayer.close(); mRecordingPlayer = null; mRecordControl = null; } } private void releasePlayer() { if (mPlaybackPlayer != null) { mPlaybackPlayer.close(); } } public void actionPerformed(ActionEvent event) { if (mTimer != null) { mTimer.cancel(); } mTimer = new Timer(); switch (event.getCommand().getId()) { case MediaPhone.id.button_start_audio: try { if (mRecordingPlayer == null) { createRecorder(); // shouldn't fail, because if we get here recording is supported } mRecordingOutput = new ByteArrayOutputStream(); mRecordControl.setRecordStream(mRecordingOutput); mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_RECORDING_IN_PROGRESS)); removeAllCommands(); addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_CANCEL), MediaPhone.id.button_abort_audio)); addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_STOP), MediaPhone.id.button_stop_audio)); mRecordingPlayer.start(); mRecordControl.startRecord(); mTimer.scheduleAtFixedRate(new TimerTask() { public void run() { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_RECORDING_IN_PROGRESS) + ": " + StringUtilities.millisecondsToTimeString((int) (mRecordingPlayer.getDuration() / 1000))); } }, 0, 500); } catch (Exception e) { e.printStackTrace(); } break; case MediaPhone.id.button_abort_audio: releaseRecorder(); mFrameEditorForm.show(); break; case MediaPhone.id.button_stop_audio: try { mRecordingPlayer.stop(); mRecordControl.stopRecord(); mRecordControl.commit(); // TODO: can pause/resume here // TODO: getDuration doesn't work on all platforms (see Nokia 5800 for example) mRecordingDuration = (int) (mRecordingPlayer.getDuration() / 1000); releaseRecorder(); removeAllCommands(); addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_CANCEL), MediaPhone.id.button_cancel_audio)); addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_PLAY), MediaPhone.id.button_play_audio)); addCommand(new Command(MediaPhone.getString(L10nConstants.keys.BUTTON_SAVE), MediaPhone.id.button_save_audio)); mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_RECORDING_COMPLETE) + ": " + StringUtilities.millisecondsToTimeString(mRecordingDuration)); } catch (Exception e) { e.printStackTrace(); } break; case MediaPhone.id.button_play_audio: if (mPlaybackPlayer == null || mPlaybackPlayer.getState() != Player.STARTED) { releasePlayer(); ByteArrayInputStream recordedInputStream = null; try { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_PLAYBACK_IN_PROGRESS)); recordedInputStream = new ByteArrayInputStream(mRecordingOutput.toByteArray()); mPlaybackPlayer = Manager.createPlayer(recordedInputStream, "audio/amr"); mPlaybackPlayer.prefetch(); mPlaybackPlayer.addPlayerListener(this); mPlaybackPlayer.start(); mTimer.scheduleAtFixedRate(new TimerTask() { public void run() { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_PLAYBACK_IN_PROGRESS) + ": " + StringUtilities.millisecondsToTimeString((int) (mPlaybackPlayer.getDuration() / 1000))); } }, 0, 500); } catch (Exception e) { try { recordedInputStream.close(); } catch (Exception e2) { } mStatusText.setText(MediaPhone.getString(L10nConstants.keys.ERROR_PLAYING_AUDIO)); if (MediaPhone.DEBUG) { e.printStackTrace(); } } } break; case MediaPhone.id.button_save_audio: releasePlayer(); mFrameEditorForm.setCurrentAudio(saveRecording(), mRecordingDuration); mFrameEditorForm.show(); break; case MediaPhone.id.button_cancel_audio: releasePlayer(); mFrameEditorForm.show(); break; } } private String saveRecording() { String outputFile = MediaPhone.AUDIO_PATH + MediaPhone.getString(L10nConstants.keys.APP_NAME) + "-" + Integer.toHexString((int) System.currentTimeMillis() & 0xffffffff) + ".amr"; FileConnection fileConnection = null; OutputStream outputStream = null; try { fileConnection = (FileConnection) Connector.open(outputFile, Connector.READ_WRITE); // *must* be r/w if (!fileConnection.exists()) { fileConnection.create(); } outputStream = fileConnection.openOutputStream(); outputStream.write(mRecordingOutput.toByteArray()); mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_AUDIO_SAVED)); } catch (Exception e) { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.ERROR_SAVING_AUDIO)); if (MediaPhone.DEBUG) { e.printStackTrace(); } } finally { try { outputStream.close(); } catch (Exception e) { } try { fileConnection.close(); } catch (Exception e) { } } return outputFile; } public void playerUpdate(Player player, String event, Object eventData) { if (event.equals(PlayerListener.STARTED)) { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_PLAYBACK_IN_PROGRESS)); } else if (event.equals(PlayerListener.END_OF_MEDIA)) { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_PLAYBACK_COMPLETE) + ": " + StringUtilities.millisecondsToTimeString(mRecordingDuration)); releasePlayer(); } else if (event.equals(PlayerListener.STOPPED)) { mStatusText.setText(MediaPhone.getString(L10nConstants.keys.HINT_PLAYBACK_STOPPED) + ": " + StringUtilities.millisecondsToTimeString(mRecordingDuration)); releasePlayer(); } } }