Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "remoting/host/linux/audio_pipe_reader.h" | 5 #include "remoting/host/linux/audio_pipe_reader.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/posix/eintr_wrapper.h" | 13 #include "base/posix/eintr_wrapper.h" |
| 14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 15 | 15 |
| 16 namespace remoting { | 16 namespace remoting { |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 const int kSampleBytesPerSecond = AudioPipeReader::kSamplingRate * | 20 const int kSampleBytesPerSecond = AudioPipeReader::kSamplingRate * |
| 21 AudioPipeReader::kChannels * | 21 AudioPipeReader::kChannels * |
| 22 AudioPipeReader::kBytesPerSample; | 22 AudioPipeReader::kBytesPerSample; |
| 23 | 23 |
| 24 // Read data from the pipe every 40ms. | |
| 25 const int kCapturingPeriodMs = 40; | |
| 26 | |
| 27 // Size of the pipe buffer in milliseconds. | |
| 28 const int kPipeBufferSizeMs = kCapturingPeriodMs * 2; | |
| 29 | |
| 30 // Size of the pipe buffer in bytes. | |
| 31 const int kPipeBufferSizeBytes = kPipeBufferSizeMs * kSampleBytesPerSecond / | |
| 32 base::Time::kMillisecondsPerSecond; | |
| 33 | |
| 34 #if !defined(F_SETPIPE_SZ) | 24 #if !defined(F_SETPIPE_SZ) |
| 35 // F_SETPIPE_SZ is supported only starting linux 2.6.35, but we want to be able | 25 // F_SETPIPE_SZ is supported only starting linux 2.6.35, but we want to be able |
| 36 // to compile this code on machines with older kernel. | 26 // to compile this code on machines with older kernel. |
| 37 #define F_SETPIPE_SZ 1031 | 27 #define F_SETPIPE_SZ 1031 |
| 38 #endif // defined(F_SETPIPE_SZ) | 28 #endif // defined(F_SETPIPE_SZ) |
| 39 | 29 |
| 40 } // namespace | 30 } // namespace |
| 41 | 31 |
| 42 // static | 32 // static |
| 43 scoped_refptr<AudioPipeReader> AudioPipeReader::Create( | 33 scoped_refptr<AudioPipeReader> AudioPipeReader::Create( |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 pipe_ = new_pipe.Pass(); | 120 pipe_ = new_pipe.Pass(); |
| 131 | 121 |
| 132 if (pipe_.IsValid()) { | 122 if (pipe_.IsValid()) { |
| 133 // Set O_NONBLOCK flag. | 123 // Set O_NONBLOCK flag. |
| 134 if (HANDLE_EINTR(fcntl(pipe_.GetPlatformFile(), F_SETFL, O_NONBLOCK)) < 0) { | 124 if (HANDLE_EINTR(fcntl(pipe_.GetPlatformFile(), F_SETFL, O_NONBLOCK)) < 0) { |
| 135 PLOG(ERROR) << "fcntl"; | 125 PLOG(ERROR) << "fcntl"; |
| 136 pipe_.Close(); | 126 pipe_.Close(); |
| 137 return; | 127 return; |
| 138 } | 128 } |
| 139 | 129 |
| 140 // Set buffer size for the pipe. | 130 pipe_buffer_size_ = fpathconf(pipe_.GetPlatformFile(), _PC_PIPE_BUF); |
|
Lambros
2014/12/23 23:07:18
I don't think this call can fail, can it?
Sergey Ulanov
2014/12/24 00:01:28
it shouldn't, but it's still better to check if it
| |
| 141 if (HANDLE_EINTR(fcntl( | 131 capture_period_ = base::TimeDelta::FromSeconds(1) * pipe_buffer_size_ / |
| 142 pipe_.GetPlatformFile(), F_SETPIPE_SZ, kPipeBufferSizeBytes)) < 0) { | 132 kSampleBytesPerSecond / 2; |
|
Lambros
2014/12/23 23:07:18
I'm curious to know why we divide by 2? Is it simp
Sergey Ulanov
2014/12/24 00:01:26
Yes. We need to capture more often than the buffer
| |
| 143 PLOG(ERROR) << "fcntl"; | |
| 144 } | |
| 145 | 133 |
| 146 WaitForPipeReadable(); | 134 WaitForPipeReadable(); |
| 147 } | 135 } |
| 148 } | 136 } |
| 149 | 137 |
| 150 void AudioPipeReader::StartTimer() { | 138 void AudioPipeReader::StartTimer() { |
| 151 DCHECK(task_runner_->BelongsToCurrentThread()); | 139 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 152 started_time_ = base::TimeTicks::Now(); | 140 started_time_ = base::TimeTicks::Now(); |
| 153 last_capture_position_ = 0; | 141 last_capture_position_ = 0; |
| 154 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kCapturingPeriodMs), | 142 timer_.Start(FROM_HERE, capture_period_, this, &AudioPipeReader::DoCapture); |
| 155 this, &AudioPipeReader::DoCapture); | |
| 156 } | 143 } |
| 157 | 144 |
| 158 void AudioPipeReader::DoCapture() { | 145 void AudioPipeReader::DoCapture() { |
| 159 DCHECK(task_runner_->BelongsToCurrentThread()); | 146 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 160 DCHECK(pipe_.IsValid()); | 147 DCHECK(pipe_.IsValid()); |
| 161 | 148 |
| 162 // Calculate how much we need read from the pipe. Pulseaudio doesn't control | 149 // Calculate how much we need read from the pipe. Pulseaudio doesn't control |
| 163 // how much data it writes to the pipe, so we need to pace the stream. | 150 // how much data it writes to the pipe, so we need to pace the stream. |
| 164 base::TimeDelta stream_position = base::TimeTicks::Now() - started_time_; | 151 base::TimeDelta stream_position = base::TimeTicks::Now() - started_time_; |
| 165 int64 stream_position_bytes = stream_position.InMilliseconds() * | 152 int64 stream_position_bytes = stream_position.InMilliseconds() * |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 194 int incomplete_samples_bytes = pos % (kChannels * kBytesPerSample); | 181 int incomplete_samples_bytes = pos % (kChannels * kBytesPerSample); |
| 195 left_over_bytes_.assign(data, pos - incomplete_samples_bytes, | 182 left_over_bytes_.assign(data, pos - incomplete_samples_bytes, |
| 196 incomplete_samples_bytes); | 183 incomplete_samples_bytes); |
| 197 data.resize(pos - incomplete_samples_bytes); | 184 data.resize(pos - incomplete_samples_bytes); |
| 198 | 185 |
| 199 last_capture_position_ += data.size(); | 186 last_capture_position_ += data.size(); |
| 200 // Normally PulseAudio will keep pipe buffer full, so we should always be able | 187 // Normally PulseAudio will keep pipe buffer full, so we should always be able |
| 201 // to read |bytes_to_read| bytes, but in case it's misbehaving we need to make | 188 // to read |bytes_to_read| bytes, but in case it's misbehaving we need to make |
| 202 // sure that |stream_position_bytes| doesn't go out of sync with the current | 189 // sure that |stream_position_bytes| doesn't go out of sync with the current |
| 203 // stream position. | 190 // stream position. |
| 204 if (stream_position_bytes - last_capture_position_ > kPipeBufferSizeBytes) | 191 if (stream_position_bytes - last_capture_position_ > pipe_buffer_size_) |
| 205 last_capture_position_ = stream_position_bytes - kPipeBufferSizeBytes; | 192 last_capture_position_ = stream_position_bytes - pipe_buffer_size_; |
| 206 DCHECK_LE(last_capture_position_, stream_position_bytes); | 193 DCHECK_LE(last_capture_position_, stream_position_bytes); |
| 207 | 194 |
| 208 // Dispatch asynchronous notification to the stream observers. | 195 // Dispatch asynchronous notification to the stream observers. |
| 209 scoped_refptr<base::RefCountedString> data_ref = | 196 scoped_refptr<base::RefCountedString> data_ref = |
| 210 base::RefCountedString::TakeString(&data); | 197 base::RefCountedString::TakeString(&data); |
| 211 observers_->Notify(&StreamObserver::OnDataRead, data_ref); | 198 observers_->Notify(&StreamObserver::OnDataRead, data_ref); |
| 212 } | 199 } |
| 213 | 200 |
| 214 void AudioPipeReader::WaitForPipeReadable() { | 201 void AudioPipeReader::WaitForPipeReadable() { |
| 215 timer_.Stop(); | 202 timer_.Stop(); |
| 216 base::MessageLoopForIO::current()->WatchFileDescriptor( | 203 base::MessageLoopForIO::current()->WatchFileDescriptor( |
| 217 pipe_.GetPlatformFile(), false, base::MessageLoopForIO::WATCH_READ, | 204 pipe_.GetPlatformFile(), false, base::MessageLoopForIO::WATCH_READ, |
| 218 &file_descriptor_watcher_, this); | 205 &file_descriptor_watcher_, this); |
| 219 } | 206 } |
| 220 | 207 |
| 221 // static | 208 // static |
| 222 void AudioPipeReaderTraits::Destruct(const AudioPipeReader* audio_pipe_reader) { | 209 void AudioPipeReaderTraits::Destruct(const AudioPipeReader* audio_pipe_reader) { |
| 223 audio_pipe_reader->task_runner_->DeleteSoon(FROM_HERE, audio_pipe_reader); | 210 audio_pipe_reader->task_runner_->DeleteSoon(FROM_HERE, audio_pipe_reader); |
| 224 } | 211 } |
| 225 | 212 |
| 226 } // namespace remoting | 213 } // namespace remoting |
| OLD | NEW |