| 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 |