OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // THREAD SAFETY | 5 // THREAD SAFETY |
6 // | 6 // |
7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used | 7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used |
8 // from the audio thread. We DCHECK on this assumption whenever we can. | 8 // from the audio thread. We DCHECK on this assumption whenever we can. |
9 // | 9 // |
10 // SEMANTICS OF Close() | 10 // SEMANTICS OF Close() |
(...skipping 19 matching lines...) Expand all Loading... |
30 // When |stop_stream_| is set, no more commands will be made against the | 30 // When |stop_stream_| is set, no more commands will be made against the |
31 // ALSA device, and playback will effectively stop. From the client's point of | 31 // ALSA device, and playback will effectively stop. From the client's point of |
32 // view, it will seem that the device has just clogged and stopped requesting | 32 // view, it will seem that the device has just clogged and stopped requesting |
33 // data. | 33 // data. |
34 | 34 |
35 #include "media/audio/alsa/alsa_output.h" | 35 #include "media/audio/alsa/alsa_output.h" |
36 | 36 |
37 #include <stddef.h> | 37 #include <stddef.h> |
38 | 38 |
39 #include <algorithm> | 39 #include <algorithm> |
| 40 #include <utility> |
40 | 41 |
41 #include "base/bind.h" | 42 #include "base/bind.h" |
42 #include "base/logging.h" | 43 #include "base/logging.h" |
43 #include "base/memory/free_deleter.h" | 44 #include "base/memory/free_deleter.h" |
44 #include "base/stl_util.h" | 45 #include "base/stl_util.h" |
45 #include "base/threading/thread_task_runner_handle.h" | 46 #include "base/threading/thread_task_runner_handle.h" |
| 47 #include "base/time/default_tick_clock.h" |
46 #include "base/trace_event/trace_event.h" | 48 #include "base/trace_event/trace_event.h" |
47 #include "media/audio/alsa/alsa_util.h" | 49 #include "media/audio/alsa/alsa_util.h" |
48 #include "media/audio/alsa/alsa_wrapper.h" | 50 #include "media/audio/alsa/alsa_wrapper.h" |
49 #include "media/audio/alsa/audio_manager_alsa.h" | 51 #include "media/audio/alsa/audio_manager_alsa.h" |
50 #include "media/base/channel_mixer.h" | 52 #include "media/base/channel_mixer.h" |
51 #include "media/base/data_buffer.h" | 53 #include "media/base/data_buffer.h" |
52 #include "media/base/seekable_buffer.h" | 54 #include "media/base/seekable_buffer.h" |
53 | 55 |
54 namespace media { | 56 namespace media { |
55 | 57 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 break; | 120 break; |
119 case AlsaPcmOutputStream::kIsPlaying: | 121 case AlsaPcmOutputStream::kIsPlaying: |
120 os << "kIsPlaying"; | 122 os << "kIsPlaying"; |
121 break; | 123 break; |
122 case AlsaPcmOutputStream::kIsStopped: | 124 case AlsaPcmOutputStream::kIsStopped: |
123 os << "kIsStopped"; | 125 os << "kIsStopped"; |
124 break; | 126 break; |
125 case AlsaPcmOutputStream::kIsClosed: | 127 case AlsaPcmOutputStream::kIsClosed: |
126 os << "kIsClosed"; | 128 os << "kIsClosed"; |
127 break; | 129 break; |
128 }; | 130 } |
129 return os; | 131 return os; |
130 } | 132 } |
131 | 133 |
132 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; | 134 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; |
133 const char AlsaPcmOutputStream::kAutoSelectDevice[] = ""; | 135 const char AlsaPcmOutputStream::kAutoSelectDevice[] = ""; |
134 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:"; | 136 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:"; |
135 | 137 |
136 // We use 40ms as our minimum required latency. If it is needed, we may be able | 138 // We use 40ms as our minimum required latency. If it is needed, we may be able |
137 // to get it down to 20ms. | 139 // to get it down to 20ms. |
138 const uint32_t AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; | 140 const uint32_t AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; |
(...skipping 18 matching lines...) Expand all Loading... |
157 stop_stream_(false), | 159 stop_stream_(false), |
158 wrapper_(wrapper), | 160 wrapper_(wrapper), |
159 manager_(manager), | 161 manager_(manager), |
160 task_runner_(base::ThreadTaskRunnerHandle::Get()), | 162 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
161 playback_handle_(NULL), | 163 playback_handle_(NULL), |
162 frames_per_packet_(packet_size_ / bytes_per_frame_), | 164 frames_per_packet_(packet_size_ / bytes_per_frame_), |
163 state_(kCreated), | 165 state_(kCreated), |
164 volume_(1.0f), | 166 volume_(1.0f), |
165 source_callback_(NULL), | 167 source_callback_(NULL), |
166 audio_bus_(AudioBus::Create(params)), | 168 audio_bus_(AudioBus::Create(params)), |
| 169 tick_clock_(new base::DefaultTickClock()), |
167 weak_factory_(this) { | 170 weak_factory_(this) { |
168 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 171 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); |
169 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); | 172 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); |
170 | 173 |
171 // Sanity check input values. | 174 // Sanity check input values. |
172 if (!params.IsValid()) { | 175 if (!params.IsValid()) { |
173 LOG(WARNING) << "Unsupported audio parameters."; | 176 LOG(WARNING) << "Unsupported audio parameters."; |
174 TransitionTo(kInError); | 177 TransitionTo(kInError); |
175 } | 178 } |
176 | 179 |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 | 341 |
339 volume_ = static_cast<float>(volume); | 342 volume_ = static_cast<float>(volume); |
340 } | 343 } |
341 | 344 |
342 void AlsaPcmOutputStream::GetVolume(double* volume) { | 345 void AlsaPcmOutputStream::GetVolume(double* volume) { |
343 DCHECK(CalledOnValidThread()); | 346 DCHECK(CalledOnValidThread()); |
344 | 347 |
345 *volume = volume_; | 348 *volume = volume_; |
346 } | 349 } |
347 | 350 |
| 351 void AlsaPcmOutputStream::SetTickClockForTesting( |
| 352 std::unique_ptr<base::TickClock> tick_clock) { |
| 353 DCHECK(tick_clock); |
| 354 tick_clock_ = std::move(tick_clock); |
| 355 } |
| 356 |
348 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { | 357 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { |
349 DCHECK(CalledOnValidThread()); | 358 DCHECK(CalledOnValidThread()); |
350 | 359 |
351 // If stopped, simulate a 0-length packet. | 360 // If stopped, simulate a 0-length packet. |
352 if (stop_stream_) { | 361 if (stop_stream_) { |
353 buffer_->Clear(); | 362 buffer_->Clear(); |
354 *source_exhausted = true; | 363 *source_exhausted = true; |
355 return; | 364 return; |
356 } | 365 } |
357 | 366 |
358 *source_exhausted = false; | 367 *source_exhausted = false; |
359 | 368 |
360 // Request more data only when we run out of data in the buffer, because | 369 // Request more data only when we run out of data in the buffer, because |
361 // WritePacket() consumes only the current chunk of data. | 370 // WritePacket() consumes only the current chunk of data. |
362 if (!buffer_->forward_bytes()) { | 371 if (!buffer_->forward_bytes()) { |
363 // Before making a request to source for data we need to determine the | 372 // Before making a request to source for data we need to determine the |
364 // delay (in bytes) for the requested data to be played. | 373 // time when the requested data will be played. |
365 const uint32_t hardware_delay = GetCurrentDelay() * bytes_per_frame_; | 374 const base::TimeTicks target_playout_time = |
| 375 tick_clock_->NowTicks() + |
| 376 FramesToTimeDelta(GetCurrentDelay(), sample_rate_); |
366 | 377 |
367 scoped_refptr<media::DataBuffer> packet = | 378 scoped_refptr<media::DataBuffer> packet = |
368 new media::DataBuffer(packet_size_); | 379 new media::DataBuffer(packet_size_); |
369 int frames_filled = RunDataCallback( | 380 int frames_filled = RunDataCallback(target_playout_time, audio_bus_.get()); |
370 audio_bus_.get(), hardware_delay); | |
371 | 381 |
372 size_t packet_size = frames_filled * bytes_per_frame_; | 382 size_t packet_size = frames_filled * bytes_per_frame_; |
373 DCHECK_LE(packet_size, packet_size_); | 383 DCHECK_LE(packet_size, packet_size_); |
374 | 384 |
375 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; | 385 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; |
376 // volume adjust should use SSE optimized vector_fmul() prior to interleave. | 386 // volume adjust should use SSE optimized vector_fmul() prior to interleave. |
377 AudioBus* output_bus = audio_bus_.get(); | 387 AudioBus* output_bus = audio_bus_.get(); |
378 ChannelLayout output_channel_layout = channel_layout_; | 388 ChannelLayout output_channel_layout = channel_layout_; |
379 if (channel_mixer_) { | 389 if (channel_mixer_) { |
380 output_bus = mixed_audio_bus_.get(); | 390 output_bus = mixed_audio_bus_.get(); |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 } else { | 780 } else { |
771 state_ = to; | 781 state_ = to; |
772 } | 782 } |
773 return state_; | 783 return state_; |
774 } | 784 } |
775 | 785 |
776 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { | 786 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { |
777 return state_; | 787 return state_; |
778 } | 788 } |
779 | 789 |
780 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, | 790 int AlsaPcmOutputStream::RunDataCallback(base::TimeTicks target_playout_time, |
781 uint32_t total_bytes_delay) { | 791 AudioBus* audio_bus) { |
782 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); | 792 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); |
783 | 793 |
784 if (source_callback_) | 794 if (source_callback_) |
785 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0); | 795 return source_callback_->OnMoreData(target_playout_time, 0, audio_bus); |
786 | 796 |
787 return 0; | 797 return 0; |
788 } | 798 } |
789 | 799 |
790 void AlsaPcmOutputStream::RunErrorCallback(int code) { | 800 void AlsaPcmOutputStream::RunErrorCallback(int code) { |
791 if (source_callback_) | 801 if (source_callback_) |
792 source_callback_->OnError(this); | 802 source_callback_->OnError(this); |
793 } | 803 } |
794 | 804 |
795 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 805 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
796 // release ownership of the currently registered callback. | 806 // release ownership of the currently registered callback. |
797 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { | 807 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { |
798 DCHECK(CalledOnValidThread()); | 808 DCHECK(CalledOnValidThread()); |
799 source_callback_ = callback; | 809 source_callback_ = callback; |
800 } | 810 } |
801 | 811 |
802 } // namespace media | 812 } // namespace media |
OLD | NEW |