Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / audio / alsa / alsa_output.cc
blobfac6888c2e35a93e453616486ba387e7c93f7a7b
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
3 // found in the LICENSE file.
4 //
5 // THREAD SAFETY
6 //
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.
9 //
10 // SEMANTICS OF Close()
12 // Close() is responsible for cleaning up any resources that were acquired after
13 // a successful Open(). Close() will nullify any scheduled outstanding runnable
14 // methods.
17 // SEMANTICS OF ERROR STATES
19 // The object has two distinct error states: |state_| == kInError
20 // and |stop_stream_|. The |stop_stream_| variable is used to indicate
21 // that the playback_handle should no longer be used either because of a
22 // hardware/low-level event.
24 // When |state_| == kInError, all public API functions will fail with an error
25 // (Start() will call the OnError() function on the callback immediately), or
26 // no-op themselves with the exception of Close(). Even if an error state has
27 // been entered, if Open() has previously returned successfully, Close() must be
28 // called to cleanup the ALSA devices and release resources.
30 // When |stop_stream_| is set, no more commands will be made against the
31 // ALSA device, and playback will effectively stop. From the client's point of
32 // view, it will seem that the device has just clogged and stopped requesting
33 // data.
35 #include "media/audio/alsa/alsa_output.h"
37 #include <algorithm>
39 #include "base/bind.h"
40 #include "base/logging.h"
41 #include "base/stl_util.h"
42 #include "base/time/time.h"
43 #include "base/trace_event/trace_event.h"
44 #include "media/audio/alsa/alsa_util.h"
45 #include "media/audio/alsa/alsa_wrapper.h"
46 #include "media/audio/alsa/audio_manager_alsa.h"
47 #include "media/base/channel_mixer.h"
48 #include "media/base/data_buffer.h"
49 #include "media/base/seekable_buffer.h"
51 namespace media {
53 // Set to 0 during debugging if you want error messages due to underrun
54 // events or other recoverable errors.
55 #if defined(NDEBUG)
56 static const int kPcmRecoverIsSilent = 1;
57 #else
58 static const int kPcmRecoverIsSilent = 0;
59 #endif
61 // The output channel layout if we set up downmixing for the kDefaultDevice
62 // device.
63 static const ChannelLayout kDefaultOutputChannelLayout = CHANNEL_LAYOUT_STEREO;
65 // While the "default" device may support multi-channel audio, in Alsa, only
66 // the device names surround40, surround41, surround50, etc, have a defined
67 // channel mapping according to Lennart:
69 // http://0pointer.de/blog/projects/guide-to-sound-apis.html
71 // This function makes a best guess at the specific > 2 channel device name
72 // based on the number of channels requested. NULL is returned if no device
73 // can be found to match the channel numbers. In this case, using
74 // kDefaultDevice is probably the best bet.
76 // A five channel source is assumed to be surround50 instead of surround41
77 // (which is also 5 channels).
79 // TODO(ajwong): The source data should have enough info to tell us if we want
80 // surround41 versus surround51, etc., instead of needing us to guess based on
81 // channel number. Fix API to pass that data down.
82 static const char* GuessSpecificDeviceName(uint32 channels) {
83 switch (channels) {
84 case 8:
85 return "surround71";
87 case 7:
88 return "surround70";
90 case 6:
91 return "surround51";
93 case 5:
94 return "surround50";
96 case 4:
97 return "surround40";
99 default:
100 return NULL;
104 std::ostream& operator<<(std::ostream& os,
105 AlsaPcmOutputStream::InternalState state) {
106 switch (state) {
107 case AlsaPcmOutputStream::kInError:
108 os << "kInError";
109 break;
110 case AlsaPcmOutputStream::kCreated:
111 os << "kCreated";
112 break;
113 case AlsaPcmOutputStream::kIsOpened:
114 os << "kIsOpened";
115 break;
116 case AlsaPcmOutputStream::kIsPlaying:
117 os << "kIsPlaying";
118 break;
119 case AlsaPcmOutputStream::kIsStopped:
120 os << "kIsStopped";
121 break;
122 case AlsaPcmOutputStream::kIsClosed:
123 os << "kIsClosed";
124 break;
126 return os;
129 const char AlsaPcmOutputStream::kDefaultDevice[] = "default";
130 const char AlsaPcmOutputStream::kAutoSelectDevice[] = "";
131 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:";
133 // We use 40ms as our minimum required latency. If it is needed, we may be able
134 // to get it down to 20ms.
135 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000;
137 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
138 const AudioParameters& params,
139 AlsaWrapper* wrapper,
140 AudioManagerBase* manager)
141 : requested_device_name_(device_name),
142 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())),
143 channels_(params.channels()),
144 channel_layout_(params.channel_layout()),
145 sample_rate_(params.sample_rate()),
146 bytes_per_sample_(params.bits_per_sample() / 8),
147 bytes_per_frame_(params.GetBytesPerFrame()),
148 packet_size_(params.GetBytesPerBuffer()),
149 latency_(std::max(
150 base::TimeDelta::FromMicroseconds(kMinLatencyMicros),
151 FramesToTimeDelta(params.frames_per_buffer() * 2, sample_rate_))),
152 bytes_per_output_frame_(bytes_per_frame_),
153 alsa_buffer_frames_(0),
154 stop_stream_(false),
155 wrapper_(wrapper),
156 manager_(manager),
157 message_loop_(base::MessageLoop::current()),
158 playback_handle_(NULL),
159 frames_per_packet_(packet_size_ / bytes_per_frame_),
160 state_(kCreated),
161 volume_(1.0f),
162 source_callback_(NULL),
163 audio_bus_(AudioBus::Create(params)),
164 weak_factory_(this) {
165 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
166 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_);
168 // Sanity check input values.
169 if (!params.IsValid()) {
170 LOG(WARNING) << "Unsupported audio parameters.";
171 TransitionTo(kInError);
174 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) {
175 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample();
176 TransitionTo(kInError);
180 AlsaPcmOutputStream::~AlsaPcmOutputStream() {
181 InternalState current_state = state();
182 DCHECK(current_state == kCreated ||
183 current_state == kIsClosed ||
184 current_state == kInError);
185 DCHECK(!playback_handle_);
188 bool AlsaPcmOutputStream::Open() {
189 DCHECK(IsOnAudioThread());
191 if (state() == kInError)
192 return false;
194 if (!CanTransitionTo(kIsOpened)) {
195 NOTREACHED() << "Invalid state: " << state();
196 return false;
199 // We do not need to check if the transition was successful because
200 // CanTransitionTo() was checked above, and it is assumed that this
201 // object's public API is only called on one thread so the state cannot
202 // transition out from under us.
203 TransitionTo(kIsOpened);
205 // Try to open the device.
206 if (requested_device_name_ == kAutoSelectDevice) {
207 playback_handle_ = AutoSelectDevice(latency_.InMicroseconds());
208 if (playback_handle_)
209 DVLOG(1) << "Auto-selected device: " << device_name_;
210 } else {
211 device_name_ = requested_device_name_;
212 playback_handle_ = alsa_util::OpenPlaybackDevice(
213 wrapper_, device_name_.c_str(), channels_, sample_rate_,
214 pcm_format_, latency_.InMicroseconds());
217 // Finish initializing the stream if the device was opened successfully.
218 if (playback_handle_ == NULL) {
219 stop_stream_ = true;
220 TransitionTo(kInError);
221 return false;
223 bytes_per_output_frame_ =
224 channel_mixer_ ? mixed_audio_bus_->channels() * bytes_per_sample_
225 : bytes_per_frame_;
226 uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_;
227 buffer_.reset(new media::SeekableBuffer(0, output_packet_size));
229 // Get alsa buffer size.
230 snd_pcm_uframes_t buffer_size;
231 snd_pcm_uframes_t period_size;
232 int error =
233 wrapper_->PcmGetParams(playback_handle_, &buffer_size, &period_size);
234 if (error < 0) {
235 LOG(ERROR) << "Failed to get playback buffer size from ALSA: "
236 << wrapper_->StrError(error);
237 // Buffer size is at least twice of packet size.
238 alsa_buffer_frames_ = frames_per_packet_ * 2;
239 } else {
240 alsa_buffer_frames_ = buffer_size;
243 return true;
246 void AlsaPcmOutputStream::Close() {
247 DCHECK(IsOnAudioThread());
249 if (state() != kIsClosed)
250 TransitionTo(kIsClosed);
252 // Shutdown the audio device.
253 if (playback_handle_) {
254 if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) {
255 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
257 playback_handle_ = NULL;
259 // Release the buffer.
260 buffer_.reset();
262 // Signal anything that might already be scheduled to stop.
263 stop_stream_ = true; // Not necessary in production, but unit tests
264 // uses the flag to verify that stream was closed.
267 weak_factory_.InvalidateWeakPtrs();
269 // Signal to the manager that we're closed and can be removed.
270 // Should be last call in the method as it deletes "this".
271 manager_->ReleaseOutputStream(this);
274 void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
275 DCHECK(IsOnAudioThread());
277 CHECK(callback);
279 if (stop_stream_)
280 return;
282 // Only post the task if we can enter the playing state.
283 if (TransitionTo(kIsPlaying) != kIsPlaying)
284 return;
286 // Before starting, the buffer might have audio from previous user of this
287 // device.
288 buffer_->Clear();
290 // When starting again, drop all packets in the device and prepare it again
291 // in case we are restarting from a pause state and need to flush old data.
292 int error = wrapper_->PcmDrop(playback_handle_);
293 if (error < 0 && error != -EAGAIN) {
294 LOG(ERROR) << "Failure clearing playback device ("
295 << wrapper_->PcmName(playback_handle_) << "): "
296 << wrapper_->StrError(error);
297 stop_stream_ = true;
298 return;
301 error = wrapper_->PcmPrepare(playback_handle_);
302 if (error < 0 && error != -EAGAIN) {
303 LOG(ERROR) << "Failure preparing stream ("
304 << wrapper_->PcmName(playback_handle_) << "): "
305 << wrapper_->StrError(error);
306 stop_stream_ = true;
307 return;
310 // Ensure the first buffer is silence to avoid startup glitches.
311 int buffer_size = GetAvailableFrames() * bytes_per_output_frame_;
312 scoped_refptr<DataBuffer> silent_packet = new DataBuffer(buffer_size);
313 silent_packet->set_data_size(buffer_size);
314 memset(silent_packet->writable_data(), 0, silent_packet->data_size());
315 buffer_->Append(silent_packet);
316 WritePacket();
318 // Start the callback chain.
319 set_source_callback(callback);
320 WriteTask();
323 void AlsaPcmOutputStream::Stop() {
324 DCHECK(IsOnAudioThread());
326 // Reset the callback, so that it is not called anymore.
327 set_source_callback(NULL);
328 weak_factory_.InvalidateWeakPtrs();
330 TransitionTo(kIsStopped);
333 void AlsaPcmOutputStream::SetVolume(double volume) {
334 DCHECK(IsOnAudioThread());
336 volume_ = static_cast<float>(volume);
339 void AlsaPcmOutputStream::GetVolume(double* volume) {
340 DCHECK(IsOnAudioThread());
342 *volume = volume_;
345 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
346 DCHECK(IsOnAudioThread());
348 // If stopped, simulate a 0-length packet.
349 if (stop_stream_) {
350 buffer_->Clear();
351 *source_exhausted = true;
352 return;
355 *source_exhausted = false;
357 // Request more data only when we run out of data in the buffer, because
358 // WritePacket() consumes only the current chunk of data.
359 if (!buffer_->forward_bytes()) {
360 // Before making a request to source for data we need to determine the
361 // delay (in bytes) for the requested data to be played.
362 const uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_;
364 scoped_refptr<media::DataBuffer> packet =
365 new media::DataBuffer(packet_size_);
366 int frames_filled = RunDataCallback(
367 audio_bus_.get(), hardware_delay);
369 size_t packet_size = frames_filled * bytes_per_frame_;
370 DCHECK_LE(packet_size, packet_size_);
372 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer;
373 // volume adjust should use SSE optimized vector_fmul() prior to interleave.
374 AudioBus* output_bus = audio_bus_.get();
375 ChannelLayout output_channel_layout = channel_layout_;
376 if (channel_mixer_) {
377 output_bus = mixed_audio_bus_.get();
378 channel_mixer_->Transform(audio_bus_.get(), output_bus);
379 output_channel_layout = kDefaultOutputChannelLayout;
380 // Adjust packet size for downmix.
381 packet_size = packet_size / bytes_per_frame_ * bytes_per_output_frame_;
384 // Reorder channels for 5.0, 5.1, and 7.1 to match ALSA's channel order,
385 // which has front center at channel index 4 and LFE at channel index 5.
386 // See http://ffmpeg.org/pipermail/ffmpeg-cvslog/2011-June/038454.html.
387 switch (output_channel_layout) {
388 case media::CHANNEL_LAYOUT_5_0:
389 case media::CHANNEL_LAYOUT_5_0_BACK:
390 output_bus->SwapChannels(2, 3);
391 output_bus->SwapChannels(3, 4);
392 break;
393 case media::CHANNEL_LAYOUT_5_1:
394 case media::CHANNEL_LAYOUT_5_1_BACK:
395 case media::CHANNEL_LAYOUT_7_1:
396 output_bus->SwapChannels(2, 4);
397 output_bus->SwapChannels(3, 5);
398 break;
399 default:
400 break;
403 // Note: If this ever changes to output raw float the data must be clipped
404 // and sanitized since it may come from an untrusted source such as NaCl.
405 output_bus->Scale(volume_);
406 output_bus->ToInterleaved(
407 frames_filled, bytes_per_sample_, packet->writable_data());
409 if (packet_size > 0) {
410 packet->set_data_size(packet_size);
411 // Add the packet to the buffer.
412 buffer_->Append(packet);
413 } else {
414 *source_exhausted = true;
419 void AlsaPcmOutputStream::WritePacket() {
420 DCHECK(IsOnAudioThread());
422 // If the device is in error, just eat the bytes.
423 if (stop_stream_) {
424 buffer_->Clear();
425 return;
428 if (state() != kIsPlaying)
429 return;
431 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u);
433 const uint8* buffer_data;
434 int buffer_size;
435 if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) {
436 snd_pcm_sframes_t frames = std::min(
437 static_cast<snd_pcm_sframes_t>(buffer_size / bytes_per_output_frame_),
438 GetAvailableFrames());
440 if (!frames)
441 return;
443 snd_pcm_sframes_t frames_written =
444 wrapper_->PcmWritei(playback_handle_, buffer_data, frames);
445 if (frames_written < 0) {
446 // Attempt once to immediately recover from EINTR,
447 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket
448 // will eventually be called again, so eventual recovery will happen if
449 // muliple retries are required.
450 frames_written = wrapper_->PcmRecover(playback_handle_,
451 frames_written,
452 kPcmRecoverIsSilent);
453 if (frames_written < 0) {
454 if (frames_written != -EAGAIN) {
455 LOG(ERROR) << "Failed to write to pcm device: "
456 << wrapper_->StrError(frames_written);
457 RunErrorCallback(frames_written);
458 stop_stream_ = true;
461 } else {
462 DCHECK_EQ(frames_written, frames);
464 // Seek forward in the buffer after we've written some data to ALSA.
465 buffer_->Seek(frames_written * bytes_per_output_frame_);
467 } else {
468 // If nothing left to write and playback hasn't started yet, start it now.
469 // This ensures that shorter sounds will still play.
470 if (playback_handle_ &&
471 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) &&
472 GetCurrentDelay() > 0) {
473 wrapper_->PcmStart(playback_handle_);
478 void AlsaPcmOutputStream::WriteTask() {
479 DCHECK(IsOnAudioThread());
481 if (stop_stream_)
482 return;
484 if (state() == kIsStopped)
485 return;
487 bool source_exhausted;
488 BufferPacket(&source_exhausted);
489 WritePacket();
491 ScheduleNextWrite(source_exhausted);
494 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
495 DCHECK(IsOnAudioThread());
497 if (stop_stream_ || state() != kIsPlaying)
498 return;
500 const uint32 kTargetFramesAvailable = alsa_buffer_frames_ / 2;
501 uint32 available_frames = GetAvailableFrames();
503 base::TimeDelta next_fill_time;
504 if (buffer_->forward_bytes() && available_frames) {
505 // If we've got data available and ALSA has room, deliver it immediately.
506 next_fill_time = base::TimeDelta();
507 } else if (buffer_->forward_bytes()) {
508 // If we've got data available and no room, poll until room is available.
509 // Polling in this manner allows us to ensure a more consistent callback
510 // schedule. In testing this yields a variance of +/- 5ms versus the non-
511 // polling strategy which is around +/- 30ms and bimodal.
512 next_fill_time = base::TimeDelta::FromMilliseconds(5);
513 } else if (available_frames < kTargetFramesAvailable) {
514 // Schedule the next write for the moment when the available buffer of the
515 // sound card hits |kTargetFramesAvailable|.
516 next_fill_time = FramesToTimeDelta(
517 kTargetFramesAvailable - available_frames, sample_rate_);
518 } else if (!source_exhausted) {
519 // The sound card has |kTargetFramesAvailable| or more frames available.
520 // Invoke the next write immediately to avoid underrun.
521 next_fill_time = base::TimeDelta();
522 } else {
523 // The sound card has frames available, but our source is exhausted, so
524 // avoid busy looping by delaying a bit.
525 next_fill_time = base::TimeDelta::FromMilliseconds(10);
528 message_loop_->PostDelayedTask(FROM_HERE, base::Bind(
529 &AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()),
530 next_fill_time);
533 // static
534 base::TimeDelta AlsaPcmOutputStream::FramesToTimeDelta(int frames,
535 double sample_rate) {
536 return base::TimeDelta::FromMicroseconds(
537 frames * base::Time::kMicrosecondsPerSecond / sample_rate);
540 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) {
541 // Constants specified by the ALSA API for device hints.
542 static const int kGetAllDevices = -1;
543 static const char kPcmInterfaceName[] = "pcm";
544 static const char kIoHintName[] = "IOID";
545 static const char kNameHintName[] = "NAME";
547 const char* wanted_device = GuessSpecificDeviceName(channels);
548 if (!wanted_device)
549 return std::string();
551 std::string guessed_device;
552 void** hints = NULL;
553 int error = wrapper_->DeviceNameHint(kGetAllDevices,
554 kPcmInterfaceName,
555 &hints);
556 if (error == 0) {
557 // NOTE: Do not early return from inside this if statement. The
558 // hints above need to be freed.
559 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
560 // Only examine devices that are output capable.. Valid values are
561 // "Input", "Output", and NULL which means both input and output.
562 scoped_ptr<char, base::FreeDeleter> io(
563 wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName));
564 if (io != NULL && strcmp(io.get(), "Input") == 0)
565 continue;
567 // Attempt to select the closest device for number of channels.
568 scoped_ptr<char, base::FreeDeleter> name(
569 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
570 if (strncmp(wanted_device, name.get(), strlen(wanted_device)) == 0) {
571 guessed_device = name.get();
572 break;
576 // Destroy the hint now that we're done with it.
577 wrapper_->DeviceNameFreeHint(hints);
578 hints = NULL;
579 } else {
580 LOG(ERROR) << "Unable to get hints for devices: "
581 << wrapper_->StrError(error);
584 return guessed_device;
587 snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() {
588 snd_pcm_sframes_t delay = -1;
589 // Don't query ALSA's delay if we have underrun since it'll be jammed at some
590 // non-zero value and potentially even negative!
592 // Also, if we're in the prepared state, don't query because that seems to
593 // cause an I/O error when we do query the delay.
594 snd_pcm_state_t pcm_state = wrapper_->PcmState(playback_handle_);
595 if (pcm_state != SND_PCM_STATE_XRUN &&
596 pcm_state != SND_PCM_STATE_PREPARED) {
597 int error = wrapper_->PcmDelay(playback_handle_, &delay);
598 if (error < 0) {
599 // Assume a delay of zero and attempt to recover the device.
600 delay = -1;
601 error = wrapper_->PcmRecover(playback_handle_,
602 error,
603 kPcmRecoverIsSilent);
604 if (error < 0) {
605 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error);
610 // snd_pcm_delay() sometimes returns crazy values. In this case return delay
611 // of data we know currently is in ALSA's buffer. Note: When the underlying
612 // driver is PulseAudio based, certain configuration settings (e.g., tsched=1)
613 // will generate much larger delay values than |alsa_buffer_frames_|, so only
614 // clip if delay is truly crazy (> 10x expected).
615 if (delay < 0 ||
616 static_cast<snd_pcm_uframes_t>(delay) > alsa_buffer_frames_ * 10) {
617 delay = alsa_buffer_frames_ - GetAvailableFrames();
620 if (delay < 0) {
621 delay = 0;
624 return delay;
627 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() {
628 DCHECK(IsOnAudioThread());
630 if (stop_stream_)
631 return 0;
633 // Find the number of frames queued in the sound device.
634 snd_pcm_sframes_t available_frames =
635 wrapper_->PcmAvailUpdate(playback_handle_);
636 if (available_frames < 0) {
637 available_frames = wrapper_->PcmRecover(playback_handle_,
638 available_frames,
639 kPcmRecoverIsSilent);
641 if (available_frames < 0) {
642 LOG(ERROR) << "Failed querying available frames. Assuming 0: "
643 << wrapper_->StrError(available_frames);
644 return 0;
646 if (static_cast<uint32>(available_frames) > alsa_buffer_frames_ * 2) {
647 LOG(ERROR) << "ALSA returned " << available_frames << " of "
648 << alsa_buffer_frames_ << " frames available.";
649 return alsa_buffer_frames_;
652 return available_frames;
655 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) {
656 // For auto-selection:
657 // 1) Attempt to open a device that best matches the number of channels
658 // requested.
659 // 2) If that fails, attempt the "plug:" version of it in case ALSA can
660 // remap and do some software conversion to make it work.
661 // 3) If that fails, attempt the "plug:" version of the guessed name in
662 // case ALSA can remap and do some software conversion to make it work.
663 // 4) Fallback to kDefaultDevice.
664 // 5) If that fails too, try the "plug:" version of kDefaultDevice.
665 // 6) Give up.
666 snd_pcm_t* handle = NULL;
667 device_name_ = FindDeviceForChannels(channels_);
669 // Step 1.
670 if (!device_name_.empty()) {
671 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
672 channels_, sample_rate_,
673 pcm_format_,
674 latency)) != NULL) {
675 return handle;
678 // Step 2.
679 device_name_ = kPlugPrefix + device_name_;
680 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
681 channels_, sample_rate_,
682 pcm_format_,
683 latency)) != NULL) {
684 return handle;
687 // Step 3.
688 device_name_ = GuessSpecificDeviceName(channels_);
689 if (!device_name_.empty()) {
690 device_name_ = kPlugPrefix + device_name_;
691 if ((handle = alsa_util::OpenPlaybackDevice(
692 wrapper_, device_name_.c_str(), channels_, sample_rate_,
693 pcm_format_, latency)) != NULL) {
694 return handle;
699 // For the kDefaultDevice device, we can only reliably depend on 2-channel
700 // output to have the correct ordering according to Lennart. For the channel
701 // formats that we know how to downmix from (3 channel to 8 channel), setup
702 // downmixing.
703 uint32 default_channels = channels_;
704 if (default_channels > 2) {
705 channel_mixer_.reset(
706 new ChannelMixer(channel_layout_, kDefaultOutputChannelLayout));
707 default_channels = 2;
708 mixed_audio_bus_ = AudioBus::Create(
709 default_channels, audio_bus_->frames());
712 // Step 4.
713 device_name_ = kDefaultDevice;
714 if ((handle = alsa_util::OpenPlaybackDevice(
715 wrapper_, device_name_.c_str(), default_channels, sample_rate_,
716 pcm_format_, latency)) != NULL) {
717 return handle;
720 // Step 5.
721 device_name_ = kPlugPrefix + device_name_;
722 if ((handle = alsa_util::OpenPlaybackDevice(
723 wrapper_, device_name_.c_str(), default_channels, sample_rate_,
724 pcm_format_, latency)) != NULL) {
725 return handle;
728 // Unable to open any device.
729 device_name_.clear();
730 return NULL;
733 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) {
734 switch (state_) {
735 case kCreated:
736 return to == kIsOpened || to == kIsClosed || to == kInError;
738 case kIsOpened:
739 return to == kIsPlaying || to == kIsStopped ||
740 to == kIsClosed || to == kInError;
742 case kIsPlaying:
743 return to == kIsPlaying || to == kIsStopped ||
744 to == kIsClosed || to == kInError;
746 case kIsStopped:
747 return to == kIsPlaying || to == kIsStopped ||
748 to == kIsClosed || to == kInError;
750 case kInError:
751 return to == kIsClosed || to == kInError;
753 case kIsClosed:
754 default:
755 return false;
759 AlsaPcmOutputStream::InternalState
760 AlsaPcmOutputStream::TransitionTo(InternalState to) {
761 DCHECK(IsOnAudioThread());
763 if (!CanTransitionTo(to)) {
764 NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to;
765 state_ = kInError;
766 } else {
767 state_ = to;
769 return state_;
772 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() {
773 return state_;
776 bool AlsaPcmOutputStream::IsOnAudioThread() const {
777 return message_loop_ && message_loop_ == base::MessageLoop::current();
780 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus,
781 uint32 total_bytes_delay) {
782 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback");
784 if (source_callback_)
785 return source_callback_->OnMoreData(audio_bus, total_bytes_delay);
787 return 0;
790 void AlsaPcmOutputStream::RunErrorCallback(int code) {
791 if (source_callback_)
792 source_callback_->OnError(this);
795 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
796 // release ownership of the currently registered callback.
797 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
798 DCHECK(IsOnAudioThread());
799 source_callback_ = callback;
802 } // namespace media