diff options
author | henrike@webrtc.org <henrike@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2013-12-11 21:42:44 +0000 |
---|---|---|
committer | henrike@webrtc.org <henrike@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2013-12-11 21:42:44 +0000 |
commit | 9ee75e9c77b467e74e470905822d0279b0e8a639 (patch) | |
tree | 2a481ef9afe8a72bab714e16b94fbb57c7cbd61c /webrtc/modules/audio_device/android/java | |
parent | f41f06b916adc58745d5c5dbbd6803c7566dbedd (diff) | |
download | webrtc-9ee75e9c77b467e74e470905822d0279b0e8a639.tar.gz |
Enables mixing and matching Java and native audio. It is used for getting best of both worlds capabilities (AEC and low latency).
BUG=N/A
R=fischman@webrtc.org, niklas.enbom@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/4189004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@5270 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'webrtc/modules/audio_device/android/java')
-rw-r--r-- | webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioRecord.java | 197 | ||||
-rw-r--r-- | webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioTrack.java (renamed from webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRTCAudioDevice.java) | 203 |
2 files changed, 201 insertions, 199 deletions
diff --git a/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioRecord.java b/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioRecord.java new file mode 100644 index 0000000000..9167af02a5 --- /dev/null +++ b/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioRecord.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc.voiceengine; + +import java.nio.ByteBuffer; +import java.util.concurrent.locks.ReentrantLock; + +import android.content.Context; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioRecord; +import android.media.MediaRecorder.AudioSource; +import android.util.Log; + +class WebRtcAudioRecord { + private AudioRecord _audioRecord = null; + + private Context _context; + + private ByteBuffer _recBuffer; + private byte[] _tempBufRec; + + private final ReentrantLock _recLock = new ReentrantLock(); + + private boolean _doRecInit = true; + private boolean _isRecording = false; + + private int _bufferedRecSamples = 0; + + WebRtcAudioRecord() { + try { + _recBuffer = ByteBuffer.allocateDirect(2 * 480); // Max 10 ms @ 48 + // kHz + } catch (Exception e) { + DoLog(e.getMessage()); + } + + _tempBufRec = new byte[2 * 480]; + } + + @SuppressWarnings("unused") + private int InitRecording(int audioSource, int sampleRate) { + audioSource = AudioSource.VOICE_COMMUNICATION; + // get the minimum buffer size that can be used + int minRecBufSize = AudioRecord.getMinBufferSize( + sampleRate, + AudioFormat.CHANNEL_IN_MONO, + AudioFormat.ENCODING_PCM_16BIT); + + // DoLog("min rec buf size is " + minRecBufSize); + + // double size to be more safe + int recBufSize = minRecBufSize * 2; + // On average half of the samples have been recorded/buffered and the + // recording interval is 1/100s. + _bufferedRecSamples = sampleRate / 200; + // DoLog("rough rec delay set to " + _bufferedRecSamples); + + // release the object + if (_audioRecord != null) { + _audioRecord.release(); + _audioRecord = null; + } + + try { + _audioRecord = new AudioRecord( + audioSource, + sampleRate, + AudioFormat.CHANNEL_IN_MONO, + AudioFormat.ENCODING_PCM_16BIT, + recBufSize); + + } catch (Exception e) { + DoLog(e.getMessage()); + return -1; + } + + // check that the audioRecord is ready to be used + if (_audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { + // DoLog("rec not initialized " + sampleRate); + return -1; + } + + // DoLog("rec sample rate set to " + sampleRate); + + return _bufferedRecSamples; + } + + @SuppressWarnings("unused") + private int StartRecording() { + // start recording + try { + _audioRecord.startRecording(); + + } catch (IllegalStateException e) { + e.printStackTrace(); + return -1; + } + + _isRecording = true; + return 0; + } + + @SuppressWarnings("unused") + private int StopRecording() { + _recLock.lock(); + try { + // only stop if we are recording + if (_audioRecord.getRecordingState() == + AudioRecord.RECORDSTATE_RECORDING) { + // stop recording + try { + _audioRecord.stop(); + } catch (IllegalStateException e) { + e.printStackTrace(); + return -1; + } + } + + // release the object + _audioRecord.release(); + _audioRecord = null; + + } finally { + // Ensure we always unlock, both for success, exception or error + // return. + _doRecInit = true; + _recLock.unlock(); + } + + _isRecording = false; + return 0; + } + + @SuppressWarnings("unused") + private int RecordAudio(int lengthInBytes) { + _recLock.lock(); + + try { + if (_audioRecord == null) { + return -2; // We have probably closed down while waiting for rec + // lock + } + + // Set priority, only do once + if (_doRecInit == true) { + try { + android.os.Process.setThreadPriority( + android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); + } catch (Exception e) { + DoLog("Set rec thread priority failed: " + e.getMessage()); + } + _doRecInit = false; + } + + int readBytes = 0; + _recBuffer.rewind(); // Reset the position to start of buffer + readBytes = _audioRecord.read(_tempBufRec, 0, lengthInBytes); + // DoLog("read " + readBytes + "from SC"); + _recBuffer.put(_tempBufRec); + + if (readBytes != lengthInBytes) { + // DoLog("Could not read all data from sc (read = " + readBytes + // + ", length = " + lengthInBytes + ")"); + return -1; + } + + } catch (Exception e) { + DoLogErr("RecordAudio try failed: " + e.getMessage()); + + } finally { + // Ensure we always unlock, both for success, exception or error + // return. + _recLock.unlock(); + } + + return _bufferedRecSamples; + } + + final String logTag = "WebRTC AD java"; + + private void DoLog(String msg) { + Log.d(logTag, msg); + } + + private void DoLogErr(String msg) { + Log.e(logTag, msg); + } +} diff --git a/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRTCAudioDevice.java b/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioTrack.java index c324b9c082..273d03f352 100644 --- a/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRTCAudioDevice.java +++ b/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/WebRtcAudioTrack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -20,106 +20,34 @@ import android.media.AudioRecord; import android.media.AudioTrack; import android.util.Log; -class WebRTCAudioDevice { +class WebRtcAudioTrack { private AudioTrack _audioTrack = null; - private AudioRecord _audioRecord = null; private Context _context; private AudioManager _audioManager; private ByteBuffer _playBuffer; - private ByteBuffer _recBuffer; private byte[] _tempBufPlay; - private byte[] _tempBufRec; private final ReentrantLock _playLock = new ReentrantLock(); - private final ReentrantLock _recLock = new ReentrantLock(); private boolean _doPlayInit = true; private boolean _doRecInit = true; private boolean _isRecording = false; private boolean _isPlaying = false; - private int _bufferedRecSamples = 0; private int _bufferedPlaySamples = 0; private int _playPosition = 0; - WebRTCAudioDevice() { + WebRtcAudioTrack() { try { _playBuffer = ByteBuffer.allocateDirect(2 * 480); // Max 10 ms @ 48 // kHz - _recBuffer = ByteBuffer.allocateDirect(2 * 480); // Max 10 ms @ 48 - // kHz } catch (Exception e) { DoLog(e.getMessage()); } _tempBufPlay = new byte[2 * 480]; - _tempBufRec = new byte[2 * 480]; - } - - @SuppressWarnings("unused") - private int InitRecording(int audioSource, int sampleRate) { - // get the minimum buffer size that can be used - int minRecBufSize = AudioRecord.getMinBufferSize( - sampleRate, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT); - - // DoLog("min rec buf size is " + minRecBufSize); - - // double size to be more safe - int recBufSize = minRecBufSize * 2; - _bufferedRecSamples = (5 * sampleRate) / 200; - // DoLog("rough rec delay set to " + _bufferedRecSamples); - - // release the object - if (_audioRecord != null) { - _audioRecord.release(); - _audioRecord = null; - } - - try { - _audioRecord = new AudioRecord( - audioSource, - sampleRate, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT, - recBufSize); - - } catch (Exception e) { - DoLog(e.getMessage()); - return -1; - } - - // check that the audioRecord is ready to be used - if (_audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { - // DoLog("rec not initialized " + sampleRate); - return -1; - } - - // DoLog("rec sample rate set to " + sampleRate); - - return _bufferedRecSamples; - } - - @SuppressWarnings("unused") - private int StartRecording() { - if (_isPlaying == false) { - SetAudioMode(true); - } - - // start recording - try { - _audioRecord.startRecording(); - - } catch (IllegalStateException e) { - e.printStackTrace(); - return -1; - } - - _isRecording = true; - return 0; } @SuppressWarnings("unused") @@ -181,10 +109,6 @@ class WebRTCAudioDevice { @SuppressWarnings("unused") private int StartPlayback() { - if (_isRecording == false) { - SetAudioMode(true); - } - // start playout try { _audioTrack.play(); @@ -199,41 +123,6 @@ class WebRTCAudioDevice { } @SuppressWarnings("unused") - private int StopRecording() { - _recLock.lock(); - try { - // only stop if we are recording - if (_audioRecord.getRecordingState() == - AudioRecord.RECORDSTATE_RECORDING) { - // stop recording - try { - _audioRecord.stop(); - } catch (IllegalStateException e) { - e.printStackTrace(); - return -1; - } - } - - // release the object - _audioRecord.release(); - _audioRecord = null; - - } finally { - // Ensure we always unlock, both for success, exception or error - // return. - _doRecInit = true; - _recLock.unlock(); - } - - if (_isPlaying == false) { - SetAudioMode(false); - } - - _isRecording = false; - return 0; - } - - @SuppressWarnings("unused") private int StopPlayback() { _playLock.lock(); try { @@ -262,10 +151,6 @@ class WebRTCAudioDevice { _playLock.unlock(); } - if (_isRecording == false) { - SetAudioMode(false); - } - _isPlaying = false; return 0; } @@ -273,8 +158,6 @@ class WebRTCAudioDevice { @SuppressWarnings("unused") private int PlayAudio(int lengthInBytes) { - int bufferedSamples = 0; - _playLock.lock(); try { if (_audioTrack == null) { @@ -311,10 +194,6 @@ class WebRTCAudioDevice { _bufferedPlaySamples -= (pos - _playPosition); _playPosition = pos; - if (!_isRecording) { - bufferedSamples = _bufferedPlaySamples; - } - if (written != lengthInBytes) { // DoLog("Could not write all data to sc (written = " + written // + ", length = " + lengthInBytes + ")"); @@ -327,52 +206,7 @@ class WebRTCAudioDevice { _playLock.unlock(); } - return bufferedSamples; - } - - @SuppressWarnings("unused") - private int RecordAudio(int lengthInBytes) { - _recLock.lock(); - - try { - if (_audioRecord == null) { - return -2; // We have probably closed down while waiting for rec - // lock - } - - // Set priority, only do once - if (_doRecInit == true) { - try { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); - } catch (Exception e) { - DoLog("Set rec thread priority failed: " + e.getMessage()); - } - _doRecInit = false; - } - - int readBytes = 0; - _recBuffer.rewind(); // Reset the position to start of buffer - readBytes = _audioRecord.read(_tempBufRec, 0, lengthInBytes); - // DoLog("read " + readBytes + "from SC"); - _recBuffer.put(_tempBufRec); - - if (readBytes != lengthInBytes) { - // DoLog("Could not read all data from sc (read = " + readBytes - // + ", length = " + lengthInBytes + ")"); - return -1; - } - - } catch (Exception e) { - DoLogErr("RecordAudio try failed: " + e.getMessage()); - - } finally { - // Ensure we always unlock, both for success, exception or error - // return. - _recLock.unlock(); - } - - return (_bufferedPlaySamples); + return _bufferedPlaySamples; } @SuppressWarnings("unused") @@ -463,35 +297,6 @@ class WebRTCAudioDevice { return level; } - private void SetAudioMode(boolean startCall) { - int apiLevel = android.os.Build.VERSION.SDK_INT; - - if (_audioManager == null && _context != null) { - _audioManager = (AudioManager) - _context.getSystemService(Context.AUDIO_SERVICE); - } - - if (_audioManager == null) { - DoLogErr("Could not set audio mode - no audio manager"); - return; - } - - // ***IMPORTANT*** When the API level for honeycomb (H) has been - // decided, - // the condition should be changed to include API level 8 to H-1. - if ((android.os.Build.BRAND.equals("Samsung") || - android.os.Build.BRAND.equals("samsung")) && - (8 == apiLevel)) { - // Set Samsung specific VoIP mode for 2.2 devices - // 4 is VoIP mode - int mode = (startCall ? 4 : AudioManager.MODE_NORMAL); - _audioManager.setMode(mode); - if (_audioManager.getMode() != mode) { - DoLogErr("Could not set audio mode for Samsung device"); - } - } - } - final String logTag = "WebRTC AD java"; private void DoLog(String msg) { |