Move media/audio files into media namespace
[chromium-blink-merge.git] / media / audio / linux / alsa_output.cc
blobd940be9e7b1863f34c020207c2f7f803c1a68cd6
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
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/linux/alsa_output.h"
37 #include <algorithm>
39 #include "base/bind.h"
40 #include "base/debug/trace_event.h"
41 #include "base/logging.h"
42 #include "base/message_loop.h"
43 #include "base/stl_util.h"
44 #include "base/time.h"
45 #include "media/audio/audio_util.h"
46 #include "media/audio/linux/alsa_util.h"
47 #include "media/audio/linux/alsa_wrapper.h"
48 #include "media/audio/linux/audio_manager_linux.h"
49 #include "media/base/data_buffer.h"
50 #include "media/base/seekable_buffer.h"
52 namespace media {
54 // Amount of time to wait if we've exhausted the data source. This is to avoid
55 // busy looping.
56 static const uint32 kNoDataSleepMilliseconds = 10;
58 // Mininum interval between OnMoreData() calls.
59 const uint32 kMinIntervalBetweenOnMoreDataCallsInMs = 5;
61 // According to the linux nanosleep manpage, nanosleep on linux can miss the
62 // deadline by up to 10ms because the kernel timeslice is 10ms. Give a 2x
63 // buffer to compensate for the timeslice, and any additional slowdowns.
64 static const uint32 kSleepErrorMilliseconds = 20;
66 // Set to 0 during debugging if you want error messages due to underrun
67 // events or other recoverable errors.
68 #if defined(NDEBUG)
69 static const int kPcmRecoverIsSilent = 1;
70 #else
71 static const int kPcmRecoverIsSilent = 0;
72 #endif
74 // ALSA is currently limited to 48kHz.
75 // TODO(fbarchard): Resample audio from higher frequency to 48000.
76 static const int kAlsaMaxSampleRate = 48000;
78 // While the "default" device may support multi-channel audio, in Alsa, only
79 // the device names surround40, surround41, surround50, etc, have a defined
80 // channel mapping according to Lennart:
82 // http://0pointer.de/blog/projects/guide-to-sound-apis.html
84 // This function makes a best guess at the specific > 2 channel device name
85 // based on the number of channels requested. NULL is returned if no device
86 // can be found to match the channel numbers. In this case, using
87 // kDefaultDevice is probably the best bet.
89 // A five channel source is assumed to be surround50 instead of surround41
90 // (which is also 5 channels).
92 // TODO(ajwong): The source data should have enough info to tell us if we want
93 // surround41 versus surround51, etc., instead of needing us to guess base don
94 // channel number. Fix API to pass that data down.
95 static const char* GuessSpecificDeviceName(uint32 channels) {
96 switch (channels) {
97 case 8:
98 return "surround71";
100 case 7:
101 return "surround70";
103 case 6:
104 return "surround51";
106 case 5:
107 return "surround50";
109 case 4:
110 return "surround40";
112 default:
113 return NULL;
117 std::ostream& operator<<(std::ostream& os,
118 AlsaPcmOutputStream::InternalState state) {
119 switch (state) {
120 case AlsaPcmOutputStream::kInError:
121 os << "kInError";
122 break;
123 case AlsaPcmOutputStream::kCreated:
124 os << "kCreated";
125 break;
126 case AlsaPcmOutputStream::kIsOpened:
127 os << "kIsOpened";
128 break;
129 case AlsaPcmOutputStream::kIsPlaying:
130 os << "kIsPlaying";
131 break;
132 case AlsaPcmOutputStream::kIsStopped:
133 os << "kIsStopped";
134 break;
135 case AlsaPcmOutputStream::kIsClosed:
136 os << "kIsClosed";
137 break;
139 return os;
142 const char AlsaPcmOutputStream::kDefaultDevice[] = "default";
143 const char AlsaPcmOutputStream::kAutoSelectDevice[] = "";
144 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:";
146 // Since we expect to only be able to wake up with a resolution of
147 // kSleepErrorMilliseconds, double that for our minimum required latency.
148 const uint32 AlsaPcmOutputStream::kMinLatencyMicros =
149 kSleepErrorMilliseconds * 2 * 1000;
151 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
152 const AudioParameters& params,
153 AlsaWrapper* wrapper,
154 AudioManagerLinux* manager)
155 : requested_device_name_(device_name),
156 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())),
157 channels_(params.channels()),
158 sample_rate_(params.sample_rate()),
159 bytes_per_sample_(params.bits_per_sample() / 8),
160 bytes_per_frame_(channels_ * params.bits_per_sample() / 8),
161 should_downmix_(false),
162 packet_size_(params.GetBytesPerBuffer()),
163 micros_per_packet_(FramesToMicros(
164 params.frames_per_buffer(), sample_rate_)),
165 latency_micros_(std::max(AlsaPcmOutputStream::kMinLatencyMicros,
166 micros_per_packet_ * 2)),
167 bytes_per_output_frame_(bytes_per_frame_),
168 alsa_buffer_frames_(0),
169 stop_stream_(false),
170 wrapper_(wrapper),
171 manager_(manager),
172 playback_handle_(NULL),
173 frames_per_packet_(packet_size_ / bytes_per_frame_),
174 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
175 state_(kCreated),
176 volume_(1.0f),
177 source_callback_(NULL) {
178 DCHECK(IsOnAudioThread());
180 // Sanity check input values.
181 if (params.sample_rate() > kAlsaMaxSampleRate ||
182 params.sample_rate() <= 0) {
183 LOG(WARNING) << "Unsupported audio frequency.";
184 TransitionTo(kInError);
187 if (AudioParameters::AUDIO_PCM_LINEAR != params.format() &&
188 AudioParameters::AUDIO_PCM_LOW_LATENCY != params.format()) {
189 LOG(WARNING) << "Unsupported audio format";
190 TransitionTo(kInError);
193 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) {
194 LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample();
195 TransitionTo(kInError);
199 AlsaPcmOutputStream::~AlsaPcmOutputStream() {
200 InternalState current_state = state();
201 DCHECK(current_state == kCreated ||
202 current_state == kIsClosed ||
203 current_state == kInError);
204 DCHECK(!playback_handle_);
207 bool AlsaPcmOutputStream::Open() {
208 DCHECK(IsOnAudioThread());
210 if (state() == kInError)
211 return false;
213 if (!CanTransitionTo(kIsOpened)) {
214 NOTREACHED() << "Invalid state: " << state();
215 return false;
218 // We do not need to check if the transition was successful because
219 // CanTransitionTo() was checked above, and it is assumed that this
220 // object's public API is only called on one thread so the state cannot
221 // transition out from under us.
222 TransitionTo(kIsOpened);
224 // Try to open the device.
225 if (requested_device_name_ == kAutoSelectDevice) {
226 playback_handle_ = AutoSelectDevice(latency_micros_);
227 if (playback_handle_)
228 DVLOG(1) << "Auto-selected device: " << device_name_;
229 } else {
230 device_name_ = requested_device_name_;
231 playback_handle_ = alsa_util::OpenPlaybackDevice(
232 wrapper_, device_name_.c_str(), channels_, sample_rate_,
233 pcm_format_, latency_micros_);
236 // Finish initializing the stream if the device was opened successfully.
237 if (playback_handle_ == NULL) {
238 stop_stream_ = true;
239 TransitionTo(kInError);
240 return false;
241 } else {
242 bytes_per_output_frame_ = should_downmix_ ? 2 * bytes_per_sample_ :
243 bytes_per_frame_;
244 uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_;
245 buffer_.reset(new media::SeekableBuffer(0, output_packet_size));
247 // Get alsa buffer size.
248 snd_pcm_uframes_t buffer_size;
249 snd_pcm_uframes_t period_size;
250 int error = wrapper_->PcmGetParams(playback_handle_, &buffer_size,
251 &period_size);
252 if (error < 0) {
253 LOG(ERROR) << "Failed to get playback buffer size from ALSA: "
254 << wrapper_->StrError(error);
255 // Buffer size is at least twice of packet size.
256 alsa_buffer_frames_ = frames_per_packet_ * 2;
257 } else {
258 alsa_buffer_frames_ = buffer_size;
262 return true;
265 void AlsaPcmOutputStream::Close() {
266 DCHECK(IsOnAudioThread());
268 if (state() != kIsClosed)
269 TransitionTo(kIsClosed);
271 // Shutdown the audio device.
272 if (playback_handle_) {
273 if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) {
274 LOG(WARNING) << "Unable to close audio device. Leaking handle.";
276 playback_handle_ = NULL;
278 // Release the buffer.
279 buffer_.reset();
281 // Signal anything that might already be scheduled to stop.
282 stop_stream_ = true; // Not necessary in production, but unit tests
283 // uses the flag to verify that stream was closed.
286 weak_factory_.InvalidateWeakPtrs();
288 // Signal to the manager that we're closed and can be removed.
289 // Should be last call in the method as it deletes "this".
290 manager_->ReleaseOutputStream(this);
293 void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
294 DCHECK(IsOnAudioThread());
296 CHECK(callback);
298 if (stop_stream_)
299 return;
301 set_source_callback(callback);
303 // Only post the task if we can enter the playing state.
304 if (TransitionTo(kIsPlaying) == kIsPlaying) {
305 // Before starting, the buffer might have audio from previous user of this
306 // device.
307 buffer_->Clear();
309 // When starting again, drop all packets in the device and prepare it again
310 // in case we are restarting from a pause state and need to flush old data.
311 int error = wrapper_->PcmDrop(playback_handle_);
312 if (error < 0 && error != -EAGAIN) {
313 LOG(ERROR) << "Failure clearing playback device ("
314 << wrapper_->PcmName(playback_handle_) << "): "
315 << wrapper_->StrError(error);
316 stop_stream_ = true;
317 } else {
318 error = wrapper_->PcmPrepare(playback_handle_);
319 if (error < 0 && error != -EAGAIN) {
320 LOG(ERROR) << "Failure preparing stream ("
321 << wrapper_->PcmName(playback_handle_) << "): "
322 << wrapper_->StrError(error);
323 stop_stream_ = true;
327 if (!stop_stream_)
328 ScheduleNextWrite(false);
332 void AlsaPcmOutputStream::Stop() {
333 DCHECK(IsOnAudioThread());
335 // Reset the callback, so that it is not called anymore.
336 set_source_callback(NULL);
338 TransitionTo(kIsStopped);
341 void AlsaPcmOutputStream::SetVolume(double volume) {
342 DCHECK(IsOnAudioThread());
344 volume_ = static_cast<float>(volume);
347 void AlsaPcmOutputStream::GetVolume(double* volume) {
348 DCHECK(IsOnAudioThread());
350 *volume = volume_;
353 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
354 DCHECK(IsOnAudioThread());
356 // If stopped, simulate a 0-length packet.
357 if (stop_stream_) {
358 buffer_->Clear();
359 *source_exhausted = true;
360 return;
363 *source_exhausted = false;
365 // Request more data only when we run out of data in the buffer, because
366 // WritePacket() comsumes only the current chunk of data.
367 if (!buffer_->forward_bytes()) {
368 // Before making a request to source for data we need to determine the
369 // delay (in bytes) for the requested data to be played.
371 uint32 buffer_delay = buffer_->forward_bytes() * bytes_per_frame_ /
372 bytes_per_output_frame_;
374 uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_;
376 scoped_refptr<media::DataBuffer> packet =
377 new media::DataBuffer(packet_size_);
378 int packet_size = RunDataCallback(packet->GetWritableData(),
379 packet->GetBufferSize(),
380 AudioBuffersState(buffer_delay,
381 hardware_delay));
382 CHECK_LE(packet_size, packet->GetBufferSize());
384 // This should not happen, but in case it does, drop any trailing bytes
385 // that aren't large enough to make a frame. Without this, packet writing
386 // may stall because the last few bytes in the packet may never get used by
387 // WritePacket.
388 DCHECK(packet_size % bytes_per_frame_ == 0);
389 packet_size = (packet_size / bytes_per_frame_) * bytes_per_frame_;
391 if (should_downmix_) {
392 if (media::FoldChannels(packet->GetWritableData(),
393 packet_size,
394 channels_,
395 bytes_per_sample_,
396 volume_)) {
397 // Adjust packet size for downmix.
398 packet_size = packet_size / bytes_per_frame_ * bytes_per_output_frame_;
399 } else {
400 LOG(ERROR) << "Folding failed";
402 } else {
403 media::AdjustVolume(packet->GetWritableData(),
404 packet_size,
405 channels_,
406 bytes_per_sample_,
407 volume_);
410 if (packet_size > 0) {
411 packet->SetDataSize(packet_size);
412 // Add the packet to the buffer.
413 buffer_->Append(packet);
414 } else {
415 *source_exhausted = true;
420 void AlsaPcmOutputStream::WritePacket() {
421 DCHECK(IsOnAudioThread());
423 // If the device is in error, just eat the bytes.
424 if (stop_stream_) {
425 buffer_->Clear();
426 return;
429 if (state() == kIsStopped)
430 return;
432 CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u);
434 const uint8* buffer_data;
435 int buffer_size;
436 if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) {
437 buffer_size = buffer_size - (buffer_size % bytes_per_output_frame_);
438 snd_pcm_sframes_t frames = buffer_size / bytes_per_output_frame_;
440 DCHECK_GT(frames, 0);
442 snd_pcm_sframes_t frames_written =
443 wrapper_->PcmWritei(playback_handle_, buffer_data, frames);
444 if (frames_written < 0) {
445 // Attempt once to immediately recover from EINTR,
446 // EPIPE (overrun/underrun), ESTRPIPE (stream suspended). WritePacket
447 // will eventually be called again, so eventual recovery will happen if
448 // muliple retries are required.
449 frames_written = wrapper_->PcmRecover(playback_handle_,
450 frames_written,
451 kPcmRecoverIsSilent);
454 if (frames_written < 0) {
455 // TODO(ajwong): Is EAGAIN the only error we want to except from stopping
456 // the pcm playback?
457 if (frames_written != -EAGAIN) {
458 LOG(ERROR) << "Failed to write to pcm device: "
459 << wrapper_->StrError(frames_written);
460 RunErrorCallback(frames_written);
461 stop_stream_ = true;
463 } else {
464 if (frames_written > frames) {
465 LOG(WARNING)
466 << "snd_pcm_writei() has written more frame that we asked.";
467 frames_written = frames;
470 // Seek forward in the buffer after we've written some data to ALSA.
471 buffer_->Seek(frames_written * bytes_per_output_frame_);
473 } else {
474 // If nothing left to write and playback hasn't started yet, start it now.
475 // This ensures that shorter sounds will still play.
476 if (playback_handle_ &&
477 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) &&
478 GetCurrentDelay() > 0) {
479 wrapper_->PcmStart(playback_handle_);
484 void AlsaPcmOutputStream::WriteTask() {
485 DCHECK(IsOnAudioThread());
487 if (stop_stream_)
488 return;
490 if (state() == kIsStopped)
491 return;
493 bool source_exhausted;
494 BufferPacket(&source_exhausted);
495 WritePacket();
497 ScheduleNextWrite(source_exhausted);
500 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
501 DCHECK(IsOnAudioThread());
503 if (stop_stream_)
504 return;
506 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2;
507 uint32 available_frames = GetAvailableFrames();
508 uint32 frames_in_buffer = buffer_->forward_bytes() / bytes_per_output_frame_;
510 // Next write is initially scheduled for the moment when half of a packet
511 // has been played out.
512 uint32 next_fill_time_ms =
513 FramesToMillis(frames_per_packet_ / 2, sample_rate_);
515 if (frames_in_buffer && (frames_in_buffer <= available_frames)) {
516 // There is data in the current buffer, consume them immediately if we have
517 // enough space in the soundcard.
518 next_fill_time_ms = 0;
519 } else {
520 // Otherwise schedule the next write for the moment when half of the alsa
521 // buffer becomes available.
522 if (available_frames < frames_avail_wanted) {
523 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames;
524 next_fill_time_ms =
525 FramesToMillis(frames_until_empty_enough, sample_rate_);
527 // Adjust for time resolution.
528 if (next_fill_time_ms > kNoDataSleepMilliseconds)
529 next_fill_time_ms -= kNoDataSleepMilliseconds;
531 // Avoid back-to-back writing.
532 if (next_fill_time_ms < kMinIntervalBetweenOnMoreDataCallsInMs)
533 next_fill_time_ms = kMinIntervalBetweenOnMoreDataCallsInMs;
534 } else if (available_frames == alsa_buffer_frames_) {
535 // Buffer is empty, invoke next write immediately.
536 next_fill_time_ms = 0;
540 // Avoid busy looping if the data source is exhausted.
541 if (source_exhausted)
542 next_fill_time_ms = std::max(next_fill_time_ms, kNoDataSleepMilliseconds);
544 // Only schedule more reads/writes if we are still in the playing state.
545 if (state() == kIsPlaying) {
546 if (next_fill_time_ms == 0) {
547 manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
548 &AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()));
549 } else {
550 // TODO(ajwong): Measure the reliability of the delay interval. Use
551 // base/metrics/histogram.h.
552 manager_->GetMessageLoop()->PostDelayedTask(
553 FROM_HERE,
554 base::Bind(&AlsaPcmOutputStream::WriteTask,
555 weak_factory_.GetWeakPtr()),
556 base::TimeDelta::FromMilliseconds(next_fill_time_ms));
561 uint32 AlsaPcmOutputStream::FramesToMicros(uint32 frames,
562 uint32 sample_rate) {
563 return frames * base::Time::kMicrosecondsPerSecond / sample_rate;
566 uint32 AlsaPcmOutputStream::FramesToMillis(uint32 frames,
567 uint32 sample_rate) {
568 return frames * base::Time::kMillisecondsPerSecond / sample_rate;
571 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) {
572 // Constants specified by the ALSA API for device hints.
573 static const int kGetAllDevices = -1;
574 static const char kPcmInterfaceName[] = "pcm";
575 static const char kIoHintName[] = "IOID";
576 static const char kNameHintName[] = "NAME";
578 const char* wanted_device = GuessSpecificDeviceName(channels);
579 if (!wanted_device)
580 return "";
582 std::string guessed_device;
583 void** hints = NULL;
584 int error = wrapper_->DeviceNameHint(kGetAllDevices,
585 kPcmInterfaceName,
586 &hints);
587 if (error == 0) {
588 // NOTE: Do not early return from inside this if statement. The
589 // hints above need to be freed.
590 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
591 // Only examine devices that are output capable.. Valid values are
592 // "Input", "Output", and NULL which means both input and output.
593 scoped_ptr_malloc<char> io(
594 wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName));
595 if (io != NULL && strcmp(io.get(), "Input") == 0)
596 continue;
598 // Attempt to select the closest device for number of channels.
599 scoped_ptr_malloc<char> name(
600 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
601 if (strncmp(wanted_device, name.get(), strlen(wanted_device)) == 0) {
602 guessed_device = name.get();
603 break;
607 // Destroy the hint now that we're done with it.
608 wrapper_->DeviceNameFreeHint(hints);
609 hints = NULL;
610 } else {
611 LOG(ERROR) << "Unable to get hints for devices: "
612 << wrapper_->StrError(error);
615 return guessed_device;
618 snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() {
619 snd_pcm_sframes_t delay = -1;
621 // Don't query ALSA's delay if we have underrun since it'll be jammed at
622 // some non-zero value and potentially even negative!
623 if (wrapper_->PcmState(playback_handle_) != SND_PCM_STATE_XRUN) {
624 int error = wrapper_->PcmDelay(playback_handle_, &delay);
625 if (error < 0) {
626 // Assume a delay of zero and attempt to recover the device.
627 delay = -1;
628 error = wrapper_->PcmRecover(playback_handle_,
629 error,
630 kPcmRecoverIsSilent);
631 if (error < 0) {
632 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error);
637 // snd_pcm_delay() may not work in the beginning of the stream. In this case
638 // return delay of data we know currently is in the ALSA's buffer.
639 if (delay < 0)
640 delay = alsa_buffer_frames_ - GetAvailableFrames();
642 return delay;
645 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() {
646 DCHECK(IsOnAudioThread());
648 if (stop_stream_)
649 return 0;
651 // Find the number of frames queued in the sound device.
652 snd_pcm_sframes_t available_frames =
653 wrapper_->PcmAvailUpdate(playback_handle_);
654 if (available_frames < 0) {
655 available_frames = wrapper_->PcmRecover(playback_handle_,
656 available_frames,
657 kPcmRecoverIsSilent);
659 if (available_frames < 0) {
660 LOG(ERROR) << "Failed querying available frames. Assuming 0: "
661 << wrapper_->StrError(available_frames);
662 return 0;
665 return available_frames;
668 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) {
669 // For auto-selection:
670 // 1) Attempt to open a device that best matches the number of channels
671 // requested.
672 // 2) If that fails, attempt the "plug:" version of it in case ALSA can
673 // remap do some software conversion to make it work.
674 // 3) Fallback to kDefaultDevice.
675 // 4) If that fails too, try the "plug:" version of kDefaultDevice.
676 // 5) Give up.
677 snd_pcm_t* handle = NULL;
678 device_name_ = FindDeviceForChannels(channels_);
680 // Step 1.
681 if (!device_name_.empty()) {
682 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
683 channels_, sample_rate_,
684 pcm_format_,
685 latency)) != NULL) {
686 return handle;
689 // Step 2.
690 device_name_ = kPlugPrefix + device_name_;
691 if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
692 channels_, sample_rate_,
693 pcm_format_,
694 latency)) != NULL) {
695 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.
704 // TODO(ajwong): We need a SupportsFolding() function.
705 uint32 default_channels = channels_;
706 if (default_channels > 2 && default_channels <= 8) {
707 should_downmix_ = true;
708 default_channels = 2;
711 // Step 3.
712 device_name_ = kDefaultDevice;
713 if ((handle = alsa_util::OpenPlaybackDevice(
714 wrapper_, device_name_.c_str(), default_channels, sample_rate_,
715 pcm_format_, latency)) != NULL) {
716 return handle;
719 // Step 4.
720 device_name_ = kPlugPrefix + device_name_;
721 if ((handle = alsa_util::OpenPlaybackDevice(
722 wrapper_, device_name_.c_str(), default_channels, sample_rate_,
723 pcm_format_, latency)) != NULL) {
724 return handle;
727 // Unable to open any device.
728 device_name_.clear();
729 return NULL;
732 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) {
733 switch (state_) {
734 case kCreated:
735 return to == kIsOpened || to == kIsClosed || to == kInError;
737 case kIsOpened:
738 return to == kIsPlaying || to == kIsStopped ||
739 to == kIsClosed || to == kInError;
741 case kIsPlaying:
742 return to == kIsPlaying || to == kIsStopped ||
743 to == kIsClosed || to == kInError;
745 case kIsStopped:
746 return to == kIsPlaying || to == kIsStopped ||
747 to == kIsClosed || to == kInError;
749 case kInError:
750 return to == kIsClosed || to == kInError;
752 case kIsClosed:
753 default:
754 return false;
758 AlsaPcmOutputStream::InternalState
759 AlsaPcmOutputStream::TransitionTo(InternalState to) {
760 DCHECK(IsOnAudioThread());
762 if (!CanTransitionTo(to)) {
763 NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to;
764 state_ = kInError;
765 } else {
766 state_ = to;
768 return state_;
771 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() {
772 return state_;
775 bool AlsaPcmOutputStream::IsOnAudioThread() const {
776 return !manager_->GetMessageLoop() ||
777 manager_->GetMessageLoop()->BelongsToCurrentThread();
780 uint32 AlsaPcmOutputStream::RunDataCallback(uint8* dest,
781 uint32 max_size,
782 AudioBuffersState buffers_state) {
783 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback");
785 if (source_callback_)
786 return source_callback_->OnMoreData(this, dest, max_size, buffers_state);
788 return 0;
791 void AlsaPcmOutputStream::RunErrorCallback(int code) {
792 if (source_callback_)
793 source_callback_->OnError(this, code);
796 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
797 // release ownership of the currently registered callback.
798 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
799 DCHECK(IsOnAudioThread());
800 source_callback_ = callback;
803 } // namespace media