- add sources.
[platform/framework/web/crosswalk.git] / src / media / audio / cras / cras_unified.cc
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 #include "media/audio/cras/cras_unified.h"
6
7 #include <cras_client.h>
8
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"
13
14 namespace media {
15
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.
27 //
28 // For output-only streams, a unified stream is created with 0 input channels.
29 //
30 // Simplified data flow for unified streams:
31 //
32 //   +-------------+                  +------------------+
33 //   | CRAS Server |                  | Chrome Client    |
34 //   +------+------+    Add Stream    +---------+--------+
35 //          |<----------------------------------|
36 //          |                                   |
37 //          |  buffer_frames captured to shm    |
38 //          |---------------------------------->|
39 //          |                                   |  UnifiedCallback()
40 //          |                                   |  ReadWriteAudio()
41 //          |                                   |
42 //          |  buffer_frames written to shm     |
43 //          |<----------------------------------|
44 //          |                                   |
45 //         ...  Repeats for each block.        ...
46 //          |                                   |
47 //          |                                   |
48 //          |  Remove stream                    |
49 //          |<----------------------------------|
50 //          |                                   |
51 //
52 // Simplified data flow for output only streams:
53 //
54 //   +-------------+                  +------------------+
55 //   | CRAS Server |                  | Chrome Client    |
56 //   +------+------+    Add Stream    +---------+--------+
57 //          |<----------------------------------|
58 //          |                                   |
59 //          | Near out of samples, request more |
60 //          |---------------------------------->|
61 //          |                                   |  UnifiedCallback()
62 //          |                                   |  WriteAudio()
63 //          |                                   |
64 //          |  buffer_frames written to shm     |
65 //          |<----------------------------------|
66 //          |                                   |
67 //         ...  Repeats for each block.        ...
68 //          |                                   |
69 //          |                                   |
70 //          |  Remove stream                    |
71 //          |<----------------------------------|
72 //          |                                   |
73 //
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
77 // of audio.
78
79 CrasUnifiedStream::CrasUnifiedStream(const AudioParameters& params,
80                                      AudioManagerCras* manager)
81     : client_(NULL),
82       stream_id_(0),
83       params_(params),
84       bytes_per_frame_(0),
85       is_playing_(false),
86       volume_(1.0),
87       manager_(manager),
88       source_callback_(NULL),
89       stream_direction_(CRAS_STREAM_OUTPUT) {
90   DCHECK(manager_);
91   DCHECK(params_.channels()  > 0);
92
93   // Must have at least one input or output.  If there are both they must be the
94   // same.
95   int input_channels = params_.input_channels();
96
97   if (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());
103   }
104
105   output_bus_ = AudioBus::Create(params);
106 }
107
108 CrasUnifiedStream::~CrasUnifiedStream() {
109   DCHECK(!is_playing_);
110 }
111
112 bool CrasUnifiedStream::Open() {
113   // Sanity check input values.
114   if (params_.sample_rate() <= 0) {
115     LOG(WARNING) << "Unsupported audio frequency.";
116     return false;
117   }
118
119   if (alsa_util::BitsToFormat(params_.bits_per_sample()) ==
120       SND_PCM_FORMAT_UNKNOWN) {
121     LOG(WARNING) << "Unsupported pcm format";
122     return false;
123   }
124
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";
128     client_ = NULL;
129     return false;
130   }
131
132   if (cras_client_connect(client_)) {
133     LOG(WARNING) << "Couldn't connect CRAS client.\n";
134     cras_client_destroy(client_);
135     client_ = NULL;
136     return false;
137   }
138
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_);
143     client_ = NULL;
144     return false;
145   }
146
147   return true;
148 }
149
150 void CrasUnifiedStream::Close() {
151   if (client_) {
152     cras_client_stop(client_);
153     cras_client_destroy(client_);
154     client_ = NULL;
155   }
156
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);
160 }
161
162 void CrasUnifiedStream::Start(AudioSourceCallback* callback) {
163   CHECK(callback);
164
165   // Channel map to CRAS_CHANNEL, values in the same order of
166   // corresponding source in Chromium defined Channels.
167   static const int kChannelMap[] = {
168     CRAS_CH_FL,
169     CRAS_CH_FR,
170     CRAS_CH_FC,
171     CRAS_CH_LFE,
172     CRAS_CH_RL,
173     CRAS_CH_RR,
174     CRAS_CH_FLC,
175     CRAS_CH_FRC,
176     CRAS_CH_RC,
177     CRAS_CH_SL,
178     CRAS_CH_SR
179   };
180
181   source_callback_ = callback;
182
183   // Only start if we can enter the playing state.
184   if (is_playing_)
185     return;
186
187   // Prepare |audio_format| and |stream_params| for the stream we
188   // will create.
189   cras_audio_format* audio_format = cras_audio_format_create(
190       alsa_util::BitsToFormat(params_.bits_per_sample()),
191       params_.sample_rate(),
192       params_.channels());
193   if (!audio_format) {
194     LOG(WARNING) << "Error setting up audio parameters.";
195     callback->OnError(this);
196     return;
197   }
198
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 };
202
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));
208
209   if (cras_audio_format_set_channel_layout(audio_format, layout)) {
210     LOG(WARNING) << "Error setting channel layout.";
211     callback->OnError(this);
212     return;
213   }
214
215   cras_stream_params* stream_params = cras_client_unified_params_create(
216       stream_direction_,
217       params_.frames_per_buffer(),
218       CRAS_STREAM_TYPE_DEFAULT,
219       0,
220       this,
221       CrasUnifiedStream::UnifiedCallback,
222       CrasUnifiedStream::StreamError,
223       audio_format);
224   if (!stream_params) {
225     LOG(WARNING) << "Error setting up stream parameters.";
226     callback->OnError(this);
227     cras_audio_format_destroy(audio_format);
228     return;
229   }
230
231   // Before starting the stream, save the number of bytes in a frame for use in
232   // the callback.
233   bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
234
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);
241     return;
242   }
243
244   // Set initial volume.
245   cras_client_set_stream_volume(client_, stream_id_, volume_);
246
247   // Done with config params.
248   cras_audio_format_destroy(audio_format);
249   cras_client_stream_params_destroy(stream_params);
250
251   is_playing_ = true;
252 }
253
254 void CrasUnifiedStream::Stop() {
255   if (!client_)
256     return;
257
258   // Removing the stream from the client stops audio.
259   cras_client_rm_stream(client_, stream_id_);
260
261   is_playing_ = false;
262 }
263
264 void CrasUnifiedStream::SetVolume(double volume) {
265   if (!client_)
266     return;
267   volume_ = static_cast<float>(volume);
268   cras_client_set_stream_volume(client_, stream_id_, volume_);
269 }
270
271 void CrasUnifiedStream::GetVolume(double* volume) {
272   *volume = volume_;
273 }
274
275 uint32 CrasUnifiedStream::GetBytesLatency(
276     const struct timespec& latency_ts) {
277   uint32 latency_usec;
278
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) {
281     latency_usec = 0;
282   } else {
283     latency_usec = (latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond) +
284         latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
285   }
286
287   double frames_latency =
288       latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
289
290   return static_cast<unsigned int>(frames_latency * bytes_per_frame_);
291 }
292
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,
298                                        unsigned int frames,
299                                        const timespec* input_ts,
300                                        const timespec* output_ts,
301                                        void* arg) {
302   CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
303   return me->DispatchCallback(frames,
304                               input_samples,
305                               output_samples,
306                               input_ts,
307                               output_ts);
308 }
309
310 // Static callback for stream errors.
311 int CrasUnifiedStream::StreamError(cras_client* client,
312                                    cras_stream_id_t stream_id,
313                                    int err,
314                                    void* arg) {
315   CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
316   me->NotifyStreamError(err);
317   return 0;
318 }
319
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.";
331       return 0;
332     case CRAS_STREAM_UNIFIED:
333       return ReadWriteAudio(frames, input_samples, output_samples,
334                             input_ts, output_ts);
335     default:
336       break;
337   }
338
339   return 0;
340 }
341
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_);
350
351   uint32 bytes_per_sample = bytes_per_frame_ / params_.channels();
352   input_bus_->FromInterleaved(input_samples, frames, bytes_per_sample);
353
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);
363
364   int frames_filled = source_callback_->OnMoreIOData(
365       input_bus_.get(),
366       output_bus_.get(),
367       AudioBuffersState(0, total_delay_bytes));
368
369   output_bus_->ToInterleaved(frames_filled, bytes_per_sample, output_samples);
370
371   return frames_filled;
372 }
373
374 uint32 CrasUnifiedStream::WriteAudio(size_t frames,
375                                      uint8* buffer,
376                                      const timespec* sample_ts) {
377   DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames()));
378
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);
382
383   int frames_filled = source_callback_->OnMoreData(
384       output_bus_.get(), AudioBuffersState(0, GetBytesLatency(latency_ts)));
385
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);
390
391   return frames_filled;
392 }
393
394 void CrasUnifiedStream::NotifyStreamError(int err) {
395   // This will remove the stream from the client.
396   if (source_callback_)
397     source_callback_->OnError(this);
398 }
399
400 }  // namespace media