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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 break; | 118 break; |
119 case AlsaPcmOutputStream::kIsPlaying: | 119 case AlsaPcmOutputStream::kIsPlaying: |
120 os << "kIsPlaying"; | 120 os << "kIsPlaying"; |
121 break; | 121 break; |
122 case AlsaPcmOutputStream::kIsStopped: | 122 case AlsaPcmOutputStream::kIsStopped: |
123 os << "kIsStopped"; | 123 os << "kIsStopped"; |
124 break; | 124 break; |
125 case AlsaPcmOutputStream::kIsClosed: | 125 case AlsaPcmOutputStream::kIsClosed: |
126 os << "kIsClosed"; | 126 os << "kIsClosed"; |
127 break; | 127 break; |
128 }; | 128 } |
129 return os; | 129 return os; |
130 } | 130 } |
131 | 131 |
132 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; | 132 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; |
133 const char AlsaPcmOutputStream::kAutoSelectDevice[] = ""; | 133 const char AlsaPcmOutputStream::kAutoSelectDevice[] = ""; |
134 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:"; | 134 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:"; |
135 | 135 |
136 // We use 40ms as our minimum required latency. If it is needed, we may be able | 136 // We use 40ms as our minimum required latency. If it is needed, we may be able |
137 // to get it down to 20ms. | 137 // to get it down to 20ms. |
138 const uint32_t AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; | 138 const uint32_t AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 *source_exhausted = true; | 354 *source_exhausted = true; |
355 return; | 355 return; |
356 } | 356 } |
357 | 357 |
358 *source_exhausted = false; | 358 *source_exhausted = false; |
359 | 359 |
360 // Request more data only when we run out of data in the buffer, because | 360 // Request more data only when we run out of data in the buffer, because |
361 // WritePacket() consumes only the current chunk of data. | 361 // WritePacket() consumes only the current chunk of data. |
362 if (!buffer_->forward_bytes()) { | 362 if (!buffer_->forward_bytes()) { |
363 // Before making a request to source for data we need to determine the | 363 // Before making a request to source for data we need to determine the |
364 // delay (in bytes) for the requested data to be played. | 364 // time when the requested data will be played. |
365 const uint32_t hardware_delay = GetCurrentDelay() * bytes_per_frame_; | 365 const base::TimeTicks target_playout_time = |
| 366 base::TimeTicks::Now() + |
| 367 FramesToTimeDelta(GetCurrentDelay(), sample_rate_); |
366 | 368 |
367 scoped_refptr<media::DataBuffer> packet = | 369 scoped_refptr<media::DataBuffer> packet = |
368 new media::DataBuffer(packet_size_); | 370 new media::DataBuffer(packet_size_); |
369 int frames_filled = RunDataCallback( | 371 int frames_filled = RunDataCallback(target_playout_time, audio_bus_.get()); |
370 audio_bus_.get(), hardware_delay); | |
371 | 372 |
372 size_t packet_size = frames_filled * bytes_per_frame_; | 373 size_t packet_size = frames_filled * bytes_per_frame_; |
373 DCHECK_LE(packet_size, packet_size_); | 374 DCHECK_LE(packet_size, packet_size_); |
374 | 375 |
375 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; | 376 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; |
376 // volume adjust should use SSE optimized vector_fmul() prior to interleave. | 377 // volume adjust should use SSE optimized vector_fmul() prior to interleave. |
377 AudioBus* output_bus = audio_bus_.get(); | 378 AudioBus* output_bus = audio_bus_.get(); |
378 ChannelLayout output_channel_layout = channel_layout_; | 379 ChannelLayout output_channel_layout = channel_layout_; |
379 if (channel_mixer_) { | 380 if (channel_mixer_) { |
380 output_bus = mixed_audio_bus_.get(); | 381 output_bus = mixed_audio_bus_.get(); |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 } else { | 771 } else { |
771 state_ = to; | 772 state_ = to; |
772 } | 773 } |
773 return state_; | 774 return state_; |
774 } | 775 } |
775 | 776 |
776 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { | 777 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { |
777 return state_; | 778 return state_; |
778 } | 779 } |
779 | 780 |
780 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, | 781 int AlsaPcmOutputStream::RunDataCallback(base::TimeTicks target_playout_time, |
781 uint32_t total_bytes_delay) { | 782 AudioBus* audio_bus) { |
782 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); | 783 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); |
783 | 784 |
784 if (source_callback_) | 785 if (source_callback_) |
785 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0); | 786 return source_callback_->OnMoreData(target_playout_time, 0, audio_bus); |
786 | 787 |
787 return 0; | 788 return 0; |
788 } | 789 } |
789 | 790 |
790 void AlsaPcmOutputStream::RunErrorCallback(int code) { | 791 void AlsaPcmOutputStream::RunErrorCallback(int code) { |
791 if (source_callback_) | 792 if (source_callback_) |
792 source_callback_->OnError(this); | 793 source_callback_->OnError(this); |
793 } | 794 } |
794 | 795 |
795 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 796 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
796 // release ownership of the currently registered callback. | 797 // release ownership of the currently registered callback. |
797 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { | 798 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { |
798 DCHECK(CalledOnValidThread()); | 799 DCHECK(CalledOnValidThread()); |
799 source_callback_ = callback; | 800 source_callback_ = callback; |
800 } | 801 } |
801 | 802 |
802 } // namespace media | 803 } // namespace media |
OLD | NEW |