Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
37b7351
Add audio recording classes: AudioRecorder (a service) and AudioRecor…
blakeelias Jun 10, 2014
245ceeb
Move audio and video recording to same package
blakeelias Jun 10, 2014
e907031
Record a continuous amount of audio until interrupted, then send a br…
blakeelias Jun 11, 2014
d88b871
Refactor pollRingBuffer() to mergeBuffers()
blakeelias Jun 17, 2014
2e81246
Remove saveAudio()
blakeelias Jun 17, 2014
1c6904d
Create constant WAV_HEADER_LENGTH
blakeelias Jun 17, 2014
300c2d0
Remove comments in WAV header creation
blakeelias Jun 17, 2014
7d6ac2a
Rename createMemoraDirectory() to createDirectory()
blakeelias Jun 17, 2014
a80722e
Remove empty constructor
blakeelias Jun 17, 2014
6060a41
Remove call to setThreadPriority
blakeelias Jun 17, 2014
d3bc49d
Fix code style / indentation issues
blakeelias Jun 17, 2014
9b99698
Convert remaining references to com.wearscript.video into com.wearscr…
blakeelias Jun 17, 2014
bca7cf9
Remove one more reference to com.wearscript.video
blakeelias Jun 18, 2014
d7c07d2
Add constant FILEPATH
blakeelias Jun 18, 2014
a01f430
Remove commented code
blakeelias Jun 18, 2014
f8a0f44
Move save-file logic inside of while recording loop
blakeelias Jun 19, 2014
9aef108
Save WAV header with long length so that we don't need to edit it whe…
blakeelias Jun 19, 2014
dad4016
Add ability to save an updated audio file whenever we want to while c…
blakeelias Jun 19, 2014
440958f
Accept audio file name passed in when recording is started
blakeelias Jun 19, 2014
5b251ea
Have AudioRecordThread accept filePath instead of fileName
blakeelias Jun 20, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions video/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".PlaybackActivity"
android:name="com.wearscript.record.PlaybackActivity"
android:label="@string/title_activity_play" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
Expand All @@ -23,7 +23,7 @@
</intent-filter>
</activity>
<activity
android:name="com.wearscript.video.RecordActivity"
android:name="com.wearscript.record.RecordActivity"
android:label="@string/title_activity_record" >
<intent-filter>
<action android:name="android.intent.action.EDIT" />
Expand All @@ -34,14 +34,26 @@
</intent-filter>
</activity>

<receiver android:name=".WearScriptBroadcastReceiver">
<receiver android:name="com.wearscript.record.WearScriptBroadcastReceiver">
<intent-filter>
<action android:name="com.wearscript.video.PLAYBACK"/>
<action android:name="com.wearscript.video.RECORD" />
<action android:name="com.wearscript.video.RECORD_RESULT" />
</intent-filter>
</receiver>

<service
android:name="com.wearscript.record.AudioRecorder"
android:enabled="true"
android:label="@string/app_name">

<intent-filter>
<action android:name="com.wearscript.record.RECORD_AUDIO" />
<action android:name="com.wearscript.record.SAVE_AUDIO" />
</intent-filter>

</service>


</application>

Expand Down
201 changes: 201 additions & 0 deletions video/src/main/java/com/wearscript/record/AudioRecordThread.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
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{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a space after Thread


private static final String LOG_TAG = "Audio";

private static final int RECORDER_SAMPLERATE = 8000;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix odd indentation

private static final int ENCODING_TYPE = AudioFormat.ENCODING_PCM_16BIT;
public static final int WAV_HEADER_LENGTH = 44;
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;
private String latestFilePath = null;

AudioRecord recorder = null;

/**
* Give the thread high priority so that it's not cancelled unexpectedly, and start it
*/

private ArrayList<byte[]> buffers;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix odd indentation

private byte[] totalBuffer;

Context context;

public AudioRecordThread(Context context)
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put open brace at the end of previous line. Please apply this convention throughout

this.context = context;
}

@Override
public void run()
{
Log.d(LOG_TAG, "Running Audio Thread");

buffers = new ArrayList<byte[]>();
int N = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,CHANNEL_TYPE,ENCODING_TYPE);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces after commas

Log.d(LOG_TAG, ""+N);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces around the +

try{
recorder = new AudioRecord(AUDIO_SOURCE, RECORDER_SAMPLERATE, CHANNEL_TYPE, ENCODING_TYPE, N*10);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too indented

}
catch(Throwable e){
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space after paren

Log.d(LOG_TAG, e.toString());
return;
}
recorder.startRecording();

