• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()
11 //
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.
15 //
16 //
17 // SEMANTICS OF ERROR STATES
18 //
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.
23 //
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.
29 //
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.
34 
35 #include "media/audio/alsa/alsa_output.h"
36 
37 #include <algorithm>
38 
39 #include "base/bind.h"
40 #include "base/debug/trace_event.h"
41 #include "base/logging.h"
42 #include "base/stl_util.h"
43 #include "base/time/time.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"
50 
51 namespace media {
52 
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
60 
61 // While the "default" device may support multi-channel audio, in Alsa, only
62 // the device names surround40, surround41, surround50, etc, have a defined
63 // channel mapping according to Lennart:
64 //
65 // http://0pointer.de/blog/projects/guide-to-sound-apis.html
66 //
67 // This function makes a best guess at the specific > 2 channel device name
68 // based on the number of channels requested.  NULL is returned if no device
69 // can be found to match the channel numbers.  In this case, using
70 // kDefaultDevice is probably the best bet.
71 //
72 // A five channel source is assumed to be surround50 instead of surround41
73 // (which is also 5 channels).
74 //
75 // TODO(ajwong): The source data should have enough info to tell us if we want
76 // surround41 versus surround51, etc., instead of needing us to guess based on
77 // channel number.  Fix API to pass that data down.
GuessSpecificDeviceName(uint32 channels)78 static const char* GuessSpecificDeviceName(uint32 channels) {
79   switch (channels) {
80     case 8:
81       return "surround71";
82 
83     case 7:
84       return "surround70";
85 
86     case 6:
87       return "surround51";
88 
89     case 5:
90       return "surround50";
91 
92     case 4:
93       return "surround40";
94 
95     default:
96       return NULL;
97   }
98 }
99 
operator <<(std::ostream & os,AlsaPcmOutputStream::InternalState state)100 std::ostream& operator<<(std::ostream& os,
101                          AlsaPcmOutputStream::InternalState state) {
102   switch (state) {
103     case AlsaPcmOutputStream::kInError:
104       os << "kInError";
105       break;
106     case AlsaPcmOutputStream::kCreated:
107       os << "kCreated";
108       break;
109     case AlsaPcmOutputStream::kIsOpened:
110       os << "kIsOpened";
111       break;
112     case AlsaPcmOutputStream::kIsPlaying:
113       os << "kIsPlaying";
114       break;
115     case AlsaPcmOutputStream::kIsStopped:
116       os << "kIsStopped";
117       break;
118     case AlsaPcmOutputStream::kIsClosed:
119       os << "kIsClosed";
120       break;
121   };
122   return os;
123 }
124 
125 const char AlsaPcmOutputStream::kDefaultDevice[] = "default";
126 const char AlsaPcmOutputStream::kAutoSelectDevice[] = "";
127 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:";
128 
129 // We use 40ms as our minimum required latency. If it is needed, we may be able
130 // to get it down to 20ms.
131 const uint32 AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000;
132 
AlsaPcmOutputStream(const std::string & device_name,const AudioParameters & params,AlsaWrapper * wrapper,AudioManagerBase * manager)133 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
134                                          const AudioParameters& params,
135                                          AlsaWrapper* wrapper,
136                                          AudioManagerBase* manager)
137     : requested_device_name_(device_name),
138       pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())),
139       channels_(params.channels()),
140       channel_layout_(params.channel_layout()),
141       sample_rate_(params.sample_rate()),
142       bytes_per_sample_(params.bits_per_sample() / 8),
143       bytes_per_frame_(params.GetBytesPerFrame()),
144       packet_size_(params.GetBytesPerBuffer()),
145       latency_(std::max(
146           base::TimeDelta::FromMicroseconds(kMinLatencyMicros),
147           FramesToTimeDelta(params.frames_per_buffer() * 2, sample_rate_))),
148       bytes_per_output_frame_(bytes_per_frame_),
149       alsa_buffer_frames_(0),
150       stop_stream_(false),
151       wrapper_(wrapper),
152       manager_(manager),
153       message_loop_(base::MessageLoop::current()),
154       playback_handle_(NULL),
155       frames_per_packet_(packet_size_ / bytes_per_frame_),
156       state_(kCreated),
157       volume_(1.0f),
158       source_callback_(NULL),
159       audio_bus_(AudioBus::Create(params)),
160       weak_factory_(this) {
161   DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
162   DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_);
163 
164   // Sanity check input values.
165   if (!params.IsValid()) {
166     LOG(WARNING) << "Unsupported audio parameters.";
167     TransitionTo(kInError);
168   }
169 
170   if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) {
171     LOG(WARNING) << "Unsupported bits per sample: " << params.bits_per_sample();
172     TransitionTo(kInError);
173   }
174 }
175 
~AlsaPcmOutputStream()176 AlsaPcmOutputStream::~AlsaPcmOutputStream() {
177   InternalState current_state = state();
178   DCHECK(current_state == kCreated ||
179          current_state == kIsClosed ||
180          current_state == kInError);
181   DCHECK(!playback_handle_);
182 }
183 
Open()184 bool AlsaPcmOutputStream::Open() {
185   DCHECK(IsOnAudioThread());
186 
187   if (state() == kInError)
188     return false;
189 
190   if (!CanTransitionTo(kIsOpened)) {
191     NOTREACHED() << "Invalid state: " << state();
192     return false;
193   }
194 
195   // We do not need to check if the transition was successful because
196   // CanTransitionTo() was checked above, and it is assumed that this
197   // object's public API is only called on one thread so the state cannot
198   // transition out from under us.
199   TransitionTo(kIsOpened);
200 
201   // Try to open the device.
202   if (requested_device_name_ == kAutoSelectDevice) {
203     playback_handle_ = AutoSelectDevice(latency_.InMicroseconds());
204     if (playback_handle_)
205       DVLOG(1) << "Auto-selected device: " << device_name_;
206   } else {
207     device_name_ = requested_device_name_;
208     playback_handle_ = alsa_util::OpenPlaybackDevice(
209         wrapper_, device_name_.c_str(), channels_, sample_rate_,
210         pcm_format_, latency_.InMicroseconds());
211   }
212 
213   // Finish initializing the stream if the device was opened successfully.
214   if (playback_handle_ == NULL) {
215     stop_stream_ = true;
216     TransitionTo(kInError);
217     return false;
218   } else {
219     bytes_per_output_frame_ = channel_mixer_ ?
220         mixed_audio_bus_->channels() * bytes_per_sample_ : bytes_per_frame_;
221     uint32 output_packet_size = frames_per_packet_ * bytes_per_output_frame_;
222     buffer_.reset(new media::SeekableBuffer(0, output_packet_size));
223 
224     // Get alsa buffer size.
225     snd_pcm_uframes_t buffer_size;
226     snd_pcm_uframes_t period_size;
227     int error = wrapper_->PcmGetParams(playback_handle_, &buffer_size,
228                                        &period_size);
229     if (error < 0) {
230       LOG(ERROR) << "Failed to get playback buffer size from ALSA: "
231                  << wrapper_->StrError(error);
232       // Buffer size is at least twice of packet size.
233       alsa_buffer_frames_ = frames_per_packet_ * 2;
234     } else {
235       alsa_buffer_frames_ = buffer_size;
236     }
237   }
238 
239   return true;
240 }
241 
Close()242 void AlsaPcmOutputStream::Close() {
243   DCHECK(IsOnAudioThread());
244 
245   if (state() != kIsClosed)
246     TransitionTo(kIsClosed);
247 
248   // Shutdown the audio device.
249   if (playback_handle_) {
250     if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) {
251       LOG(WARNING) << "Unable to close audio device. Leaking handle.";
252     }
253     playback_handle_ = NULL;
254 
255     // Release the buffer.
256     buffer_.reset();
257 
258     // Signal anything that might already be scheduled to stop.
259     stop_stream_ = true;  // Not necessary in production, but unit tests
260                           // uses the flag to verify that stream was closed.
261   }
262 
263   weak_factory_.InvalidateWeakPtrs();
264 
265   // Signal to the manager that we're closed and can be removed.
266   // Should be last call in the method as it deletes "this".
267   manager_->ReleaseOutputStream(this);
268 }
269 
Start(AudioSourceCallback * callback)270 void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) {
271   DCHECK(IsOnAudioThread());
272 
273   CHECK(callback);
274 
275   if (stop_stream_)
276     return;
277 
278   // Only post the task if we can enter the playing state.
279   if (TransitionTo(kIsPlaying) != kIsPlaying)
280     return;
281 
282   // Before starting, the buffer might have audio from previous user of this
283   // device.
284   buffer_->Clear();
285 
286   // When starting again, drop all packets in the device and prepare it again
287   // in case we are restarting from a pause state and need to flush old data.
288   int error = wrapper_->PcmDrop(playback_handle_);
289   if (error < 0 && error != -EAGAIN) {
290     LOG(ERROR) << "Failure clearing playback device ("
291                << wrapper_->PcmName(playback_handle_) << "): "
292                << wrapper_->StrError(error);
293     stop_stream_ = true;
294     return;
295   }
296 
297   error = wrapper_->PcmPrepare(playback_handle_);
298   if (error < 0 && error != -EAGAIN) {
299     LOG(ERROR) << "Failure preparing stream ("
300                << wrapper_->PcmName(playback_handle_) << "): "
301                << wrapper_->StrError(error);
302     stop_stream_ = true;
303     return;
304   }
305 
306   // Ensure the first buffer is silence to avoid startup glitches.
307   int buffer_size = GetAvailableFrames() * bytes_per_output_frame_;
308   scoped_refptr<DataBuffer> silent_packet = new DataBuffer(buffer_size);
309   silent_packet->set_data_size(buffer_size);
310   memset(silent_packet->writable_data(), 0, silent_packet->data_size());
311   buffer_->Append(silent_packet);
312   WritePacket();
313 
314   // Start the callback chain.
315   set_source_callback(callback);
316   WriteTask();
317 }
318 
Stop()319 void AlsaPcmOutputStream::Stop() {
320   DCHECK(IsOnAudioThread());
321 
322   // Reset the callback, so that it is not called anymore.
323   set_source_callback(NULL);
324   weak_factory_.InvalidateWeakPtrs();
325 
326   TransitionTo(kIsStopped);
327 }
328 
SetVolume(double volume)329 void AlsaPcmOutputStream::SetVolume(double volume) {
330   DCHECK(IsOnAudioThread());
331 
332   volume_ = static_cast<float>(volume);
333 }
334 
GetVolume(double * volume)335 void AlsaPcmOutputStream::GetVolume(double* volume) {
336   DCHECK(IsOnAudioThread());
337 
338   *volume = volume_;
339 }
340 
BufferPacket(bool * source_exhausted)341 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
342   DCHECK(IsOnAudioThread());
343 
344   // If stopped, simulate a 0-length packet.
345   if (stop_stream_) {
346     buffer_->Clear();
347     *source_exhausted = true;
348     return;
349   }
350 
351   *source_exhausted = false;
352 
353   // Request more data only when we run out of data in the buffer, because
354   // WritePacket() comsumes only the current chunk of data.
355   if (!buffer_->forward_bytes()) {
356     // Before making a request to source for data we need to determine the
357     // delay (in bytes) for the requested data to be played.
358     const uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_;
359 
360     scoped_refptr<media::DataBuffer> packet =
361         new media::DataBuffer(packet_size_);
362     int frames_filled = RunDataCallback(
363         audio_bus_.get(), AudioBuffersState(0, hardware_delay));
364 
365     size_t packet_size = frames_filled * bytes_per_frame_;
366     DCHECK_LE(packet_size, packet_size_);
367 
368     // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer;
369     // volume adjust should use SSE optimized vector_fmul() prior to interleave.
370     AudioBus* output_bus = audio_bus_.get();
371     if (channel_mixer_) {
372       output_bus = mixed_audio_bus_.get();
373       channel_mixer_->Transform(audio_bus_.get(), output_bus);
374       // Adjust packet size for downmix.
375       packet_size = packet_size / bytes_per_frame_ * bytes_per_output_frame_;
376     }
377 
378     // Note: If this ever changes to output raw float the data must be clipped
379     // and sanitized since it may come from an untrusted source such as NaCl.
380     output_bus->Scale(volume_);
381     output_bus->ToInterleaved(
382         frames_filled, bytes_per_sample_, packet->writable_data());
383 
384     if (packet_size > 0) {
385       packet->set_data_size(packet_size);
386       // Add the packet to the buffer.
387       buffer_->Append(packet);
388     } else {
389       *source_exhausted = true;
390     }
391   }
392 }
393 
WritePacket()394 void AlsaPcmOutputStream::WritePacket() {
395   DCHECK(IsOnAudioThread());
396 
397   // If the device is in error, just eat the bytes.
398   if (stop_stream_) {
399     buffer_->Clear();
400     return;
401   }
402 
403   if (state() != kIsPlaying)
404     return;
405 
406   CHECK_EQ(buffer_->forward_bytes() % bytes_per_output_frame_, 0u);
407 
408   const uint8* buffer_data;
409   int buffer_size;
410   if (buffer_->GetCurrentChunk(&buffer_data, &buffer_size)) {
411     buffer_size = buffer_size - (buffer_size % bytes_per_output_frame_);
412     snd_pcm_sframes_t frames = std::min(
413         static_cast<snd_pcm_sframes_t>(buffer_size / bytes_per_output_frame_),
414         GetAvailableFrames());
415 
416     if (!frames)
417       return;
418 
419     snd_pcm_sframes_t frames_written =
420         wrapper_->PcmWritei(playback_handle_, buffer_data, frames);
421     if (frames_written < 0) {
422       // Attempt once to immediately recover from EINTR,
423       // EPIPE (overrun/underrun), ESTRPIPE (stream suspended).  WritePacket
424       // will eventually be called again, so eventual recovery will happen if
425       // muliple retries are required.
426       frames_written = wrapper_->PcmRecover(playback_handle_,
427                                             frames_written,
428                                             kPcmRecoverIsSilent);
429       if (frames_written < 0) {
430         if (frames_written != -EAGAIN) {
431           LOG(ERROR) << "Failed to write to pcm device: "
432                      << wrapper_->StrError(frames_written);
433           RunErrorCallback(frames_written);
434           stop_stream_ = true;
435         }
436       }
437     } else {
438       DCHECK_EQ(frames_written, frames);
439 
440       // Seek forward in the buffer after we've written some data to ALSA.
441       buffer_->Seek(frames_written * bytes_per_output_frame_);
442     }
443   } else {
444     // If nothing left to write and playback hasn't started yet, start it now.
445     // This ensures that shorter sounds will still play.
446     if (playback_handle_ &&
447         (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) &&
448         GetCurrentDelay() > 0) {
449       wrapper_->PcmStart(playback_handle_);
450     }
451   }
452 }
453 
WriteTask()454 void AlsaPcmOutputStream::WriteTask() {
455   DCHECK(IsOnAudioThread());
456 
457   if (stop_stream_)
458     return;
459 
460   if (state() == kIsStopped)
461     return;
462 
463   bool source_exhausted;
464   BufferPacket(&source_exhausted);
465   WritePacket();
466 
467   ScheduleNextWrite(source_exhausted);
468 }
469 
ScheduleNextWrite(bool source_exhausted)470 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
471   DCHECK(IsOnAudioThread());
472 
473   if (stop_stream_ || state() != kIsPlaying)
474     return;
475 
476   const uint32 kTargetFramesAvailable = alsa_buffer_frames_ / 2;
477   uint32 available_frames = GetAvailableFrames();
478 
479   base::TimeDelta next_fill_time;
480   if (buffer_->forward_bytes() && available_frames) {
481     // If we've got data available and ALSA has room, deliver it immediately.
482     next_fill_time = base::TimeDelta();
483   } else if (buffer_->forward_bytes()) {
484     // If we've got data available and no room, poll until room is available.
485     // Polling in this manner allows us to ensure a more consistent callback
486     // schedule.  In testing this yields a variance of +/- 5ms versus the non-
487     // polling strategy which is around +/- 30ms and bimodal.
488     next_fill_time = base::TimeDelta::FromMilliseconds(5);
489   } else if (available_frames < kTargetFramesAvailable) {
490     // Schedule the next write for the moment when the available buffer of the
491     // sound card hits |kTargetFramesAvailable|.
492     next_fill_time = FramesToTimeDelta(
493         kTargetFramesAvailable - available_frames, sample_rate_);
494   } else if (!source_exhausted) {
495     // The sound card has |kTargetFramesAvailable| or more frames available.
496     // Invoke the next write immediately to avoid underrun.
497     next_fill_time = base::TimeDelta();
498   } else {
499     // The sound card has frames available, but our source is exhausted, so
500     // avoid busy looping by delaying a bit.
501     next_fill_time = base::TimeDelta::FromMilliseconds(10);
502   }
503 
504   message_loop_->PostDelayedTask(FROM_HERE, base::Bind(
505       &AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()),
506       next_fill_time);
507 }
508 
509 // static
FramesToTimeDelta(int frames,double sample_rate)510 base::TimeDelta AlsaPcmOutputStream::FramesToTimeDelta(int frames,
511                                                        double sample_rate) {
512   return base::TimeDelta::FromMicroseconds(
513       frames * base::Time::kMicrosecondsPerSecond / sample_rate);
514 }
515 
FindDeviceForChannels(uint32 channels)516 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32 channels) {
517   // Constants specified by the ALSA API for device hints.
518   static const int kGetAllDevices = -1;
519   static const char kPcmInterfaceName[] = "pcm";
520   static const char kIoHintName[] = "IOID";
521   static const char kNameHintName[] = "NAME";
522 
523   const char* wanted_device = GuessSpecificDeviceName(channels);
524   if (!wanted_device)
525     return std::string();
526 
527   std::string guessed_device;
528   void** hints = NULL;
529   int error = wrapper_->DeviceNameHint(kGetAllDevices,
530                                        kPcmInterfaceName,
531                                        &hints);
532   if (error == 0) {
533     // NOTE: Do not early return from inside this if statement.  The
534     // hints above need to be freed.
535     for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
536       // Only examine devices that are output capable..  Valid values are
537       // "Input", "Output", and NULL which means both input and output.
538       scoped_ptr<char, base::FreeDeleter> io(
539           wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName));
540       if (io != NULL && strcmp(io.get(), "Input") == 0)
541         continue;
542 
543       // Attempt to select the closest device for number of channels.
544       scoped_ptr<char, base::FreeDeleter> name(
545           wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
546       if (strncmp(wanted_device, name.get(), strlen(wanted_device)) == 0) {
547         guessed_device = name.get();
548         break;
549       }
550     }
551 
552     // Destroy the hint now that we're done with it.
553     wrapper_->DeviceNameFreeHint(hints);
554     hints = NULL;
555   } else {
556     LOG(ERROR) << "Unable to get hints for devices: "
557                << wrapper_->StrError(error);
558   }
559 
560   return guessed_device;
561 }
562 
GetCurrentDelay()563 snd_pcm_sframes_t AlsaPcmOutputStream::GetCurrentDelay() {
564   snd_pcm_sframes_t delay = -1;
565   // Don't query ALSA's delay if we have underrun since it'll be jammed at some
566   // non-zero value and potentially even negative!
567   //
568   // Also, if we're in the prepared state, don't query because that seems to
569   // cause an I/O error when we do query the delay.
570   snd_pcm_state_t pcm_state = wrapper_->PcmState(playback_handle_);
571   if (pcm_state != SND_PCM_STATE_XRUN &&
572       pcm_state != SND_PCM_STATE_PREPARED) {
573     int error = wrapper_->PcmDelay(playback_handle_, &delay);
574     if (error < 0) {
575       // Assume a delay of zero and attempt to recover the device.
576       delay = -1;
577       error = wrapper_->PcmRecover(playback_handle_,
578                                    error,
579                                    kPcmRecoverIsSilent);
580       if (error < 0) {
581         LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error);
582       }
583     }
584   }
585 
586   // snd_pcm_delay() sometimes returns crazy values.  In this case return delay
587   // of data we know currently is in ALSA's buffer.  Note: When the underlying
588   // driver is PulseAudio based, certain configuration settings (e.g., tsched=1)
589   // will generate much larger delay values than |alsa_buffer_frames_|, so only
590   // clip if delay is truly crazy (> 10x expected).
591   if (static_cast<snd_pcm_uframes_t>(delay) > alsa_buffer_frames_ * 10) {
592     delay = alsa_buffer_frames_ - GetAvailableFrames();
593   }
594 
595   if (delay < 0) {
596     delay = 0;
597   }
598 
599   return delay;
600 }
601 
GetAvailableFrames()602 snd_pcm_sframes_t AlsaPcmOutputStream::GetAvailableFrames() {
603   DCHECK(IsOnAudioThread());
604 
605   if (stop_stream_)
606     return 0;
607 
608   // Find the number of frames queued in the sound device.
609   snd_pcm_sframes_t available_frames =
610       wrapper_->PcmAvailUpdate(playback_handle_);
611   if (available_frames < 0) {
612     available_frames = wrapper_->PcmRecover(playback_handle_,
613                                             available_frames,
614                                             kPcmRecoverIsSilent);
615   }
616   if (available_frames < 0) {
617     LOG(ERROR) << "Failed querying available frames. Assuming 0: "
618                << wrapper_->StrError(available_frames);
619     return 0;
620   }
621   if (static_cast<uint32>(available_frames) > alsa_buffer_frames_ * 2) {
622     LOG(ERROR) << "ALSA returned " << available_frames << " of "
623                << alsa_buffer_frames_ << " frames available.";
624     return alsa_buffer_frames_;
625   }
626 
627   return available_frames;
628 }
629 
AutoSelectDevice(unsigned int latency)630 snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) {
631   // For auto-selection:
632   //   1) Attempt to open a device that best matches the number of channels
633   //      requested.
634   //   2) If that fails, attempt the "plug:" version of it in case ALSA can
635   //      remap do some software conversion to make it work.
636   //   3) Fallback to kDefaultDevice.
637   //   4) If that fails too, try the "plug:" version of kDefaultDevice.
638   //   5) Give up.
639   snd_pcm_t* handle = NULL;
640   device_name_ = FindDeviceForChannels(channels_);
641 
642   // Step 1.
643   if (!device_name_.empty()) {
644     if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
645                                                 channels_, sample_rate_,
646                                                 pcm_format_,
647                                                 latency)) != NULL) {
648       return handle;
649     }
650 
651     // Step 2.
652     device_name_ = kPlugPrefix + device_name_;
653     if ((handle = alsa_util::OpenPlaybackDevice(wrapper_, device_name_.c_str(),
654                                                 channels_, sample_rate_,
655                                                 pcm_format_,
656                                                 latency)) != NULL) {
657       return handle;
658     }
659   }
660 
661   // For the kDefaultDevice device, we can only reliably depend on 2-channel
662   // output to have the correct ordering according to Lennart.  For the channel
663   // formats that we know how to downmix from (3 channel to 8 channel), setup
664   // downmixing.
665   uint32 default_channels = channels_;
666   if (default_channels > 2) {
667     channel_mixer_.reset(new ChannelMixer(
668         channel_layout_, CHANNEL_LAYOUT_STEREO));
669     default_channels = 2;
670     mixed_audio_bus_ = AudioBus::Create(
671         default_channels, audio_bus_->frames());
672   }
673 
674   // Step 3.
675   device_name_ = kDefaultDevice;
676   if ((handle = alsa_util::OpenPlaybackDevice(
677       wrapper_, device_name_.c_str(), default_channels, sample_rate_,
678       pcm_format_, latency)) != NULL) {
679     return handle;
680   }
681 
682   // Step 4.
683   device_name_ = kPlugPrefix + device_name_;
684   if ((handle = alsa_util::OpenPlaybackDevice(
685       wrapper_, device_name_.c_str(), default_channels, sample_rate_,
686       pcm_format_, latency)) != NULL) {
687     return handle;
688   }
689 
690   // Unable to open any device.
691   device_name_.clear();
692   return NULL;
693 }
694 
CanTransitionTo(InternalState to)695 bool AlsaPcmOutputStream::CanTransitionTo(InternalState to) {
696   switch (state_) {
697     case kCreated:
698       return to == kIsOpened || to == kIsClosed || to == kInError;
699 
700     case kIsOpened:
701       return to == kIsPlaying || to == kIsStopped ||
702           to == kIsClosed || to == kInError;
703 
704     case kIsPlaying:
705       return to == kIsPlaying || to == kIsStopped ||
706           to == kIsClosed || to == kInError;
707 
708     case kIsStopped:
709       return to == kIsPlaying || to == kIsStopped ||
710           to == kIsClosed || to == kInError;
711 
712     case kInError:
713       return to == kIsClosed || to == kInError;
714 
715     case kIsClosed:
716     default:
717       return false;
718   }
719 }
720 
721 AlsaPcmOutputStream::InternalState
TransitionTo(InternalState to)722 AlsaPcmOutputStream::TransitionTo(InternalState to) {
723   DCHECK(IsOnAudioThread());
724 
725   if (!CanTransitionTo(to)) {
726     NOTREACHED() << "Cannot transition from: " << state_ << " to: " << to;
727     state_ = kInError;
728   } else {
729     state_ = to;
730   }
731   return state_;
732 }
733 
state()734 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() {
735   return state_;
736 }
737 
IsOnAudioThread() const738 bool AlsaPcmOutputStream::IsOnAudioThread() const {
739   return message_loop_ && message_loop_ == base::MessageLoop::current();
740 }
741 
RunDataCallback(AudioBus * audio_bus,AudioBuffersState buffers_state)742 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus,
743                                          AudioBuffersState buffers_state) {
744   TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback");
745 
746   if (source_callback_)
747     return source_callback_->OnMoreData(audio_bus, buffers_state);
748 
749   return 0;
750 }
751 
RunErrorCallback(int code)752 void AlsaPcmOutputStream::RunErrorCallback(int code) {
753   if (source_callback_)
754     source_callback_->OnError(this);
755 }
756 
757 // Changes the AudioSourceCallback to proxy calls to.  Pass in NULL to
758 // release ownership of the currently registered callback.
set_source_callback(AudioSourceCallback * callback)759 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
760   DCHECK(IsOnAudioThread());
761   source_callback_ = callback;
762 }
763 
764 }  // namespace media
765