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.
5 #include "media/audio/cras/cras_unified.h"
7 #include <cras_client.h>
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "media/audio/cras/audio_manager_cras.h"
12 #include "media/audio/linux/alsa_util.h"
16 // Overview of operation:
17 // 1) An object of CrasUnifiedStream is created by the AudioManager
18 // factory: audio_man->MakeAudioStream().
19 // 2) Next some thread will call Open(), at that point a client is created and
20 // configured for the correct format and sample rate.
21 // 3) Then Start(source) is called and a stream is added to the CRAS client
22 // which will create its own thread that periodically calls the source for more
23 // data as buffers are being consumed.
24 // 4) When finished Stop() is called, which is handled by stopping the stream.
25 // 5) Finally Close() is called. It cleans up and notifies the audio manager,
26 // which likely will destroy this object.
28 // For output-only streams, a unified stream is created with 0 input channels.
30 // Simplified data flow for unified streams:
32 // +-------------+ +------------------+
33 // | CRAS Server | | Chrome Client |
34 // +------+------+ Add Stream +---------+--------+
35 // |<----------------------------------|
37 // | buffer_frames captured to shm |
38 // |---------------------------------->|
39 // | | UnifiedCallback()
40 // | | ReadWriteAudio()
42 // | buffer_frames written to shm |
43 // |<----------------------------------|
45 // ... Repeats for each block. ...
49 // |<----------------------------------|
52 // Simplified data flow for output only streams:
54 // +-------------+ +------------------+
55 // | CRAS Server | | Chrome Client |
56 // +------+------+ Add Stream +---------+--------+
57 // |<----------------------------------|
59 // | Near out of samples, request more |
60 // |---------------------------------->|
61 // | | UnifiedCallback()
64 // | buffer_frames written to shm |
65 // |<----------------------------------|
67 // ... Repeats for each block. ...
71 // |<----------------------------------|
74 // For Unified streams the Chrome client is notified whenever buffer_frames have
75 // been captured. For Output streams the client is notified a few milliseconds
76 // before the hardware buffer underruns and fills the buffer with another block
79 CrasUnifiedStream::CrasUnifiedStream(const AudioParameters& params,
80 AudioManagerCras* manager)
88 source_callback_(NULL),
89 stream_direction_(CRAS_STREAM_OUTPUT) {
91 DCHECK(params_.channels() > 0);
93 // Must have at least one input or output. If there are both they must be the
95 int input_channels = params_.input_channels();
98 // A unified stream for input and output.
99 DCHECK(params_.channels() == input_channels);
100 stream_direction_ = CRAS_STREAM_UNIFIED;
101 input_bus_ = AudioBus::Create(input_channels,
102 params_.frames_per_buffer());
105 output_bus_ = AudioBus::Create(params);
108 CrasUnifiedStream::~CrasUnifiedStream() {
109 DCHECK(!is_playing_);
112 bool CrasUnifiedStream::Open() {
113 // Sanity check input values.
114 if (params_.sample_rate() <= 0) {
115 LOG(WARNING) << "Unsupported audio frequency.";
119 if (alsa_util::BitsToFormat(params_.bits_per_sample()) ==
120 SND_PCM_FORMAT_UNKNOWN) {
121 LOG(WARNING) << "Unsupported pcm format";
125 // Create the client and connect to the CRAS server.
126 if (cras_client_create(&client_)) {
127 LOG(WARNING) << "Couldn't create CRAS client.\n";
132 if (cras_client_connect(client_)) {
133 LOG(WARNING) << "Couldn't connect CRAS client.\n";
134 cras_client_destroy(client_);
139 // Then start running the client.
140 if (cras_client_run_thread(client_)) {
141 LOG(WARNING) << "Couldn't run CRAS client.\n";
142 cras_client_destroy(client_);
150 void CrasUnifiedStream::Close() {
152 cras_client_stop(client_);
153 cras_client_destroy(client_);
157 // Signal to the manager that we're closed and can be removed.
158 // Should be last call in the method as it deletes "this".
159 manager_->ReleaseOutputStream(this);
162 void CrasUnifiedStream::Start(AudioSourceCallback* callback) {
165 // Channel map to CRAS_CHANNEL, values in the same order of
166 // corresponding source in Chromium defined Channels.
167 static const int kChannelMap[] = {
181 source_callback_ = callback;
183 // Only start if we can enter the playing state.
187 // Prepare |audio_format| and |stream_params| for the stream we
189 cras_audio_format* audio_format = cras_audio_format_create(
190 alsa_util::BitsToFormat(params_.bits_per_sample()),
191 params_.sample_rate(),
194 LOG(WARNING) << "Error setting up audio parameters.";
195 callback->OnError(this);
199 // Initialize channel layout to all -1 to indicate that none of
200 // the channels is set in the layout.
201 int8 layout[CRAS_CH_MAX] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
203 // Converts to CRAS defined channels. ChannelOrder will return -1
204 // for channels that does not present in params_.channel_layout().
205 for (size_t i = 0; i < arraysize(kChannelMap); ++i)
206 layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
207 static_cast<Channels>(i));
209 if (cras_audio_format_set_channel_layout(audio_format, layout)) {
210 LOG(WARNING) << "Error setting channel layout.";
211 callback->OnError(this);
215 cras_stream_params* stream_params = cras_client_unified_params_create(
217 params_.frames_per_buffer(),
218 CRAS_STREAM_TYPE_DEFAULT,
221 CrasUnifiedStream::UnifiedCallback,
222 CrasUnifiedStream::StreamError,
224 if (!stream_params) {
225 LOG(WARNING) << "Error setting up stream parameters.";
226 callback->OnError(this);
227 cras_audio_format_destroy(audio_format);
231 // Before starting the stream, save the number of bytes in a frame for use in
233 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
235 // Adding the stream will start the audio callbacks requesting data.
236 if (cras_client_add_stream(client_, &stream_id_, stream_params) < 0) {
237 LOG(WARNING) << "Failed to add the stream";
238 callback->OnError(this);
239 cras_audio_format_destroy(audio_format);
240 cras_client_stream_params_destroy(stream_params);
244 // Set initial volume.
245 cras_client_set_stream_volume(client_, stream_id_, volume_);
247 // Done with config params.
248 cras_audio_format_destroy(audio_format);
249 cras_client_stream_params_destroy(stream_params);
254 void CrasUnifiedStream::Stop() {
258 // Removing the stream from the client stops audio.
259 cras_client_rm_stream(client_, stream_id_);
264 void CrasUnifiedStream::SetVolume(double volume) {
267 volume_ = static_cast<float>(volume);
268 cras_client_set_stream_volume(client_, stream_id_, volume_);
271 void CrasUnifiedStream::GetVolume(double* volume) {
275 uint32 CrasUnifiedStream::GetBytesLatency(
276 const struct timespec& latency_ts) {
279 // Treat negative latency (if we are too slow to render) as 0.
280 if (latency_ts.tv_sec < 0 || latency_ts.tv_nsec < 0) {
283 latency_usec = (latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond) +
284 latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
287 double frames_latency =
288 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
290 return static_cast<unsigned int>(frames_latency * bytes_per_frame_);
293 // Static callback asking for samples.
294 int CrasUnifiedStream::UnifiedCallback(cras_client* client,
295 cras_stream_id_t stream_id,
296 uint8* input_samples,
297 uint8* output_samples,
299 const timespec* input_ts,
300 const timespec* output_ts,
302 CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
303 return me->DispatchCallback(frames,
310 // Static callback for stream errors.
311 int CrasUnifiedStream::StreamError(cras_client* client,
312 cras_stream_id_t stream_id,
315 CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
316 me->NotifyStreamError(err);
320 // Calls the appropriate rendering function for this type of stream.
321 uint32 CrasUnifiedStream::DispatchCallback(size_t frames,
322 uint8* input_samples,
323 uint8* output_samples,
324 const timespec* input_ts,
325 const timespec* output_ts) {
326 switch (stream_direction_) {
327 case CRAS_STREAM_OUTPUT:
328 return WriteAudio(frames, output_samples, output_ts);
329 case CRAS_STREAM_INPUT:
330 NOTREACHED() << "CrasUnifiedStream doesn't support input streams.";
332 case CRAS_STREAM_UNIFIED:
333 return ReadWriteAudio(frames, input_samples, output_samples,
334 input_ts, output_ts);
342 // Note these are run from a real time thread, so don't waste cycles here.
343 uint32 CrasUnifiedStream::ReadWriteAudio(size_t frames,
344 uint8* input_samples,
345 uint8* output_samples,
346 const timespec* input_ts,
347 const timespec* output_ts) {
348 DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames()));
349 DCHECK(source_callback_);
351 uint32 bytes_per_sample = bytes_per_frame_ / params_.channels();
352 input_bus_->FromInterleaved(input_samples, frames, bytes_per_sample);
354 // Determine latency and pass that on to the source. We have the capture time
355 // of the first input sample and the playback time of the next audio sample
356 // passed from the audio server, add them together for total latency.
357 uint32 total_delay_bytes;
358 timespec latency_ts = {0, 0};
359 cras_client_calc_capture_latency(input_ts, &latency_ts);
360 total_delay_bytes = GetBytesLatency(latency_ts);
361 cras_client_calc_playback_latency(output_ts, &latency_ts);
362 total_delay_bytes += GetBytesLatency(latency_ts);
364 int frames_filled = source_callback_->OnMoreIOData(
367 AudioBuffersState(0, total_delay_bytes));
369 output_bus_->ToInterleaved(frames_filled, bytes_per_sample, output_samples);
371 return frames_filled;
374 uint32 CrasUnifiedStream::WriteAudio(size_t frames,
376 const timespec* sample_ts) {
377 DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames()));
379 // Determine latency and pass that on to the source.
380 timespec latency_ts = {0, 0};
381 cras_client_calc_playback_latency(sample_ts, &latency_ts);
383 int frames_filled = source_callback_->OnMoreData(
384 output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts)));
386 // Note: If this ever changes to output raw float the data must be clipped and
387 // sanitized since it may come from an untrusted source such as NaCl.
388 output_bus_->ToInterleaved(
389 frames_filled, bytes_per_frame_ / params_.channels(), buffer);
391 return frames_filled;
394 void CrasUnifiedStream::NotifyStreamError(int err) {
395 // This will remove the stream from the client.
396 if (source_callback_)
397 source_callback_->OnError(this);