Index: media/audio/android/audio_track_output_stream.cc |
diff --git a/media/audio/android/audio_track_output_stream.cc b/media/audio/android/audio_track_output_stream.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3ebd5457a8f7f90020ad6045ced028a844980281 |
--- /dev/null |
+++ b/media/audio/android/audio_track_output_stream.cc |
@@ -0,0 +1,150 @@ |
+// Copyright 2016 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. |
+ |
+#include "media/audio/android/audio_track_output_stream.h" |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/logging.h" |
+#include "base/single_thread_task_runner.h" |
+#include "base/time/default_tick_clock.h" |
+#include "jni/AudioTrackOutputStream_jni.h" |
+#include "media/audio/audio_manager_base.h" |
+ |
+using base::android::AttachCurrentThread; |
+ |
+namespace media { |
+ |
+// Android audio format. For more information, please see: |
+// https://developer.android.com/reference/android/media/AudioFormat.html |
+enum { |
+ kEncodingPcmFloat = 4, // ENCODING_PCM_FLOAT |
+ kEncodingAc3 = 5, // ENCODING_AC3 |
+ kEncodingEac3 = 6, // ENCODING_E_AC3 |
+}; |
+ |
+AudioTrackOutputStream::AudioTrackOutputStream(AudioManagerBase* manager, |
+ const AudioParameters& params) |
+ : params_(params), |
+ audio_manager_(manager), |
+ callback_(nullptr), |
+ audio_bus_(AudioBus::Create(params_)), |
+ muted_(false), |
+ volume_(1.0), |
+ total_read_frames_(0), |
+ tick_clock_(new base::DefaultTickClock()) { |
+ audio_bus_->Zero(); |
+} |
+ |
+AudioTrackOutputStream::~AudioTrackOutputStream() { |
+ DCHECK(!callback_); |
+} |
+ |
+bool AudioTrackOutputStream::Open() { |
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
+ JNIEnv* env = AttachCurrentThread(); |
+ j_audio_output_stream_.Reset(Java_AudioTrackOutputStream_create(env)); |
+ |
+ int format = kEncodingPcmFloat; |
+ if (params_.IsRawFormat()) { |
+ if (params_.format() == AudioParameters::AUDIO_RAW_AC3) { |
+ format = kEncodingAc3; |
+ } else if (params_.format() == AudioParameters::AUDIO_RAW_EAC3) { |
+ format = kEncodingEac3; |
+ } else { |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ return Java_AudioTrackOutputStream_open(env, j_audio_output_stream_.obj(), |
+ params_.channels(), |
+ params_.sample_rate(), format); |
+} |
+ |
+void AudioTrackOutputStream::Start(AudioSourceCallback* callback) { |
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
+ callback_ = callback; |
+ total_read_frames_ = 0; |
+ Java_AudioTrackOutputStream_start(AttachCurrentThread(), |
+ j_audio_output_stream_.obj(), |
+ reinterpret_cast<intptr_t>(this)); |
+} |
+ |
+void AudioTrackOutputStream::Stop() { |
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
+ Java_AudioTrackOutputStream_stop(AttachCurrentThread(), |
+ j_audio_output_stream_.obj()); |
+ callback_ = nullptr; |
+} |
+ |
+void AudioTrackOutputStream::Close() { |
+ DCHECK(!callback_); |
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
+ |
+ Java_AudioTrackOutputStream_close(AttachCurrentThread(), |
+ j_audio_output_stream_.obj()); |
+ audio_manager_->ReleaseOutputStream(this); |
+} |
+ |
+void AudioTrackOutputStream::SetMute(bool muted) { |
+ if (muted_ == muted) |
+ return; |
+ |
+ muted_ = muted; |
+ Java_AudioTrackOutputStream_setVolume(AttachCurrentThread(), |
+ j_audio_output_stream_.obj(), |
+ muted_ ? 0.0 : volume_); |
+} |
+ |
+void AudioTrackOutputStream::SetVolume(double volume) { |
+ // Track |volume_| since AudioTrack uses a scaled value. |
+ volume_ = volume; |
+ if (muted_) |
+ return; |
+ |
+ Java_AudioTrackOutputStream_setVolume(AttachCurrentThread(), |
+ j_audio_output_stream_.obj(), volume); |
+}; |
+ |
+void AudioTrackOutputStream::GetVolume(double* volume) { |
+ *volume = volume_; |
+}; |
+ |
+// AudioOutputStream::SourceCallback implementation methods called from Java. |
+int AudioTrackOutputStream::OnMoreData(JNIEnv* env, |
+ jobject obj, |
+ jobject audio_data, |
+ int total_played_frames) { |
+ if (!callback_) |
+ return 0; |
+ |
+ int delay_in_frame = total_read_frames_ - total_played_frames; |
+ if (delay_in_frame < 0) |
+ delay_in_frame = 0; |
+ base::TimeDelta delay = base::TimeDelta::FromSecondsD( |
+ static_cast<double>(delay_in_frame) / params_.sample_rate()); |
+ |
+ callback_->OnMoreData(delay, tick_clock_->NowTicks(), 0, audio_bus_.get()); |
+ |
+ if (audio_bus_->data_size() <= 0) |
+ return 0; |
+ |
+ total_read_frames_ += audio_bus_->frames(); |
+ |
+ void* native_bus = env->GetDirectBufferAddress(audio_data); |
+ memcpy(native_bus, audio_bus_->channel(0), audio_bus_->data_size()); |
+ return audio_bus_->data_size(); |
+} |
+ |
+void AudioTrackOutputStream::OnError(JNIEnv* env, jobject obj) { |
+ DCHECK(callback_); |
+ callback_->OnError(this); |
+} |
+ |
+// static |
+bool AudioTrackOutputStream::RegisterAudioTrackOutputStream(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+} // namespace media |