OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/audio/android/audio_track_output_stream.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
| 9 #include "base/logging.h" |
| 10 #include "base/single_thread_task_runner.h" |
| 11 #include "base/time/default_tick_clock.h" |
| 12 #include "jni/AudioTrackOutputStream_jni.h" |
| 13 #include "media/audio/audio_manager_base.h" |
| 14 |
| 15 using base::android::AttachCurrentThread; |
| 16 |
| 17 namespace media { |
| 18 |
| 19 // Android audio format. For more information, please see: |
| 20 // https://developer.android.com/reference/android/media/AudioFormat.html |
| 21 enum { |
| 22 kEncodingPcmFloat = 4, // ENCODING_PCM_FLOAT |
| 23 kEncodingAc3 = 5, // ENCODING_AC3 |
| 24 kEncodingEac3 = 6, // ENCODING_E_AC3 |
| 25 }; |
| 26 |
| 27 AudioTrackOutputStream::AudioTrackOutputStream(AudioManagerBase* manager, |
| 28 const AudioParameters& params) |
| 29 : params_(params), |
| 30 audio_manager_(manager), |
| 31 callback_(nullptr), |
| 32 audio_bus_(AudioBus::Create(params_)), |
| 33 muted_(false), |
| 34 volume_(1.0), |
| 35 total_read_frames_(0), |
| 36 tick_clock_(new base::DefaultTickClock()) { |
| 37 audio_bus_->Zero(); |
| 38 } |
| 39 |
| 40 AudioTrackOutputStream::~AudioTrackOutputStream() { |
| 41 DCHECK(!callback_); |
| 42 } |
| 43 |
| 44 bool AudioTrackOutputStream::Open() { |
| 45 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| 46 JNIEnv* env = AttachCurrentThread(); |
| 47 j_audio_output_stream_.Reset(Java_AudioTrackOutputStream_create(env)); |
| 48 |
| 49 int format = kEncodingPcmFloat; |
| 50 if (params_.IsRawFormat()) { |
| 51 if (params_.format() == AudioParameters::AUDIO_RAW_AC3) { |
| 52 format = kEncodingAc3; |
| 53 } else if (params_.format() == AudioParameters::AUDIO_RAW_EAC3) { |
| 54 format = kEncodingEac3; |
| 55 } else { |
| 56 NOTREACHED(); |
| 57 } |
| 58 } |
| 59 |
| 60 return Java_AudioTrackOutputStream_open(env, j_audio_output_stream_.obj(), |
| 61 params_.channels(), |
| 62 params_.sample_rate(), format); |
| 63 } |
| 64 |
| 65 void AudioTrackOutputStream::Start(AudioSourceCallback* callback) { |
| 66 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| 67 callback_ = callback; |
| 68 total_read_frames_ = 0; |
| 69 Java_AudioTrackOutputStream_start(AttachCurrentThread(), |
| 70 j_audio_output_stream_.obj(), |
| 71 reinterpret_cast<intptr_t>(this)); |
| 72 } |
| 73 |
| 74 void AudioTrackOutputStream::Stop() { |
| 75 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| 76 Java_AudioTrackOutputStream_stop(AttachCurrentThread(), |
| 77 j_audio_output_stream_.obj()); |
| 78 callback_ = nullptr; |
| 79 } |
| 80 |
| 81 void AudioTrackOutputStream::Close() { |
| 82 DCHECK(!callback_); |
| 83 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| 84 |
| 85 Java_AudioTrackOutputStream_close(AttachCurrentThread(), |
| 86 j_audio_output_stream_.obj()); |
| 87 audio_manager_->ReleaseOutputStream(this); |
| 88 } |
| 89 |
| 90 void AudioTrackOutputStream::SetMute(bool muted) { |
| 91 if (muted_ == muted) |
| 92 return; |
| 93 |
| 94 muted_ = muted; |
| 95 Java_AudioTrackOutputStream_setVolume(AttachCurrentThread(), |
| 96 j_audio_output_stream_.obj(), |
| 97 muted_ ? 0.0 : volume_); |
| 98 } |
| 99 |
| 100 void AudioTrackOutputStream::SetVolume(double volume) { |
| 101 // Track |volume_| since AudioTrack uses a scaled value. |
| 102 volume_ = volume; |
| 103 if (muted_) |
| 104 return; |
| 105 |
| 106 Java_AudioTrackOutputStream_setVolume(AttachCurrentThread(), |
| 107 j_audio_output_stream_.obj(), volume); |
| 108 }; |
| 109 |
| 110 void AudioTrackOutputStream::GetVolume(double* volume) { |
| 111 *volume = volume_; |
| 112 }; |
| 113 |
| 114 // AudioOutputStream::SourceCallback implementation methods called from Java. |
| 115 int AudioTrackOutputStream::OnMoreData(JNIEnv* env, |
| 116 jobject obj, |
| 117 jobject audio_data, |
| 118 int total_played_frames) { |
| 119 if (!callback_) |
| 120 return 0; |
| 121 |
| 122 int delay_in_frame = total_read_frames_ - total_played_frames; |
| 123 if (delay_in_frame < 0) |
| 124 delay_in_frame = 0; |
| 125 base::TimeDelta delay = base::TimeDelta::FromSecondsD( |
| 126 static_cast<double>(delay_in_frame) / params_.sample_rate()); |
| 127 |
| 128 callback_->OnMoreData(delay, tick_clock_->NowTicks(), 0, audio_bus_.get()); |
| 129 |
| 130 if (audio_bus_->data_size() <= 0) |
| 131 return 0; |
| 132 |
| 133 total_read_frames_ += audio_bus_->frames(); |
| 134 |
| 135 void* native_bus = env->GetDirectBufferAddress(audio_data); |
| 136 memcpy(native_bus, audio_bus_->channel(0), audio_bus_->data_size()); |
| 137 return audio_bus_->data_size(); |
| 138 } |
| 139 |
| 140 void AudioTrackOutputStream::OnError(JNIEnv* env, jobject obj) { |
| 141 DCHECK(callback_); |
| 142 callback_->OnError(this); |
| 143 } |
| 144 |
| 145 // static |
| 146 bool AudioTrackOutputStream::RegisterAudioTrackOutputStream(JNIEnv* env) { |
| 147 return RegisterNativesImpl(env); |
| 148 } |
| 149 |
| 150 } // namespace media |
OLD | NEW |