Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(630)

Unified Diff: media/base/android/java/src/org/chromium/media/AudioTrackOutputStream.java

Issue 1525033003: Add an AudioTrack based audio output stream. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/android/BUILD.gn ('k') | media/base/android/media_jni_registrar.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/android/java/src/org/chromium/media/AudioTrackOutputStream.java
diff --git a/media/base/android/java/src/org/chromium/media/AudioTrackOutputStream.java b/media/base/android/java/src/org/chromium/media/AudioTrackOutputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..54045e4bcda85d42eeb65e229e589b775c2eb0fc
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/AudioTrackOutputStream.java
@@ -0,0 +1,142 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.media;
+
+import android.annotation.TargetApi;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+
+import org.chromium.base.Log;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+import java.nio.ByteBuffer;
+
+@JNINamespace("media")
+class AudioTrackOutputStream implements AudioTrack.OnPlaybackPositionUpdateListener {
+ private static final String TAG = "cr.media";
+
+ private AudioTrack mAudioTrack;
+ private long mNativeAudioTrackOutputStream;
+ private int mBufferSizeInBytes;
+ private ByteBuffer mAudioBuffer;
+ private long mPeriodCount;
+
+ @CalledByNative
+ private static AudioTrackOutputStream create() {
+ return new AudioTrackOutputStream();
+ }
+
+ @CalledByNative
+ private boolean open(int channelCount, int sampleRate, int sampleFormat, int framesPerBuffer) {
+ assert (channelCount == 1 || channelCount == 2);
+ assert (sampleFormat == AudioFormat.ENCODING_PCM_16BIT || sampleFormat == AudioFormat.ENCODING_PCM_FLOAT);
+
+ int bytesPerSample = sampleFormat == AudioFormat.ENCODING_PCM_16BIT ? 2 : 4;
+ mBufferSizeInBytes = framesPerBuffer * channelCount * bytesPerSample;
+ int allocatedBufferSize = (int)(mBufferSizeInBytes * 3);
+ allocatedBufferSize += allocatedBufferSize % (channelCount * bytesPerSample);
+
+ // Size the playout buffer at 1.5 times the requested size; this allows
+ // us to refill at the halfway mark and have room to spare.
+ try {
+ mAudioTrack = new AudioTrack(
+ AudioManager.STREAM_MUSIC, sampleRate,
+ channelCount == 1 ? AudioFormat.CHANNEL_OUT_MONO
+ : AudioFormat.CHANNEL_OUT_STEREO,
+ sampleFormat, allocatedBufferSize, AudioTrack.MODE_STREAM);
+ } catch (IllegalArgumentException ile) {
+ Log.e(TAG, "Exception creating AudioTrack for playback: ", ile);
+ return false;
+ }
+
+ if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) {
+ Log.e(TAG, "Failed to create AudioTrack...");
+ return false;
+ }
+
+ // Setup periodic callbacks to deliver audio data.
+ mAudioTrack.setPlaybackPositionUpdateListener(this);
+ if (mAudioTrack.setPositionNotificationPeriod(framesPerBuffer) != AudioTrack.SUCCESS) {
+ Log.e(TAG, "Failed to set AudioTrack position listener.");
+ return false;
+ }
+
+ return true;
+ }
+
+ @CalledByNative
+ private void start(long nativeAudioTrackOutputStream) {
+ Log.w(TAG, "AudioTrackOutputStream.start()");
+ mPeriodCount = 0;
+ mNativeAudioTrackOutputStream = nativeAudioTrackOutputStream;
+
+ // Prime the buffer with silence.
+ mAudioBuffer = ByteBuffer.allocateDirect(mBufferSizeInBytes);
+ int bytesWritten = 0;
+ do {
+ bytesWritten = mAudioTrack.write(mAudioBuffer.asReadOnlyBuffer(), mBufferSizeInBytes, AudioTrack.WRITE_BLOCKING);
+ } while (bytesWritten == mBufferSizeInBytes);
+ mAudioTrack.play();
+
+ //onPeriodicNotification(mAudioTrack);
+ }
+
+ @CalledByNative
+ private void stop() {
+ Log.w(TAG, "AudioTrackOutputStream.stop()");
+ mAudioTrack.pause();
+ mAudioTrack.flush();
+ mNativeAudioTrackOutputStream = 0;
+ }
+
+ @SuppressWarnings("deprecation")
+ @CalledByNative
+ private void setVolume(double volume) {
+ Log.w(TAG, "AudioTrackOutputStream.setVolume()");
+ // Chrome sends the volume in the range [0, 1.0], whereas Android
+ // expects the volume to be within [0, getMaxVolume()].
+ float scaledVolume = (float)(volume * mAudioTrack.getMaxVolume());
+ mAudioTrack.setStereoVolume(scaledVolume, scaledVolume);
+ }
+
+ @CalledByNative
+ private void close() {
+ Log.w(TAG, "AudioTrackOutputStream.close()");
+ if (mAudioTrack != null)
+ mAudioTrack.release();
+ }
+
+ @Override
+ public void onMarkerReached(AudioTrack track) {
+ }
+
+ @Override
+ public void onPeriodicNotification(AudioTrack track) {
+ if (mNativeAudioTrackOutputStream == 0)
+ return;
+ // // Our period is half the requested size and our buffer size is 1.5
+ // // times the requested size, so skip every other interval such that we
+ // // have enough data left for glitch free playback and enough space to
+ // // fill a full request.
+ // if (mPeriodCount++ % 2 == 1)
+ // return;
+
+ // TODO(dalecurtis): Add delay information here.
+ // TODO(dalecurtis): Add < lollipop support.
+ //short[] nativeAudioData = nativeOnMoreData(nativeAudioTrackOutputStream, 0);
+ nativeOnMoreData(mNativeAudioTrackOutputStream, mAudioBuffer, 0);
+
+ long start = System.nanoTime();
+ mAudioTrack.write(mAudioBuffer.asReadOnlyBuffer(), mBufferSizeInBytes,
+ AudioTrack.WRITE_NON_BLOCKING);
+ //Log.w(TAG, "Write took: " + (System.nanoTime() - start) / (1000.0 * 1000.0) + "ms");
+ }
+
+ //private native short[] nativeOnMoreDataOld(long nativeAudioTrackOutputStream, int delayInFrames);
+ private native void nativeOnMoreData(long nativeAudioTrackOutputStream, ByteBuffer audioData, int delayInFrames);
+ private native void nativeOnError(long nativeAudioTrackOutputStream);
+}
« no previous file with comments | « media/base/android/BUILD.gn ('k') | media/base/android/media_jni_registrar.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698