OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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), | |
DaleCurtis
2017/06/15 21:46:31
Inline initialize these parameters in the header f
AndyWu
2017/08/02 01:43:38
Done.
| |
32 audio_bus_(AudioBus::Create(params_)), | |
33 muted_(false), | |
34 volume_(1.0), | |
35 total_read_frames_(0), | |
36 tick_clock_(new base::DefaultTickClock()) { | |
DaleCurtis
2017/06/15 21:46:31
No need for this unless you're going to add a test
AndyWu
2017/08/02 01:43:38
Done.
| |
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_.IsBitstreamFormat()) { | |
51 if (params_.format() == AudioParameters::AUDIO_BITSTREAM_AC3) { | |
52 format = kEncodingAc3; | |
53 } else if (params_.format() == AudioParameters::AUDIO_BITSTREAM_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) { | |
DaleCurtis
2017/06/15 21:46:31
As Chris notes, this should be an int64_t.
AndyWu
2017/08/02 01:43:38
AudioTrack.getPlaybackHeadPosition()[1] returns a
DaleCurtis
2017/08/03 01:38:10
Overflow isn't defined for signed types, so if you
AndyWu
2017/08/03 17:11:17
Well, I consider 0x7FFFFFFF + 1 = 0x80000000 is ov
DaleCurtis
2017/08/03 17:22:55
Thanks for changing it. For future reference, what
AndyWu
2017/08/03 21:58:45
Thanks for the great information. :) It does make
| |
119 if (!callback_) | |
120 return 0; | |
121 | |
122 int delay_in_frame = total_read_frames_ - total_played_frames; | |
DaleCurtis
2017/06/15 21:46:31
Ditto; int64_t.
AndyWu
2017/08/02 01:43:38
Done.
| |
123 if (delay_in_frame < 0) | |
DaleCurtis
2017/06/15 21:46:31
Should be impossible?, DCHECK instead?
AndyWu
2017/08/02 01:43:38
Normally, it should not happen. However, it could
| |
124 delay_in_frame = 0; | |
125 base::TimeDelta delay = base::TimeDelta::FromSecondsD( | |
DaleCurtis
2017/06/15 21:46:31
Use AudioTimestampHelper::FramesToTime().
AndyWu
2017/08/02 01:43:38
Done.
| |
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); | |
DaleCurtis
2017/06/15 21:46:31
Get this pointer ahead of time and use AudioBus::W
AndyWu
2017/08/02 01:43:38
TBD
| |
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(); | |
143 } | |
144 | |
145 // static | |
146 bool AudioTrackOutputStream::RegisterAudioTrackOutputStream(JNIEnv* env) { | |
147 return RegisterNativesImpl(env); | |
148 } | |
149 | |
150 } // namespace media | |
OLD | NEW |