Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: media/audio/linux/alsa_input.cc

Issue 9655018: Make AudioParameters a class instead of a struct (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix copyright years Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/linux/alsa_input.h ('k') | media/audio/linux/alsa_output.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "media/audio/linux/alsa_input.h" 5 #include "media/audio/linux/alsa_input.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 11 matching lines...) Expand all
22 22
23 const char* AlsaPcmInputStream::kAutoSelectDevice = ""; 23 const char* AlsaPcmInputStream::kAutoSelectDevice = "";
24 24
25 AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerLinux* audio_manager, 25 AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerLinux* audio_manager,
26 const std::string& device_name, 26 const std::string& device_name,
27 const AudioParameters& params, 27 const AudioParameters& params,
28 AlsaWrapper* wrapper) 28 AlsaWrapper* wrapper)
29 : audio_manager_(audio_manager), 29 : audio_manager_(audio_manager),
30 device_name_(device_name), 30 device_name_(device_name),
31 params_(params), 31 params_(params),
32 bytes_per_packet_(params.samples_per_packet * 32 bytes_per_buffer_(params.frames_per_buffer() *
33 (params.channels * params.bits_per_sample) / 8), 33 (params.channels() * params.bits_per_sample()) / 8),
34 wrapper_(wrapper), 34 wrapper_(wrapper),
35 packet_duration_ms_( 35 buffer_duration_ms_(
36 (params.samples_per_packet * base::Time::kMillisecondsPerSecond) / 36 (params.frames_per_buffer() * base::Time::kMillisecondsPerSecond) /
37 params.sample_rate), 37 params.sample_rate()),
38 callback_(NULL), 38 callback_(NULL),
39 device_handle_(NULL), 39 device_handle_(NULL),
40 mixer_handle_(NULL), 40 mixer_handle_(NULL),
41 mixer_element_handle_(NULL), 41 mixer_element_handle_(NULL),
42 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 42 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
43 read_callback_behind_schedule_(false) { 43 read_callback_behind_schedule_(false) {
44 } 44 }
45 45
46 AlsaPcmInputStream::~AlsaPcmInputStream() {} 46 AlsaPcmInputStream::~AlsaPcmInputStream() {}
47 47
48 bool AlsaPcmInputStream::Open() { 48 bool AlsaPcmInputStream::Open() {
49 if (device_handle_) 49 if (device_handle_)
50 return false; // Already open. 50 return false; // Already open.
51 51
52 snd_pcm_format_t pcm_format = alsa_util::BitsToFormat( 52 snd_pcm_format_t pcm_format = alsa_util::BitsToFormat(
53 params_.bits_per_sample); 53 params_.bits_per_sample());
54 if (pcm_format == SND_PCM_FORMAT_UNKNOWN) { 54 if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
55 LOG(WARNING) << "Unsupported bits per sample: " 55 LOG(WARNING) << "Unsupported bits per sample: "
56 << params_.bits_per_sample; 56 << params_.bits_per_sample();
57 return false; 57 return false;
58 } 58 }
59 59
60 uint32 latency_us = packet_duration_ms_ * kNumPacketsInRingBuffer * 60 uint32 latency_us = buffer_duration_ms_ * kNumPacketsInRingBuffer *
61 base::Time::kMicrosecondsPerMillisecond; 61 base::Time::kMicrosecondsPerMillisecond;
62 62
63 // Use the same minimum required latency as output. 63 // Use the same minimum required latency as output.
64 latency_us = std::max(latency_us, AlsaPcmOutputStream::kMinLatencyMicros); 64 latency_us = std::max(latency_us, AlsaPcmOutputStream::kMinLatencyMicros);
65 65
66 if (device_name_ == kAutoSelectDevice) { 66 if (device_name_ == kAutoSelectDevice) {
67 const char* device_names[] = { kDefaultDevice1, kDefaultDevice2 }; 67 const char* device_names[] = { kDefaultDevice1, kDefaultDevice2 };
68 for (size_t i = 0; i < arraysize(device_names); ++i) { 68 for (size_t i = 0; i < arraysize(device_names); ++i) {
69 device_handle_ = alsa_util::OpenCaptureDevice(wrapper_, device_names[i], 69 device_handle_ = alsa_util::OpenCaptureDevice(
70 params_.channels, 70 wrapper_, device_names[i], params_.channels(),
71 params_.sample_rate, 71 params_.sample_rate(), pcm_format, latency_us);
72 pcm_format, latency_us); 72
73 if (device_handle_) { 73 if (device_handle_) {
74 device_name_ = device_names[i]; 74 device_name_ = device_names[i];
75 break; 75 break;
76 } 76 }
77 } 77 }
78 } else { 78 } else {
79 device_handle_ = alsa_util::OpenCaptureDevice(wrapper_, 79 device_handle_ = alsa_util::OpenCaptureDevice(wrapper_,
80 device_name_.c_str(), 80 device_name_.c_str(),
81 params_.channels, 81 params_.channels(),
82 params_.sample_rate, 82 params_.sample_rate(),
83 pcm_format, latency_us); 83 pcm_format, latency_us);
84 } 84 }
85 85
86 if (device_handle_) { 86 if (device_handle_) {
87 audio_packet_.reset(new uint8[bytes_per_packet_]); 87 audio_buffer_.reset(new uint8[bytes_per_buffer_]);
88 88
89 // Open the microphone mixer. 89 // Open the microphone mixer.
90 mixer_handle_ = alsa_util::OpenMixer(wrapper_, device_name_); 90 mixer_handle_ = alsa_util::OpenMixer(wrapper_, device_name_);
91 if (mixer_handle_) { 91 if (mixer_handle_) {
92 mixer_element_handle_ = alsa_util::LoadCaptureMixerElement( 92 mixer_element_handle_ = alsa_util::LoadCaptureMixerElement(
93 wrapper_, mixer_handle_); 93 wrapper_, mixer_handle_);
94 } 94 }
95 } 95 }
96 96
97 return device_handle_ != NULL; 97 return device_handle_ != NULL;
98 } 98 }
99 99
100 void AlsaPcmInputStream::Start(AudioInputCallback* callback) { 100 void AlsaPcmInputStream::Start(AudioInputCallback* callback) {
101 DCHECK(!callback_ && callback); 101 DCHECK(!callback_ && callback);
102 callback_ = callback; 102 callback_ = callback;
103 int error = wrapper_->PcmPrepare(device_handle_); 103 int error = wrapper_->PcmPrepare(device_handle_);
104 if (error < 0) { 104 if (error < 0) {
105 HandleError("PcmPrepare", error); 105 HandleError("PcmPrepare", error);
106 } else { 106 } else {
107 error = wrapper_->PcmStart(device_handle_); 107 error = wrapper_->PcmStart(device_handle_);
108 if (error < 0) 108 if (error < 0)
109 HandleError("PcmStart", error); 109 HandleError("PcmStart", error);
110 } 110 }
111 111
112 if (error < 0) { 112 if (error < 0) {
113 callback_ = NULL; 113 callback_ = NULL;
114 } else { 114 } else {
115 // We start reading data half |packet_duration_ms_| later than when the 115 // We start reading data half |buffer_duration_ms_| later than when the
116 // packet might have got filled, to accommodate some delays in the audio 116 // buffer might have got filled, to accommodate some delays in the audio
117 // driver. This could also give us a smooth read sequence going forward. 117 // driver. This could also give us a smooth read sequence going forward.
118 base::TimeDelta delay = base::TimeDelta::FromMilliseconds( 118 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(
119 packet_duration_ms_ + packet_duration_ms_ / 2); 119 buffer_duration_ms_ + buffer_duration_ms_ / 2);
120 next_read_time_ = base::Time::Now() + delay; 120 next_read_time_ = base::Time::Now() + delay;
121 MessageLoop::current()->PostDelayedTask( 121 MessageLoop::current()->PostDelayedTask(
122 FROM_HERE, 122 FROM_HERE,
123 base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()), 123 base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()),
124 delay); 124 delay);
125 125
126 audio_manager_->IncreaseActiveInputStreamCount(); 126 audio_manager_->IncreaseActiveInputStreamCount();
127 } 127 }
128 } 128 }
129 129
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 169
170 void AlsaPcmInputStream::ReadAudio() { 170 void AlsaPcmInputStream::ReadAudio() {
171 DCHECK(callback_); 171 DCHECK(callback_);
172 172
173 snd_pcm_sframes_t frames = wrapper_->PcmAvailUpdate(device_handle_); 173 snd_pcm_sframes_t frames = wrapper_->PcmAvailUpdate(device_handle_);
174 if (frames < 0) { // Potentially recoverable error? 174 if (frames < 0) { // Potentially recoverable error?
175 LOG(WARNING) << "PcmAvailUpdate(): " << wrapper_->StrError(frames); 175 LOG(WARNING) << "PcmAvailUpdate(): " << wrapper_->StrError(frames);
176 Recover(frames); 176 Recover(frames);
177 } 177 }
178 178
179 if (frames < params_.samples_per_packet) { 179 if (frames < params_.frames_per_buffer()) {
180 // Not enough data yet or error happened. In both cases wait for a very 180 // Not enough data yet or error happened. In both cases wait for a very
181 // small duration before checking again. 181 // small duration before checking again.
182 // Even Though read callback was behind schedule, there is no data, so 182 // Even Though read callback was behind schedule, there is no data, so
183 // reset the next_read_time_. 183 // reset the next_read_time_.
184 if (read_callback_behind_schedule_) { 184 if (read_callback_behind_schedule_) {
185 next_read_time_ = base::Time::Now(); 185 next_read_time_ = base::Time::Now();
186 read_callback_behind_schedule_ = false; 186 read_callback_behind_schedule_ = false;
187 } 187 }
188 188
189 base::TimeDelta next_check_time = base::TimeDelta::FromMilliseconds( 189 base::TimeDelta next_check_time = base::TimeDelta::FromMilliseconds(
190 packet_duration_ms_ / 2); 190 buffer_duration_ms_ / 2);
191 MessageLoop::current()->PostDelayedTask( 191 MessageLoop::current()->PostDelayedTask(
192 FROM_HERE, 192 FROM_HERE,
193 base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()), 193 base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()),
194 next_check_time); 194 next_check_time);
195 return; 195 return;
196 } 196 }
197 197
198 int num_packets = frames / params_.samples_per_packet; 198 int num_buffers = frames / params_.frames_per_buffer();
199 int num_packets_read = num_packets; 199 int num_buffers_read = num_buffers;
200 int bytes_per_frame = params_.channels * params_.bits_per_sample / 8;
201 uint32 hardware_delay_bytes = 200 uint32 hardware_delay_bytes =
202 static_cast<uint32>(GetCurrentDelay() * bytes_per_frame); 201 static_cast<uint32>(GetCurrentDelay() * params_.GetBytesPerFrame());
203 while (num_packets--) { 202 while (num_buffers--) {
204 int frames_read = wrapper_->PcmReadi(device_handle_, audio_packet_.get(), 203 int frames_read = wrapper_->PcmReadi(device_handle_, audio_buffer_.get(),
205 params_.samples_per_packet); 204 params_.frames_per_buffer());
206 if (frames_read == params_.samples_per_packet) { 205 if (frames_read == params_.frames_per_buffer()) {
207 callback_->OnData(this, audio_packet_.get(), bytes_per_packet_, 206 callback_->OnData(this, audio_buffer_.get(), bytes_per_buffer_,
208 hardware_delay_bytes); 207 hardware_delay_bytes);
209 } else { 208 } else {
210 LOG(WARNING) << "PcmReadi returning less than expected frames: " 209 LOG(WARNING) << "PcmReadi returning less than expected frames: "
211 << frames_read << " vs. " << params_.samples_per_packet 210 << frames_read << " vs. " << params_.frames_per_buffer()
212 << ". Dropping this packet."; 211 << ". Dropping this buffer.";
213 } 212 }
214 } 213 }
215 214
216 next_read_time_ += base::TimeDelta::FromMilliseconds( 215 next_read_time_ += base::TimeDelta::FromMilliseconds(
217 packet_duration_ms_ * num_packets_read); 216 buffer_duration_ms_ * num_buffers_read);
218 base::TimeDelta delay = next_read_time_ - base::Time::Now(); 217 base::TimeDelta delay = next_read_time_ - base::Time::Now();
219 if (delay < base::TimeDelta()) { 218 if (delay < base::TimeDelta()) {
220 LOG(WARNING) << "Audio read callback behind schedule by " 219 LOG(WARNING) << "Audio read callback behind schedule by "
221 << (packet_duration_ms_ - delay.InMilliseconds()) 220 << (buffer_duration_ms_ - delay.InMilliseconds())
222 << " (ms)."; 221 << " (ms).";
223 // Read callback is behind schedule. Assuming there is data pending in 222 // Read callback is behind schedule. Assuming there is data pending in
224 // the soundcard, invoke the read callback immediate in order to catch up. 223 // the soundcard, invoke the read callback immediate in order to catch up.
225 read_callback_behind_schedule_ = true; 224 read_callback_behind_schedule_ = true;
226 delay = base::TimeDelta(); 225 delay = base::TimeDelta();
227 } 226 }
228 227
229 MessageLoop::current()->PostDelayedTask( 228 MessageLoop::current()->PostDelayedTask(
230 FROM_HERE, 229 FROM_HERE,
231 base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()), 230 base::Bind(&AlsaPcmInputStream::ReadAudio, weak_factory_.GetWeakPtr()),
(...skipping 17 matching lines...) Expand all
249 void AlsaPcmInputStream::Close() { 248 void AlsaPcmInputStream::Close() {
250 if (device_handle_) { 249 if (device_handle_) {
251 weak_factory_.InvalidateWeakPtrs(); // Cancel the next scheduled read. 250 weak_factory_.InvalidateWeakPtrs(); // Cancel the next scheduled read.
252 int error = alsa_util::CloseDevice(wrapper_, device_handle_); 251 int error = alsa_util::CloseDevice(wrapper_, device_handle_);
253 if (error < 0) 252 if (error < 0)
254 HandleError("PcmClose", error); 253 HandleError("PcmClose", error);
255 254
256 if (mixer_handle_) 255 if (mixer_handle_)
257 alsa_util::CloseMixer(wrapper_, mixer_handle_, device_name_); 256 alsa_util::CloseMixer(wrapper_, mixer_handle_, device_name_);
258 257
259 audio_packet_.reset(); 258 audio_buffer_.reset();
260 device_handle_ = NULL; 259 device_handle_ = NULL;
261 mixer_handle_ = NULL; 260 mixer_handle_ = NULL;
262 mixer_element_handle_ = NULL; 261 mixer_element_handle_ = NULL;
263 262
264 if (callback_) 263 if (callback_)
265 callback_->OnClose(this); 264 callback_->OnClose(this);
266 } 265 }
267 266
268 audio_manager_->ReleaseInputStream(this); 267 audio_manager_->ReleaseInputStream(this);
269 } 268 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 return 0.0; 320 return 0.0;
322 } 321 }
323 322
324 return static_cast<double>(current_volume); 323 return static_cast<double>(current_volume);
325 } 324 }
326 325
327 void AlsaPcmInputStream::HandleError(const char* method, int error) { 326 void AlsaPcmInputStream::HandleError(const char* method, int error) {
328 LOG(WARNING) << method << ": " << wrapper_->StrError(error); 327 LOG(WARNING) << method << ": " << wrapper_->StrError(error);
329 callback_->OnError(this, error); 328 callback_->OnError(this, error);
330 } 329 }
OLDNEW
« no previous file with comments | « media/audio/linux/alsa_input.h ('k') | media/audio/linux/alsa_output.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698