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

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

Issue 275022: Move Alsa device opening into the audio thread, and add in support for multi-channel audio. (Closed)
Patch Set: Fix up the unittests since we not only downmix for a very small set of channels. Created 11 years, 2 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
« no previous file with comments | « media/audio/linux/alsa_output.h ('k') | media/audio/linux/alsa_output_unittest.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) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 // The AlsaPcmOutputStream object's internal state is accessed by two threads: 7 // The AlsaPcmOutputStream object's internal state is accessed by two threads:
8 // 8 //
9 // client thread - creates the object and calls the public APIs. 9 // client thread - creates the object and calls the public APIs.
10 // message loop thread - executes all the internal tasks including querying 10 // message loop thread - executes all the internal tasks including querying
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 95
96 // Set to 0 during debugging if you want error messages due to underrun 96 // Set to 0 during debugging if you want error messages due to underrun
97 // events or other recoverable errors. 97 // events or other recoverable errors.
98 #if defined(NDEBUG) 98 #if defined(NDEBUG)
99 static const int kPcmRecoverIsSilent = 1; 99 static const int kPcmRecoverIsSilent = 1;
100 #else 100 #else
101 static const int kPcmRecoverIsSilent = 0; 101 static const int kPcmRecoverIsSilent = 0;
102 #endif 102 #endif
103 103
104 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; 104 const char AlsaPcmOutputStream::kDefaultDevice[] = "default";
105 const char AlsaPcmOutputStream::kAutoSelectDevice[] = "";
106 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:";
107
108 // Since we expect to only be able to wake up with a resolution of
109 // kSleepErrorMilliseconds, double that for our minimum required latency.
110 const int AlsaPcmOutputStream::kMinLatencyMicros =
111 kSleepErrorMilliseconds * 2 * 1000;
105 112
106 namespace { 113 namespace {
107 114
108 snd_pcm_format_t BitsToFormat(char bits_per_sample) { 115 snd_pcm_format_t BitsToFormat(char bits_per_sample) {
109 switch (bits_per_sample) { 116 switch (bits_per_sample) {
110 case 8: 117 case 8:
111 return SND_PCM_FORMAT_S8; 118 return SND_PCM_FORMAT_U8;
112 119
113 case 16: 120 case 16:
114 return SND_PCM_FORMAT_S16; 121 return SND_PCM_FORMAT_S16;
115 122
116 case 24: 123 case 24:
117 return SND_PCM_FORMAT_S24; 124 return SND_PCM_FORMAT_S24;
118 125
119 case 32: 126 case 32:
120 return SND_PCM_FORMAT_S32; 127 return SND_PCM_FORMAT_S32;
121 128
122 default: 129 default:
123 return SND_PCM_FORMAT_UNKNOWN; 130 return SND_PCM_FORMAT_UNKNOWN;
124 } 131 }
125 } 132 }
126 133
134 // While the "default" device may support multi-channel audio, in Alsa, only
135 // the device names surround40, surround41, surround50, etc, have a defined
136 // channel mapping according to Lennart:
137 //
138 // http://0pointer.de/blog/projects/guide-to-sound-apis.html
139 //
140 // This function makes a best guess at the specific > 2 channel device name
141 // based on the number of channels requested. NULL is returned if no device
142 // can be found to match the channel numbers. In this case, using
143 // kDefaultDevice is probably the best bet.
144 //
145 // A five channel source is assumed to be surround50 instead of surround41
146 // (which is also 5 channels).
147 //
148 // TODO(ajwong): The source data should have enough info to tell us if we want
149 // surround41 versus surround51, etc., instead of needing us to guess base don
150 // channel number. Fix API to pass that data down.
151 const char* GuessSpecificDeviceName(int channels) {
152 switch (channels) {
153 case 8:
154 return "surround71";
155
156 case 7:
157 return "surround70";
158
159 case 6:
160 return "surround51";
161
162 case 5:
163 return "surround50";
164
165 case 4:
166 return "surround40";
167
168 default:
169 return NULL;
170 }
171 }
172
173 // Reorder PCM from AAC layout to Alsa layout.
174 // TODO(fbarchard): Switch layout when ffmpeg is updated.
175 template<class Format>
176 static void Swizzle50Layout(Format* b, size_t filled) {
177 static const int kNumSurroundChannels = 5;
178 Format aac[kNumSurroundChannels];
179 for (size_t i = 0; i < filled; i += sizeof(aac), b += kNumSurroundChannels) {
180 memcpy(aac, b, sizeof(aac));
181 b[0] = aac[1]; // L
182 b[1] = aac[2]; // R
183 b[2] = aac[3]; // Ls
184 b[3] = aac[4]; // Rs
185 b[4] = aac[0]; // C
186 }
187 }
188
189 template<class Format>
190 static void Swizzle51Layout(Format* b, size_t filled) {
191 static const int kNumSurroundChannels = 6;
192 Format aac[kNumSurroundChannels];
193 for (size_t i = 0; i < filled; i += sizeof(aac), b += kNumSurroundChannels) {
194 memcpy(aac, b, sizeof(aac));
195 b[0] = aac[1]; // L
196 b[1] = aac[2]; // R
197 b[2] = aac[3]; // Ls
198 b[3] = aac[4]; // Rs
199 b[4] = aac[0]; // C
200 b[5] = aac[5]; // LFE
201 }
202 }
203
127 } // namespace 204 } // namespace
128 205
206 // Not in an anonymous so that it can be a friend to AlsaPcmOutputStream.
129 std::ostream& operator<<(std::ostream& os, 207 std::ostream& operator<<(std::ostream& os,
130 AlsaPcmOutputStream::InternalState state) { 208 AlsaPcmOutputStream::InternalState state) {
131 switch (state) { 209 switch (state) {
132 case AlsaPcmOutputStream::kInError: 210 case AlsaPcmOutputStream::kInError:
133 os << "kInError"; 211 os << "kInError";
134 break; 212 break;
135 case AlsaPcmOutputStream::kCreated: 213 case AlsaPcmOutputStream::kCreated:
136 os << "kCreated"; 214 os << "kCreated";
137 break; 215 break;
138 case AlsaPcmOutputStream::kIsOpened: 216 case AlsaPcmOutputStream::kIsOpened:
(...skipping 14 matching lines...) Expand all
153 231
154 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, 232 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
155 AudioManager::Format format, 233 AudioManager::Format format,
156 int channels, 234 int channels,
157 int sample_rate, 235 int sample_rate,
158 int bits_per_sample, 236 int bits_per_sample,
159 AlsaWrapper* wrapper, 237 AlsaWrapper* wrapper,
160 AudioManagerLinux* manager, 238 AudioManagerLinux* manager,
161 MessageLoop* message_loop) 239 MessageLoop* message_loop)
162 : shared_data_(MessageLoop::current()), 240 : shared_data_(MessageLoop::current()),
163 device_name_(device_name), 241 requested_device_name_(device_name),
164 pcm_format_(BitsToFormat(bits_per_sample)), 242 pcm_format_(BitsToFormat(bits_per_sample)),
165 channels_(channels), 243 channels_(channels),
166 sample_rate_(sample_rate), 244 sample_rate_(sample_rate),
167 bytes_per_sample_(bits_per_sample / 8), 245 bytes_per_sample_(bits_per_sample / 8),
168 bytes_per_frame_(channels_ * bits_per_sample / 8), 246 bytes_per_frame_(channels_ * bits_per_sample / 8),
247 should_downmix_(false),
248 latency_micros_(0),
249 micros_per_packet_(0),
250 bytes_per_output_frame_(bytes_per_frame_),
169 stop_stream_(false), 251 stop_stream_(false),
170 wrapper_(wrapper), 252 wrapper_(wrapper),
171 manager_(manager), 253 manager_(manager),
172 playback_handle_(NULL), 254 playback_handle_(NULL),
173 frames_per_packet_(0), 255 frames_per_packet_(0),
174 client_thread_loop_(MessageLoop::current()), 256 client_thread_loop_(MessageLoop::current()),
175 message_loop_(message_loop) { 257 message_loop_(message_loop) {
176 258
177 // Sanity check input values. 259 // Sanity check input values.
178 //
179 // TODO(scherkus): ALSA works fine if you pass in multichannel audio, however
180 // it seems to be mapped to the wrong channels. We may have to do some
181 // channel swizzling from decoder output to ALSA's preferred multichannel
182 // format.
183 if (channels_ != 1 && channels_ != 2) {
184 LOG(WARNING) << "Only 1 and 2 channel audio is supported right now.";
185 shared_data_.TransitionTo(kInError);
186 }
187
188 if (AudioManager::AUDIO_PCM_LINEAR != format) { 260 if (AudioManager::AUDIO_PCM_LINEAR != format) {
189 LOG(WARNING) << "Only linear PCM supported."; 261 LOG(WARNING) << "Only linear PCM supported.";
190 shared_data_.TransitionTo(kInError); 262 shared_data_.TransitionTo(kInError);
191 } 263 }
192 264
193 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { 265 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) {
194 LOG(WARNING) << "Unsupported bits per sample: " << bits_per_sample; 266 LOG(WARNING) << "Unsupported bits per sample: " << bits_per_sample;
195 shared_data_.TransitionTo(kInError); 267 shared_data_.TransitionTo(kInError);
196 } 268 }
197 } 269 }
(...skipping 17 matching lines...) Expand all
215 287
216 if (shared_data_.state() == kInError) { 288 if (shared_data_.state() == kInError) {
217 return false; 289 return false;
218 } 290 }
219 291
220 if (!shared_data_.CanTransitionTo(kIsOpened)) { 292 if (!shared_data_.CanTransitionTo(kIsOpened)) {
221 NOTREACHED() << "Invalid state: " << shared_data_.state(); 293 NOTREACHED() << "Invalid state: " << shared_data_.state();
222 return false; 294 return false;
223 } 295 }
224 296
225 // Try to open the device.
226 snd_pcm_t* handle = NULL;
227 int error = wrapper_->PcmOpen(&handle, device_name_.c_str(),
228 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
229 if (error < 0) {
230 LOG(ERROR) << "Cannot open audio device (" << device_name_ << "): "
231 << wrapper_->StrError(error);
232 return false;
233 }
234
235 // Configure the device for software resampling, and add enough buffer for
236 // two audio packets.
237 int micros_per_packet =
238 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_);
239 if ((error = wrapper_->PcmSetParams(handle,
240 pcm_format_,
241 SND_PCM_ACCESS_RW_INTERLEAVED,
242 channels_,
243 sample_rate_,
244 1, // soft_resample -- let ALSA resample
245 micros_per_packet * 2)) < 0) {
246 LOG(ERROR) << "Unable to set PCM parameters for (" << device_name_
247 << "): " << wrapper_->StrError(error);
248 if (!CloseDevice(handle)) {
249 // TODO(ajwong): Retry on certain errors?
250 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
251 }
252 return false;
253 }
254
255 // We do not need to check if the transition was successful because 297 // We do not need to check if the transition was successful because
256 // CanTransitionTo() was checked above, and it is assumed that this 298 // CanTransitionTo() was checked above, and it is assumed that this
257 // object's public API is only called on one thread so the state cannot 299 // object's public API is only called on one thread so the state cannot
258 // transition out from under us. 300 // transition out from under us.
259 shared_data_.TransitionTo(kIsOpened); 301 shared_data_.TransitionTo(kIsOpened);
260 message_loop_->PostTask( 302 message_loop_->PostTask(
261 FROM_HERE, 303 FROM_HERE,
262 NewRunnableMethod(this, &AlsaPcmOutputStream::FinishOpen, 304 NewRunnableMethod(this, &AlsaPcmOutputStream::OpenTask, packet_size));
263 handle, packet_size));
264 305
265 return true; 306 return true;
266 } 307 }
267 308
268 void AlsaPcmOutputStream::Close() { 309 void AlsaPcmOutputStream::Close() {
269 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); 310 DCHECK_EQ(MessageLoop::current(), client_thread_loop_);
270 311
271 // Sanity check that the transition occurs correctly. It is safe to 312 // Sanity check that the transition occurs correctly. It is safe to
272 // continue anyways because all operations for closing are idempotent. 313 // continue anyways because all operations for closing are idempotent.
273 if (shared_data_.TransitionTo(kIsClosed) != kIsClosed) { 314 if (shared_data_.TransitionTo(kIsClosed) != kIsClosed) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 355
315 shared_data_.set_volume(static_cast<float>(left_level)); 356 shared_data_.set_volume(static_cast<float>(left_level));
316 } 357 }
317 358
318 void AlsaPcmOutputStream::GetVolume(double* left_level, double* right_level) { 359 void AlsaPcmOutputStream::GetVolume(double* left_level, double* right_level) {
319 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); 360 DCHECK_EQ(MessageLoop::current(), client_thread_loop_);
320 361
321 *left_level = *right_level = shared_data_.volume(); 362 *left_level = *right_level = shared_data_.volume();
322 } 363 }
323 364
324 void AlsaPcmOutputStream::FinishOpen(snd_pcm_t* playback_handle, 365 void AlsaPcmOutputStream::OpenTask(size_t packet_size) {
325 size_t packet_size) {
326 DCHECK_EQ(MessageLoop::current(), message_loop_); 366 DCHECK_EQ(MessageLoop::current(), message_loop_);
327 367
328 playback_handle_ = playback_handle; 368 // Initialize the configuration variables.
329 packet_.reset(new Packet(packet_size));
330 frames_per_packet_ = packet_size / bytes_per_frame_; 369 frames_per_packet_ = packet_size / bytes_per_frame_;
370
371 // Try to open the device.
372 micros_per_packet_ =
373 FramesToMicros(packet_size / bytes_per_frame_, sample_rate_);
374 latency_micros_ = std::max(AlsaPcmOutputStream::kMinLatencyMicros,
375 micros_per_packet_ * 2);
376 if (requested_device_name_ == kAutoSelectDevice) {
377 playback_handle_ = AutoSelectDevice(latency_micros_);
378 if (playback_handle_) {
379 LOG(INFO) << "Auto-selected device: " << device_name_;
380 }
381 } else {
382 device_name_ = requested_device_name_;
383 playback_handle_ = OpenDevice(device_name_, channels_, latency_micros_);
384 }
385
386 // Finish initializing the stream if the device was opened successfully.
387 if (playback_handle_ == NULL) {
388 stop_stream_ = true;
389 } else {
390 packet_.reset(new Packet(packet_size));
391 if (should_downmix_) {
392 bytes_per_output_frame_ = 2 * bytes_per_sample_;
393 }
394 }
331 } 395 }
332 396
333 void AlsaPcmOutputStream::StartTask() { 397 void AlsaPcmOutputStream::StartTask() {
334 DCHECK_EQ(MessageLoop::current(), message_loop_); 398 DCHECK_EQ(MessageLoop::current(), message_loop_);
335 399
400 if (stop_stream_) {
401 return;
402 }
403
336 // When starting again, drop all packets in the device and prepare it again 404 // When starting again, drop all packets in the device and prepare it again
337 // incase we are restarting from a pause state and need to flush old data. 405 // incase we are restarting from a pause state and need to flush old data.
338 int error = wrapper_->PcmDrop(playback_handle_); 406 int error = wrapper_->PcmDrop(playback_handle_);
339 if (error < 0 && error != -EAGAIN) { 407 if (error < 0 && error != -EAGAIN) {
340 LOG(ERROR) << "Failure clearing playback device (" 408 LOG(ERROR) << "Failure clearing playback device ("
341 << wrapper_->PcmName(playback_handle_) << "): " 409 << wrapper_->PcmName(playback_handle_) << "): "
342 << wrapper_->StrError(error); 410 << wrapper_->StrError(error);
343 stop_stream_ = true; 411 stop_stream_ = true;
344 return; 412 return;
345 } 413 }
346 414
347 error = wrapper_->PcmPrepare(playback_handle_); 415 error = wrapper_->PcmPrepare(playback_handle_);
348 if (error < 0 && error != -EAGAIN) { 416 if (error < 0 && error != -EAGAIN) {
349 LOG(ERROR) << "Failure preparing stream (" 417 LOG(ERROR) << "Failure preparing stream ("
350 << wrapper_->PcmName(playback_handle_) << "): " 418 << wrapper_->PcmName(playback_handle_) << "): "
351 << wrapper_->StrError(error); 419 << wrapper_->StrError(error);
352 stop_stream_ = true; 420 stop_stream_ = true;
353 return; 421 return;
354 } 422 }
355 423
356 // Do a best-effort write of 2 packets to pre-roll. 424 // Do a best-effort pre-roll to fill the buffer. Use integer rounding to find
425 // the maximum number of full packets that can fit into the buffer.
357 // 426 //
358 // TODO(ajwong): Make this track with the us_latency set in Open(). 427 // TODO(ajwong): Handle EAGAIN.
359 // Also handle EAGAIN. 428 const int num_preroll = latency_micros_ / micros_per_packet_;
360 BufferPacket(packet_.get()); 429 for (int i = 0; i < num_preroll; ++i) {
361 WritePacket(packet_.get()); 430 BufferPacket(packet_.get());
362 BufferPacket(packet_.get()); 431 WritePacket(packet_.get());
363 WritePacket(packet_.get()); 432 }
364 433
365 ScheduleNextWrite(packet_.get()); 434 ScheduleNextWrite(packet_.get());
366 } 435 }
367 436
368 void AlsaPcmOutputStream::CloseTask() { 437 void AlsaPcmOutputStream::CloseTask() {
369 // NOTE: Keep this function idempotent to handle errors that might cause 438 // NOTE: Keep this function idempotent to handle errors that might cause
370 // multiple CloseTasks to be posted. 439 // multiple CloseTasks to be posted.
371 DCHECK_EQ(MessageLoop::current(), message_loop_); 440 DCHECK_EQ(MessageLoop::current(), message_loop_);
372 441
373 // Shutdown the audio device. 442 // Shutdown the audio device.
(...skipping 29 matching lines...) Expand all
403 error, 472 error,
404 kPcmRecoverIsSilent); 473 kPcmRecoverIsSilent);
405 if (error < 0) { 474 if (error < 0) {
406 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error); 475 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error);
407 } 476 }
408 477
409 // TODO(hclam): If we cannot query the delay, we may want to stop 478 // TODO(hclam): If we cannot query the delay, we may want to stop
410 // the playback and report an error. 479 // the playback and report an error.
411 delay = 0; 480 delay = 0;
412 } else { 481 } else {
413 delay *= bytes_per_frame_; 482 delay *= bytes_per_output_frame_;
414 } 483 }
415 484
416 packet->used = 0; 485 packet->used = 0;
417 packet->size = shared_data_.OnMoreData(this, packet->buffer.get(), 486 packet->size = shared_data_.OnMoreData(this, packet->buffer.get(),
418 packet->capacity, delay); 487 packet->capacity, delay);
419 CHECK(packet->size <= packet->capacity) << "Data source overran buffer."; 488 CHECK(packet->size <= packet->capacity) << "Data source overran buffer.";
420 489
421 // This should not happen, but incase it does, drop any trailing bytes 490 // This should not happen, but incase it does, drop any trailing bytes
422 // that aren't large enough to make a frame. Without this, packet writing 491 // that aren't large enough to make a frame. Without this, packet writing
423 // may stall because the last few bytes in the packet may never get used by 492 // may stall because the last few bytes in the packet may never get used by
424 // WritePacket. 493 // WritePacket.
425 DCHECK(packet->size % bytes_per_frame_ == 0); 494 DCHECK(packet->size % bytes_per_frame_ == 0);
426 packet->size = (packet->size / bytes_per_frame_) * bytes_per_frame_; 495 packet->size = (packet->size / bytes_per_frame_) * bytes_per_frame_;
427 496
428 media::AdjustVolume(packet->buffer.get(), 497 if (should_downmix_) {
429 packet->size, 498 if (media::FoldChannels(packet->buffer.get(),
430 channels_, 499 packet->size,
431 bytes_per_sample_, 500 channels_,
432 shared_data_.volume()); 501 bytes_per_sample_,
502 shared_data_.volume())) {
503 // Adjust packet size for downmix.
504 packet->size =
505 packet->size / bytes_per_frame_ * bytes_per_output_frame_;
506 } else {
507 LOG(ERROR) << "Folding failed";
508 }
509 } else {
510 // TODO(ajwong): Handle other channel orderings.
511
512 // Handle channel order for 5.0 audio.
513 if (channels_ == 5) {
514 if (bytes_per_sample_ == 1) {
515 Swizzle50Layout(reinterpret_cast<uint8*>(packet->buffer.get()),
516 packet->size);
517 } else if (bytes_per_sample_ == 2) {
518 Swizzle50Layout(reinterpret_cast<int16*>(packet->buffer.get()),
519 packet->size);
520 } else if (bytes_per_sample_ == 4) {
521 Swizzle50Layout(reinterpret_cast<int32*>(packet->buffer.get()),
522 packet->size);
523 }
524 }
525
526 // Handle channel order for 5.1 audio.
527 if (channels_ == 6) {
528 if (bytes_per_sample_ == 1) {
529 Swizzle51Layout(reinterpret_cast<uint8*>(packet->buffer.get()),
530 packet->size);
531 } else if (bytes_per_sample_ == 2) {
532 Swizzle51Layout(reinterpret_cast<int16*>(packet->buffer.get()),
533 packet->size);
534 } else if (bytes_per_sample_ == 4) {
535 Swizzle51Layout(reinterpret_cast<int32*>(packet->buffer.get()),
536 packet->size);
537 }
538 }
539
540 media::AdjustVolume(packet->buffer.get(),
541 packet->size,
542 channels_,
543 bytes_per_sample_,
544 shared_data_.volume());
545 }
433 } 546 }
434 } 547 }
435 548
436 void AlsaPcmOutputStream::WritePacket(Packet* packet) { 549 void AlsaPcmOutputStream::WritePacket(Packet* packet) {
437 DCHECK_EQ(MessageLoop::current(), message_loop_); 550 DCHECK_EQ(MessageLoop::current(), message_loop_);
438 551
439 CHECK(packet->size % bytes_per_frame_ == 0); 552 CHECK(packet->size % bytes_per_output_frame_ == 0);
440 553
441 // If the device is in error, just eat the bytes. 554 // If the device is in error, just eat the bytes.
442 if (stop_stream_) { 555 if (stop_stream_) {
443 packet->used = packet->size; 556 packet->used = packet->size;
444 return; 557 return;
445 } 558 }
446 559
447 if (packet->used < packet->size) { 560 if (packet->used < packet->size) {
448 char* buffer_pos = packet->buffer.get() + packet->used; 561 char* buffer_pos = packet->buffer.get() + packet->used;
449 snd_pcm_sframes_t frames = FramesInPacket(*packet, bytes_per_frame_); 562 snd_pcm_sframes_t frames = FramesInPacket(*packet, bytes_per_output_frame_);
450 563
451 DCHECK_GT(frames, 0); 564 DCHECK_GT(frames, 0);
452 565
453 snd_pcm_sframes_t frames_written = 566 snd_pcm_sframes_t frames_written =
454 wrapper_->PcmWritei(playback_handle_, buffer_pos, frames); 567 wrapper_->PcmWritei(playback_handle_, buffer_pos, frames);
455 if (frames_written < 0) { 568 if (frames_written < 0) {
456 // Attempt once to immediately recover from EINTR, 569 // Attempt once to immediately recover from EINTR,
457 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket 570 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket
458 // will eventually be called again, so eventual recovery will happen if 571 // will eventually be called again, so eventual recovery will happen if
459 // muliple retries are required. 572 // muliple retries are required.
460 frames_written = wrapper_->PcmRecover(playback_handle_, 573 frames_written = wrapper_->PcmRecover(playback_handle_,
461 frames_written, 574 frames_written,
462 kPcmRecoverIsSilent); 575 kPcmRecoverIsSilent);
463 } 576 }
464 577
465 if (frames_written < 0) { 578 if (frames_written < 0) {
466 // TODO(ajwong): Is EAGAIN the only error we want to except from stopping 579 // TODO(ajwong): Is EAGAIN the only error we want to except from stopping
467 // the pcm playback? 580 // the pcm playback?
468 if (frames_written != -EAGAIN) { 581 if (frames_written != -EAGAIN) {
469 LOG(ERROR) << "Failed to write to pcm device: " 582 LOG(ERROR) << "Failed to write to pcm device: "
470 << wrapper_->StrError(frames_written); 583 << wrapper_->StrError(frames_written);
471 shared_data_.OnError(this, frames_written); 584 shared_data_.OnError(this, frames_written);
472 stop_stream_ = true; 585 stop_stream_ = true;
473 } 586 }
474 } else { 587 } else {
475 packet->used += frames_written * bytes_per_frame_; 588 packet->used += frames_written * bytes_per_output_frame_;
476 } 589 }
477 } 590 }
478 } 591 }
479 592
480 void AlsaPcmOutputStream::WriteTask() { 593 void AlsaPcmOutputStream::WriteTask() {
481 DCHECK_EQ(MessageLoop::current(), message_loop_); 594 DCHECK_EQ(MessageLoop::current(), message_loop_);
482 595
483 if (stop_stream_) { 596 if (stop_stream_) {
484 return; 597 return;
485 } 598 }
486 599
487 BufferPacket(packet_.get()); 600 BufferPacket(packet_.get());
488 WritePacket(packet_.get()); 601 WritePacket(packet_.get());
489 602
490 ScheduleNextWrite(packet_.get()); 603 ScheduleNextWrite(packet_.get());
491 } 604 }
492 605
493 void AlsaPcmOutputStream::ScheduleNextWrite(Packet* current_packet) { 606 void AlsaPcmOutputStream::ScheduleNextWrite(Packet* current_packet) {
494 DCHECK_EQ(MessageLoop::current(), message_loop_); 607 DCHECK_EQ(MessageLoop::current(), message_loop_);
495 608
496 if (stop_stream_) { 609 if (stop_stream_) {
497 return; 610 return;
498 } 611 }
499 612
500 // Calculate when we should have enough buffer for another packet of data. 613 // Calculate when we should have enough buffer for another packet of data.
501 int frames_leftover = FramesInPacket(*current_packet, bytes_per_frame_); 614 // Make sure to take into consideration down-mixing.
502 int frames_needed = 615 int frames_leftover =
503 frames_leftover > 0 ? frames_leftover : frames_per_packet_; 616 FramesInPacket(*current_packet, bytes_per_output_frame_);
504 int frames_until_empty_enough = frames_needed - GetAvailableFrames(); 617 int frames_avail_wanted =
618 (frames_leftover > 0) ? frames_leftover : frames_per_packet_;
619 int frames_until_empty_enough = frames_avail_wanted - GetAvailableFrames();
505 int next_fill_time_ms = 620 int next_fill_time_ms =
506 FramesToMillis(frames_until_empty_enough, sample_rate_); 621 FramesToMillis(frames_until_empty_enough, sample_rate_);
507 622
508 // Adjust for timer resolution issues. 623 // Adjust for timer resolution issues.
509 if (next_fill_time_ms > kSleepErrorMilliseconds) { 624 if (next_fill_time_ms > kSleepErrorMilliseconds) {
510 next_fill_time_ms -= kSleepErrorMilliseconds; 625 next_fill_time_ms -= kSleepErrorMilliseconds;
511 } 626 }
512 627
513 // Avoid busy looping if the data source is exhausted. 628 // Avoid busy looping if the data source is exhausted.
514 if (current_packet->size == 0) { 629 if (current_packet->size == 0) {
(...skipping 23 matching lines...) Expand all
538 } 653 }
539 654
540 int64 AlsaPcmOutputStream::FramesToMicros(int frames, int sample_rate) { 655 int64 AlsaPcmOutputStream::FramesToMicros(int frames, int sample_rate) {
541 return frames * base::Time::kMicrosecondsPerSecond / sample_rate; 656 return frames * base::Time::kMicrosecondsPerSecond / sample_rate;
542 } 657 }
543 658
544 int64 AlsaPcmOutputStream::FramesToMillis(int frames, int sample_rate) { 659 int64 AlsaPcmOutputStream::FramesToMillis(int frames, int sample_rate) {
545 return frames * base::Time::kMillisecondsPerSecond / sample_rate; 660 return frames * base::Time::kMillisecondsPerSecond / sample_rate;
546 } 661 }
547 662
663 std::string AlsaPcmOutputStream::FindDeviceForChannels(int channels) {
664 // Constants specified by the ALSA API for device hints.
665 static const int kGetAllDevices = -1;
666 static const char kPcmInterfaceName[] = "pcm";
667 static const char kIoHintName[] = "IOID";
668 static const char kNameHintName[] = "NAME";
669
670 const char* wanted_device = GuessSpecificDeviceName(channels);
671 if (!wanted_device) {
672 return "";
673 }
674
675 std::string guessed_device;
676 void** hints = NULL;
677 int error = wrapper_->DeviceNameHint(kGetAllDevices,
678 kPcmInterfaceName,
679 &hints);
680 if (error == 0) {
681 // NOTE: Do not early return from inside this if statement. The
682 // hints above need to be freed.
683 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
684 // Only examine devices that are output capable.. Valid values are
685 // "Input", "Output", and NULL which means both input and output.
686 scoped_ptr_malloc<char> io(
687 wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName));
688 if (io != NULL && strcmp(io.get(), "Input") == 0)
689 continue;
690
691 // Attempt to select the closest device for number of channels.
692 scoped_ptr_malloc<char> name(
693 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
694 if (strncmp(wanted_device, name.get(), strlen(wanted_device)) == 0) {
695 guessed_device = name.get();
696 break;
697 }
698 }
699
700 // Destory the hint now that we're done with it.
701 wrapper_->DeviceNameFreeHint(hints);
702 hints = NULL;
703 } else {
704 LOG(ERROR) << "Unable to get hints for devices: "
705 << wrapper_->StrError(error);
706 }
707
708 return guessed_device;
709 }
710
711 snd_pcm_t* AlsaPcmOutputStream::OpenDevice(const std::string& device_name,
712 int channels,
713 unsigned int latency) {
714 snd_pcm_t* handle = NULL;
715 int error = wrapper_->PcmOpen(&handle, device_name.c_str(),
716 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
717 if (error < 0) {
718 LOG(ERROR) << "Cannot open audio device (" << device_name << "): "
719 << wrapper_->StrError(error);
720 return NULL;
721 }
722
723 // Configure the device for software resampling.
724 if ((error = wrapper_->PcmSetParams(handle,
725 pcm_format_,
726 SND_PCM_ACCESS_RW_INTERLEAVED,
727 channels,
728 sample_rate_,
729 1, // soft_resample -- let ALSA resample
730 latency)) < 0) {
731 LOG(ERROR) << "Unable to set PCM parameters for (" << device_name
732 << "): " << wrapper_->StrError(error)
733 << " -- Format: " << pcm_format_
734 << " Channels: " << channels
735 << " Latency (us): " << latency;
736 if (!CloseDevice(handle)) {
737 // TODO(ajwong): Retry on certain errors?
738 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
739 }
740 return NULL;
741 }
742
743 return handle;
744 }
745
548 bool AlsaPcmOutputStream::CloseDevice(snd_pcm_t* handle) { 746 bool AlsaPcmOutputStream::CloseDevice(snd_pcm_t* handle) {
549 int error = wrapper_->PcmClose(handle); 747 int error = wrapper_->PcmClose(handle);
550 if (error < 0) { 748 if (error < 0) {
551 LOG(ERROR) << "Cannot close audio device (" << wrapper_->PcmName(handle) 749 LOG(ERROR) << "Cannot close audio device (" << wrapper_->PcmName(handle)
552 << "): " << wrapper_->StrError(error); 750 << "): " << wrapper_->StrError(error);
553 return false; 751 return false;
554 } 752 }
555 753
556 return true; 754 return true;
557 } 755 }
(...skipping 15 matching lines...) Expand all
573 } 771 }
574 if (available_frames < 0) { 772 if (available_frames < 0) {
575 LOG(ERROR) << "Failed querying available frames. Assuming 0: " 773 LOG(ERROR) << "Failed querying available frames. Assuming 0: "
576 << wrapper_->StrError(available_frames); 774 << wrapper_->StrError(available_frames);
577 return 0; 775 return 0;
578 } 776 }
579 777
580 return available_frames; 778 return available_frames;
581 } 779 }
582 780
781 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) {
782 // For auto-selection:
783 // 1) Attempt to open a device that best matches the number of channels
784 // requested.
785 // 2) If that fails, attempt the "plug:" version of it incase ALSA can
786 // remap do some software conversion to make it work.
787 // 3) Fallback to kDefaultDevice.
788 // 4) If that fails too, try the "plug:" version of kDefaultDevice.
789 // 5) Give up.
790 snd_pcm_t* handle = NULL;
791 device_name_ = FindDeviceForChannels(channels_);
792
793 // Step 1.
794 if (!device_name_.empty()) {
795 if ((handle = OpenDevice(device_name_, channels_, latency)) != NULL) {
796 return handle;
797 }
798
799 // Step 2.
800 device_name_ = kPlugPrefix + device_name_;
801 if ((handle = OpenDevice(device_name_, channels_, latency)) != NULL) {
802 return handle;
803 }
804 }
805
806 // For the kDefaultDevice device, we can only reliably depend on 2-channel
807 // output to have the correct ordering according to Lennart. For the channel
808 // formats that we know how to downmix from (5 channel to 6 channel), setup
809 // downmixing.
810 //
811 // TODO(ajwong): We need a SupportsFolding() function.
812 int default_channels = channels_;
813 if (default_channels >= 5 && default_channels <= 6) {
814 should_downmix_ = true;
815 default_channels = 2;
816 }
817
818 // Step 3.
819 device_name_ = kDefaultDevice;
820 if ((handle = OpenDevice(device_name_, default_channels, latency)) != NULL) {
821 return handle;
822 }
823
824 // Step 4.
825 device_name_ = kPlugPrefix + device_name_;
826 if ((handle = OpenDevice(device_name_, default_channels, latency)) != NULL) {
827 return handle;
828 }
829
830 // Unable to open any device.
831 device_name_.clear();
832 return NULL;
833 }
834
583 AudioManagerLinux* AlsaPcmOutputStream::manager() { 835 AudioManagerLinux* AlsaPcmOutputStream::manager() {
584 DCHECK_EQ(MessageLoop::current(), client_thread_loop_); 836 DCHECK_EQ(MessageLoop::current(), client_thread_loop_);
585 return manager_; 837 return manager_;
586 } 838 }
587 839
588 AlsaPcmOutputStream::SharedData::SharedData( 840 AlsaPcmOutputStream::SharedData::SharedData(
589 MessageLoop* state_transition_loop) 841 MessageLoop* state_transition_loop)
590 : state_(kCreated), 842 : state_(kCreated),
591 volume_(1.0f), 843 volume_(1.0f),
592 source_callback_(NULL), 844 source_callback_(NULL),
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 } 936 }
685 937
686 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 938 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
687 // release ownership of the currently registered callback. 939 // release ownership of the currently registered callback.
688 void AlsaPcmOutputStream::SharedData::set_source_callback( 940 void AlsaPcmOutputStream::SharedData::set_source_callback(
689 AudioSourceCallback* callback) { 941 AudioSourceCallback* callback) {
690 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); 942 DCHECK_EQ(MessageLoop::current(), state_transition_loop_);
691 AutoLock l(lock_); 943 AutoLock l(lock_);
692 source_callback_ = callback; 944 source_callback_ = callback;
693 } 945 }
OLDNEW
« no previous file with comments | « media/audio/linux/alsa_output.h ('k') | media/audio/linux/alsa_output_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698