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 // Get buffer size for the pipe. |
141 if (HANDLE_EINTR(fcntl( | 131 pipe_buffer_size_ = fpathconf(pipe_.GetPlatformFile(), _PC_PIPE_BUF); |
142 pipe_.GetPlatformFile(), F_SETPIPE_SZ, kPipeBufferSizeBytes)) < 0) { | 132 if (pipe_buffer_size_ < 0) { |
143 PLOG(ERROR) << "fcntl"; | 133 PLOG(ERROR) << "fpathconf(_PC_PIPE_BUF)"; |
| 134 pipe_buffer_size_ = 4096; |
144 } | 135 } |
145 | 136 |
| 137 // Read from the pipe twice per buffer length, to avoid starving the stream. |
| 138 capture_period_ = base::TimeDelta::FromSeconds(1) * pipe_buffer_size_ / |
| 139 kSampleBytesPerSecond / 2; |
| 140 |
146 WaitForPipeReadable(); | 141 WaitForPipeReadable(); |
147 } | 142 } |
148 } | 143 } |
149 | 144 |
150 void AudioPipeReader::StartTimer() { | 145 void AudioPipeReader::StartTimer() { |
151 DCHECK(task_runner_->BelongsToCurrentThread()); | 146 DCHECK(task_runner_->BelongsToCurrentThread()); |
152 started_time_ = base::TimeTicks::Now(); | 147 started_time_ = base::TimeTicks::Now(); |
153 last_capture_position_ = 0; | 148 last_capture_position_ = 0; |
154 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kCapturingPeriodMs), | 149 timer_.Start(FROM_HERE, capture_period_, this, &AudioPipeReader::DoCapture); |
155 this, &AudioPipeReader::DoCapture); | |
156 } | 150 } |
157 | 151 |
158 void AudioPipeReader::DoCapture() { | 152 void AudioPipeReader::DoCapture() { |
159 DCHECK(task_runner_->BelongsToCurrentThread()); | 153 DCHECK(task_runner_->BelongsToCurrentThread()); |
160 DCHECK(pipe_.IsValid()); | 154 DCHECK(pipe_.IsValid()); |
161 | 155 |
162 // Calculate how much we need read from the pipe. Pulseaudio doesn't control | 156 // 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. | 157 // 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_; | 158 base::TimeDelta stream_position = base::TimeTicks::Now() - started_time_; |
165 int64 stream_position_bytes = stream_position.InMilliseconds() * | 159 int64 stream_position_bytes = stream_position.InMilliseconds() * |
(...skipping 28 matching lines...) Expand all Loading... |
194 int incomplete_samples_bytes = pos % (kChannels * kBytesPerSample); | 188 int incomplete_samples_bytes = pos % (kChannels * kBytesPerSample); |
195 left_over_bytes_.assign(data, pos - incomplete_samples_bytes, | 189 left_over_bytes_.assign(data, pos - incomplete_samples_bytes, |
196 incomplete_samples_bytes); | 190 incomplete_samples_bytes); |
197 data.resize(pos - incomplete_samples_bytes); | 191 data.resize(pos - incomplete_samples_bytes); |
198 | 192 |
199 last_capture_position_ += data.size(); | 193 last_capture_position_ += data.size(); |
200 // Normally PulseAudio will keep pipe buffer full, so we should always be able | 194 // 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 | 195 // 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 | 196 // sure that |stream_position_bytes| doesn't go out of sync with the current |
203 // stream position. | 197 // stream position. |
204 if (stream_position_bytes - last_capture_position_ > kPipeBufferSizeBytes) | 198 if (stream_position_bytes - last_capture_position_ > pipe_buffer_size_) |
205 last_capture_position_ = stream_position_bytes - kPipeBufferSizeBytes; | 199 last_capture_position_ = stream_position_bytes - pipe_buffer_size_; |
206 DCHECK_LE(last_capture_position_, stream_position_bytes); | 200 DCHECK_LE(last_capture_position_, stream_position_bytes); |
207 | 201 |
208 // Dispatch asynchronous notification to the stream observers. | 202 // Dispatch asynchronous notification to the stream observers. |
209 scoped_refptr<base::RefCountedString> data_ref = | 203 scoped_refptr<base::RefCountedString> data_ref = |
210 base::RefCountedString::TakeString(&data); | 204 base::RefCountedString::TakeString(&data); |
211 observers_->Notify(&StreamObserver::OnDataRead, data_ref); | 205 observers_->Notify(&StreamObserver::OnDataRead, data_ref); |
212 } | 206 } |
213 | 207 |
214 void AudioPipeReader::WaitForPipeReadable() { | 208 void AudioPipeReader::WaitForPipeReadable() { |
215 timer_.Stop(); | 209 timer_.Stop(); |
216 base::MessageLoopForIO::current()->WatchFileDescriptor( | 210 base::MessageLoopForIO::current()->WatchFileDescriptor( |
217 pipe_.GetPlatformFile(), false, base::MessageLoopForIO::WATCH_READ, | 211 pipe_.GetPlatformFile(), false, base::MessageLoopForIO::WATCH_READ, |
218 &file_descriptor_watcher_, this); | 212 &file_descriptor_watcher_, this); |
219 } | 213 } |
220 | 214 |
221 // static | 215 // static |
222 void AudioPipeReaderTraits::Destruct(const AudioPipeReader* audio_pipe_reader) { | 216 void AudioPipeReaderTraits::Destruct(const AudioPipeReader* audio_pipe_reader) { |
223 audio_pipe_reader->task_runner_->DeleteSoon(FROM_HERE, audio_pipe_reader); | 217 audio_pipe_reader->task_runner_->DeleteSoon(FROM_HERE, audio_pipe_reader); |
224 } | 218 } |
225 | 219 |
226 } // namespace remoting | 220 } // namespace remoting |
OLD | NEW |