diff --git a/video/src/main/AndroidManifest.xml b/video/src/main/AndroidManifest.xml index 916a9fd..3926733 100644 --- a/video/src/main/AndroidManifest.xml +++ b/video/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.wearscript.record" > @@ -14,7 +14,7 @@ android:icon="@drawable/ic_launcher" android:label="@string/app_name" > @@ -23,7 +23,7 @@ @@ -34,14 +34,27 @@ - + - - - + + + + + + + + + + + + + diff --git a/video/src/main/java/com/wearscript/record/AudioRecordThread.java b/video/src/main/java/com/wearscript/record/AudioRecordThread.java new file mode 100644 index 0000000..6ae441d --- /dev/null +++ b/video/src/main/java/com/wearscript/record/AudioRecordThread.java @@ -0,0 +1,210 @@ +package com.wearscript.record; + +import android.content.Context; +import android.content.Intent; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder.AudioSource; +import android.os.Environment; +import android.util.Log; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; + +public class AudioRecordThread extends Thread { + + private static final String LOG_TAG = "Audio"; + + private static final int RECORDER_SAMPLERATE = 8000; + private static final int ENCODING_TYPE = AudioFormat.ENCODING_PCM_16BIT; + public static final int WAV_HEADER_LENGTH = 44; + public static final String FILEPATH = "filepath"; + private final int CHANNEL_TYPE = AudioFormat.CHANNEL_IN_MONO; + private final int NUM_CHANNELS = 1; + private byte BITS_PER_SAMPLE = 16; + private final int AUDIO_SOURCE = AudioSource.MIC; + private final int BYTE_RATE = RECORDER_SAMPLERATE * NUM_CHANNELS * (BITS_PER_SAMPLE / 8); + + public static final String directory = Environment.getExternalStorageDirectory() + File.separator + "wearscript"; + public static final String directoryAudio = directory + File.separator+"audio"; + + private final int bufferSize = 160; //Each buffer holds 1/100th of a second. + private boolean pollingBuffer = false; + + AudioRecord recorder = null; + FileOutputStream os = null; + String filePath; + + /** + * Give the thread high priority so that it's not cancelled unexpectedly, and start it + */ + + private ArrayList buffers; + private byte[] totalBuffer; + + Context context; + + public AudioRecordThread(Context context, String filePath) + { + this.context = context; + writeWavHeader(filePath); + } + + @Override + public void run() { + Log.d(LOG_TAG, "Running Audio Thread"); + + buffers = new ArrayList(); + int N = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, CHANNEL_TYPE,ENCODING_TYPE); + Log.d(LOG_TAG, "" + N); + try { + recorder = new AudioRecord(AUDIO_SOURCE, RECORDER_SAMPLERATE, CHANNEL_TYPE, ENCODING_TYPE, N*10); + } + catch (Throwable e) { + Log.d(LOG_TAG, e.toString()); + return; + } + recorder.startRecording(); + + try { + while (!interrupted()) { + buffers.add(new byte[bufferSize]); + recorder.read(buffers.get(buffers.size() - 1), 0, bufferSize); + } + } + catch (Throwable x) { + Log.d(LOG_TAG, "Error reading voice audio", x); + } + /* + * Frees the thread's resources after the loop completes so that it can be run again + */ + finally { + recorder.stop(); + recorder.release(); + context.stopService(new Intent(context, AudioRecorder.class)); + Log.d(LOG_TAG, "Thread Terminated"); + } + } + + private void mergeBuffers() { + Log.d(LOG_TAG, "in mergeBuffers()"); + int i; + int j; + int ix = 0; + + ArrayList copy = (ArrayList) buffers.clone(); + buffers = new ArrayList(); + + totalBuffer = new byte[copy.size() * bufferSize]; + for (i = 0; i < copy.size(); i++) { + for(j = 0; j> 8) & 0xff); + header[6] = (byte) ((totalDataLen >> 16) & 0xff); + header[7] = (byte) ((totalDataLen >> 24) & 0xff); + header[8] = 'W'; + header[9] = 'A'; + header[10] = 'V'; + header[11] = 'E'; + header[12] = 'f'; // 'fmt ' chunk + header[13] = 'm'; + header[14] = 't'; + header[15] = ' '; + header[16] = 16; // 4 bytes: size of 'fmt ' chunk + header[17] = 0; + header[18] = 0; + header[19] = 0; + header[20] = 1; // format = 1 + header[21] = 0; + header[22] = (byte) NUM_CHANNELS; + header[23] = 0; + header[24] = (byte) (RECORDER_SAMPLERATE & 0xff); + header[25] = (byte) ((RECORDER_SAMPLERATE >> 8) & 0xff); + header[26] = (byte) ((RECORDER_SAMPLERATE >> 16) & 0xff); + header[27] = (byte) ((RECORDER_SAMPLERATE >> 24) & 0xff); + header[28] = (byte) (BYTE_RATE & 0xff); + header[29] = (byte) ((BYTE_RATE >> 8) & 0xff); + header[30] = (byte) ((BYTE_RATE >> 16) & 0xff); + header[31] = (byte) ((BYTE_RATE >> 24) & 0xff); + header[32] = (byte) (NUM_CHANNELS * BITS_PER_SAMPLE / 8); + header[33] = 0; + header[34] = BITS_PER_SAMPLE; + header[35] = 0; + header[36] = 'd'; + header[37] = 'a'; + header[38] = 't'; + header[39] = 'a'; + header[40] = (byte) (totalAudioLen & 0xff); + header[41] = (byte) ((totalAudioLen >> 8) & 0xff); + header[42] = (byte) ((totalAudioLen >> 16) & 0xff); + header[43] = (byte) ((totalAudioLen >> 24) & 0xff); + + try { + os.write(header, 0, header.length); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void stopRecording() { + Log.d(LOG_TAG, "in stopRecording()"); + writeAudioDataToFile(); + + try { + os.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + interrupt(); + } + + public void writeAudioDataToFile() { + mergeBuffers(); + + try { + os.write(totalBuffer, 0, totalBuffer.length); + } catch (IOException e) { + e.printStackTrace(); + } + + Intent intent = new Intent("com.wearscript.record.FILE_WRITTEN_AUDIO").putExtra(FILEPATH, filePath); + context.sendBroadcast(intent); + Log.d(LOG_TAG, "Sending broadcast: com.wearscript.record.FILE_WRITTEN_AUDIO"); + } +} + diff --git a/video/src/main/java/com/wearscript/record/AudioRecorder.java b/video/src/main/java/com/wearscript/record/AudioRecorder.java new file mode 100644 index 0000000..e2305a8 --- /dev/null +++ b/video/src/main/java/com/wearscript/record/AudioRecorder.java @@ -0,0 +1,61 @@ +package com.wearscript.record; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.util.Log; + +import java.io.File; + +public class AudioRecorder extends Service { + + private final String LOG_TAG = "AudioRecorder"; + + private AudioRecordThread recorder; + public static String MILLIS_EXTRA_KEY = "millis"; + + @Override + public void onCreate() { + super.onCreate(); + + Log.d(LOG_TAG, "Service Started"); + createDirectory(); + } + + @Override + public void onDestroy() { + Log.d(LOG_TAG, "Service Destroy"); + recorder.interrupt(); + super.onDestroy(); + } + + @Override + public IBinder onBind(Intent intent) { + // TODO: Return the communication channel to the service. + throw new UnsupportedOperationException("Not yet implemented"); + } + + private void createDirectory() { + File directory = new File(AudioRecordThread.directoryAudio); + if (!directory.isDirectory()){ + directory.mkdirs(); + } + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent.getAction() != null) { + if (intent.getAction().equals("com.wearscript.record.RECORD_AUDIO")) { + recorder = new AudioRecordThread(this, intent.getStringExtra("filePath")); + recorder.start(); + } else if (intent.getAction().equals("com.wearscript.record.SAVE_AUDIO")) { + recorder.writeAudioDataToFile(); + } else if (intent.getAction().equals("com.wearscript.record.STOP_AUDIO")) { + recorder.stopRecording(); + stopSelf(); + } + } + return 0; + } + +} diff --git a/video/src/main/java/com/wearscript/video/PlaybackActivity.java b/video/src/main/java/com/wearscript/record/PlaybackActivity.java similarity index 98% rename from video/src/main/java/com/wearscript/video/PlaybackActivity.java rename to video/src/main/java/com/wearscript/record/PlaybackActivity.java index b94a65e..83801e0 100644 --- a/video/src/main/java/com/wearscript/video/PlaybackActivity.java +++ b/video/src/main/java/com/wearscript/record/PlaybackActivity.java @@ -1,4 +1,4 @@ -package com.wearscript.video; +package com.wearscript.record; import android.app.Activity; import android.content.Intent; @@ -7,7 +7,6 @@ import android.os.Bundle; import android.util.Log; import android.widget.VideoView; - import java.io.File; public class PlaybackActivity extends Activity implements MediaPlayer.OnPreparedListener, diff --git a/video/src/main/java/com/wearscript/video/RecordActivity.java b/video/src/main/java/com/wearscript/record/RecordActivity.java similarity index 99% rename from video/src/main/java/com/wearscript/video/RecordActivity.java rename to video/src/main/java/com/wearscript/record/RecordActivity.java index 790432f..a7bbbda 100644 --- a/video/src/main/java/com/wearscript/video/RecordActivity.java +++ b/video/src/main/java/com/wearscript/record/RecordActivity.java @@ -1,4 +1,4 @@ -package com.wearscript.video; +package com.wearscript.record; import android.app.Activity; import android.content.Intent; @@ -21,8 +21,6 @@ import java.util.Date; import java.util.List; -import com.wearscript.video.WearScriptBroadcastReceiver; - public class RecordActivity extends Activity implements SurfaceHolder.Callback { private final static String TAG = "RecordActivity"; private final static boolean DBG = true; diff --git a/video/src/main/java/com/wearscript/video/WearScriptBroadcastReceiver.java b/video/src/main/java/com/wearscript/record/WearScriptBroadcastReceiver.java similarity index 92% rename from video/src/main/java/com/wearscript/video/WearScriptBroadcastReceiver.java rename to video/src/main/java/com/wearscript/record/WearScriptBroadcastReceiver.java index 509e730..9d22587 100644 --- a/video/src/main/java/com/wearscript/video/WearScriptBroadcastReceiver.java +++ b/video/src/main/java/com/wearscript/record/WearScriptBroadcastReceiver.java @@ -1,4 +1,4 @@ -package com.wearscript.video; +package com.wearscript.record; import android.content.BroadcastReceiver; import android.content.Context; @@ -7,9 +7,9 @@ public class WearScriptBroadcastReceiver extends BroadcastReceiver { - public static final String PLAYBACK_ACTION = "com.wearscript.video.PLAYBACK"; - public static final String RECORD_ACTION = "com.wearscript.video.RECORD"; - public static final String RECORD_RESULT_ACTION = "com.wearscript.video.RECORD_RESULT"; + public static final String PLAYBACK_ACTION = "com.wearscript.record.PLAYBACK"; + public static final String RECORD_ACTION = "com.wearscript.record.RECORD"; + public static final String RECORD_RESULT_ACTION = "com.wearscript.record.RECORD_RESULT"; private static final String TAG = "WearScriptBroadcastReceiver"; private static final boolean DBG = true; diff --git a/video/src/main/res/layout/activity_play.xml b/video/src/main/res/layout/activity_play.xml index 470475b..9b7cd48 100644 --- a/video/src/main/res/layout/activity_play.xml +++ b/video/src/main/res/layout/activity_play.xml @@ -2,7 +2,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" -tools:context="com.wearscript.video.PlaybackActivity"> +tools:context="com.wearscript.record.PlaybackActivity"> + tools:context="com.wearscript.record.RecordActivity"> \ No newline at end of file diff --git a/video/src/main/res/menu/record.xml b/video/src/main/res/menu/record.xml index ae77365..99fac1c 100644 --- a/video/src/main/res/menu/record.xml +++ b/video/src/main/res/menu/record.xml @@ -1,6 +1,6 @@ + tools:context="com.wearscript.record.RecordActivity" >