try{
while(!interrupted() && !pollingBuffer)
{
buffers.add(new byte[bufferSize]);
recorder.read(buffers.get(buffers.size()-1),0,bufferSize);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces after commas

}
mergeBuffers();
writeAudioDataToFile();
pollingBuffer = false;
Log.d(LOG_TAG, "Audio Saved");
}
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");
}
}

public String startPolling(long millis){
pollingBuffer = true;
latestFilePath = audioFileName(millis);
return latestFilePath;
}

private void mergeBuffers(){
Log.d(LOG_TAG, "in mergeBuffers()");
int i;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix indentation

int j;
int ix = 0;
totalBuffer = new byte[buffers.size() * bufferSize];
for(i = 0; i<buffers.size(); i++){
for(j = 0; j<bufferSize; j++){
totalBuffer[ix] = buffers.get(i)[j];
ix++;
}
}
}

private String audioFileName(long millis) {
return directoryAudio + File.separator + String.valueOf(millis) + ".wav";
}

private void writeAudioDataToFile() {
int totalAudioLen = buffers.size() * bufferSize;
int totalDataLen = (totalAudioLen * NUM_CHANNELS * BITS_PER_SAMPLE / 8) + 36;
//String filePath = audioFileName();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a01f430

byte header[] = new byte[WAV_HEADER_LENGTH];
byte wavFile[] = new byte[totalAudioLen + header.length];

FileOutputStream os = null;
try {
os = new FileOutputStream(latestFilePath);
Log.d(LOG_TAG, "file path: " + latestFilePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 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);

System.arraycopy(header, 0, wavFile, 0, header.length);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix indentation

System.arraycopy(totalBuffer, 0, wavFile, header.length, totalBuffer.length);

try {
os.write(wavFile, 0, wavFile.length);
} catch (IOException e) {
e.printStackTrace();
}

try {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix indentation

os.close();
} catch (IOException e) {
e.printStackTrace();
}

Intent intent = new Intent("com.wearscript.record.FILE_WRITTEN_AUDIO").putExtra("filepath", latestFilePath);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider making "filepath" a static final variable at the top

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d7c07d2

context.sendBroadcast(intent);
Log.d(LOG_TAG, "Sending broadcast: com.wearscript.record.FILE_WRITTEN_AUDIO");
}
}

60 changes: 60 additions & 0 deletions video/src/main/java/com/wearscript/record/AudioRecorder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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();

recorder = new AudioRecordThread(this);
recorder.start();
}

@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 && intent.getAction().equals("com.wearscript.record.SAVE_AUDIO")) {
Log.d(LOG_TAG, "Got message");
long millis = intent.getExtras().getLong(MILLIS_EXTRA_KEY);
Log.d(LOG_TAG, "millis: " + millis);
String filepath = recorder.startPolling(millis);
Log.d(LOG_TAG, "filepath: " + filepath);
}
return 0;
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wearscript.video;
package com.wearscript.record;

import android.app.Activity;
import android.content.Intent;
Expand All @@ -8,6 +8,8 @@
import android.util.Log;
import android.widget.VideoView;

import com.wearscript.video.R;

import java.io.File;

public class PlaybackActivity extends Activity implements MediaPlayer.OnPreparedListener,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wearscript.video;
package com.wearscript.record;

import android.app.Activity;
import android.content.Intent;
Expand All @@ -21,7 +21,7 @@
import java.util.Date;
import java.util.List;

import com.wearscript.video.WearScriptBroadcastReceiver;
import com.wearscript.video.R;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uh-oh, why doesn't this say com.wearscript.record?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9b99698


public class RecordActivity extends Activity implements SurfaceHolder.Callback {
private final static String TAG = "RecordActivity";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wearscript.video;
package com.wearscript.record;

import android.content.BroadcastReceiver;
import android.content.Context;
Expand Down
2 changes: 1 addition & 1 deletion video/src/main/res/layout/activity_play.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">

<VideoView
android:id = "@+id/video"
Expand Down
2 changes: 1 addition & 1 deletion video/src/main/res/layout/activity_record.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
android:layout_height="match_parent"
android:id="@+id/camera_preview"
tools:ignore="MergeRootFrame"
tools:context="com.wearscript.video.RecordActivity">
tools:context="com.wearscript.record.RecordActivity">

</FrameLayout>
2 changes: 1 addition & 1 deletion video/src/main/res/menu/record.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.wearscript.video.RecordActivity" >
tools:context="com.wearscript.record.RecordActivity" >

<item android:id="@+id/action_settings"
android:title="@string/action_settings"
Expand Down