Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: media/audio/linux/cras_input.cc

Issue 10592014: media/audio/linux: Add CrasInputStream. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #include "media/audio/linux/cras_input.h"
6
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "base/time.h"
11 #include "media/audio/audio_manager.h"
12 #include "media/audio/linux/alsa_util.h"
13 #include "media/audio/linux/audio_manager_linux.h"
14
15 namespace media {
16
17 CrasInputStream::CrasInputStream(const AudioParameters& params,
18 AudioManagerLinux* manager)
19 : audio_manager_(manager),
20 bytes_per_frame_(0),
21 callback_(NULL),
22 client_(NULL),
23 frame_rate_(params.sample_rate()),
no longer working on chromium 2012/06/20 10:45:26 How about changing the name to sample_rate_? We d
dgreid 2012/06/20 17:14:25 Done.
24 num_channels_(params.channels()),
25 params_(params),
26 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())),
27 stream_id_(0) {
28 DCHECK(audio_manager_);
29 }
30
31 CrasInputStream::~CrasInputStream() {}
no longer working on chromium 2012/06/20 10:45:26 Add a DCHECK here to make sure things have already
dgreid 2012/06/20 17:14:25 Done.
32
33 bool CrasInputStream::Open() {
34 if (client_) {
35 NOTREACHED() << "CrasInputStream already open";
36 return false; // Already open.
37 }
38
39 // Sanity check input values.
40 if (params_.sample_rate() <= 0) {
41 LOG(WARNING) << "Unsupported audio frequency.";
no longer working on chromium 2012/06/20 10:45:26 I know we use LOG for alsa too, but is it really n
dgreid 2012/06/20 17:14:25 Done for whole file.
42 return false;
43 }
44
45 if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
46 AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
47 LOG(WARNING) << "Unsupported audio format.";
no longer working on chromium 2012/06/20 10:45:26 ditto
48 return false;
49 }
50
51 if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) {
52 LOG(WARNING) << "Unsupported bits/sample: " << params_.bits_per_sample();
no longer working on chromium 2012/06/20 10:45:26 ditto
53 return false;
54 }
55
56 // Create the client and connect to the CRAS server.
57 if (cras_client_create(&client_) < 0) {
58 LOG(WARNING) << "Couldn't create CRAS client.\n";
no longer working on chromium 2012/06/20 10:45:26 ditto
59 client_ = NULL;
60 return false;
61 }
62
63 if (cras_client_connect(client_)) {
64 LOG(WARNING) << "Couldn't connect CRAS client.\n";
no longer working on chromium 2012/06/20 10:45:26 ditto
65 cras_client_destroy(client_);
66 client_ = NULL;
67 return false;
68 }
69
70 // Then start running the client.
71 if (cras_client_run_thread(client_)) {
72 LOG(WARNING) << "Couldn't run CRAS client.\n";
73 cras_client_destroy(client_);
74 client_ = NULL;
75 return false;
76 }
77
78 return true;
79 }
80
81 void CrasInputStream::Close() {
82 if (client_) {
83 cras_client_stop(client_);
84 cras_client_destroy(client_);
85 client_ = NULL;
86 }
87
88 if (callback_)
89 callback_->OnClose(this);
90
91 // Signal to the manager that we're closed and can be removed.
92 // Should be last call in the method as it deletes "this".
93 audio_manager_->ReleaseInputStream(this);
94 }
95
96 void CrasInputStream::Start(AudioInputCallback* callback) {
97 DCHECK(client_);
98 DCHECK(!callback_ && callback);
no longer working on chromium 2012/06/20 10:45:26 Does this mean we only allow calling Start() once?
dgreid 2012/06/20 17:14:25 Yes, call Start once until Stop is called. This s
99 callback_ = callback;
100
101 // Prepare |audio_format| and |stream_params| for the stream we
102 // will create.
103 cras_audio_format* audio_format = cras_audio_format_create(
104 pcm_format_,
105 frame_rate_,
106 num_channels_);
107 if (!audio_format) {
108 LOG(WARNING) << "Error setting up audio parameters.";
109 callback->OnError(this, -ENOMEM);
110 return;
111 }
112
113 unsigned int frames_per_packet = params_.frames_per_buffer();
114 cras_stream_params* stream_params = cras_client_stream_params_create(
115 CRAS_STREAM_INPUT,
116 frames_per_packet, // Total latency.
no longer working on chromium 2012/06/20 10:45:26 Curiously, does it mean we are using one queue wit
dgreid 2012/06/20 17:14:25 On the server side there are two buffers of this s
117 frames_per_packet, // Call back when this many ready.
118 frames_per_packet, // Don't care for capture.
no longer working on chromium 2012/06/20 10:45:26 I am curious, what does this parameter mean?
dgreid 2012/06/20 17:14:25 For an output stream, it indicates the minimum amo
119 CRAS_STREAM_TYPE_DEFAULT,
120 0, // Unused flags.
121 this,
122 CrasInputStream::SamplesReady,
123 CrasInputStream::StreamError,
124 audio_format);
125 if (!stream_params) {
126 LOG(WARNING) << "Error setting up stream parameters.";
127 callback->OnError(this, -ENOMEM);
128 cras_audio_format_destroy(audio_format);
129 return;
130 }
131
132 // Before starting the stream, save the number of bytes in a frame for use in
133 // the callback.
134 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
135
136 // Adding the stream will start the audio callbacks.
137 if (cras_client_add_stream(client_, &stream_id_, stream_params) == 0) {
138 audio_manager_->IncreaseActiveInputStreamCount();
no longer working on chromium 2012/06/20 10:45:26 In case Start() fails for any of the reason, shoul
dgreid 2012/06/20 17:14:25 Thanks, good catch. Made them match up, so that c
139 } else {
140 LOG(WARNING) << "Failed to add the stream";
no longer working on chromium 2012/06/20 10:45:26 DLOG, and add a period.
dgreid 2012/06/20 17:14:25 Done.
141 callback->OnError(this, -EIO);
142 }
143
144 // Done with config params.
145 cras_audio_format_destroy(audio_format);
146 cras_client_stream_params_destroy(stream_params);
147 }
148
149 void CrasInputStream::Stop() {
150 if (!client_ || !callback_)
151 return;
152
153 // Removing the stream from the client stops audio.
154 cras_client_rm_stream(client_, stream_id_);
155
156 audio_manager_->DecreaseActiveInputStreamCount();
157 }
158
159 // Static callback asking for samples. Run on high priority thread.
160 int CrasInputStream::SamplesReady(cras_client* client,
161 cras_stream_id_t stream_id,
162 uint8* samples,
163 size_t frames,
164 const timespec* sample_ts,
165 void* arg) {
166 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
167 me->ReadAudio(frames, samples, sample_ts);
168 return frames;
169 }
170
171 // Static callback for stream errors.
172 int CrasInputStream::StreamError(cras_client* client,
173 cras_stream_id_t stream_id,
174 int err,
175 void* arg) {
176 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
177 me->NotifyStreamError(err);
178 return 0;
179 }
180
181 void CrasInputStream::ReadAudio(size_t frames,
182 uint8* buffer,
183 const timespec* sample_ts) {
184 DCHECK(callback_);
185
186 timespec latency_ts = {0, 0};
187
188 // Determine latency and pass that on to the sink. sample_ts is the wall time
189 // indicating when the first sample in the buffer was captured. Convert that
190 // to latency in bytes.
191 cras_client_calc_capture_latency(sample_ts, &latency_ts);
192 double latency_usec = (latency_ts.tv_sec * 1e6) + latency_ts.tv_nsec * 1e-3;
193 double frames_latency = latency_usec * frame_rate_ * 1e-6;
194 unsigned int bytes_latency =
195 static_cast<unsigned int>(frames_latency * bytes_per_frame_);
196
197 // Update the AGC volume level once every second. Note that, |volume| is
198 // also updated each time SetVolume() is called through IPC by the
199 // render-side AGC.
200 double normalized_volume = 0.0;
201 QueryAgcVolume(&normalized_volume);
202
203 callback_->OnData(this,
204 buffer,
205 frames * bytes_per_frame_,
206 bytes_latency,
207 normalized_volume);
208 }
209
210 void CrasInputStream::NotifyStreamError(int err) {
211 if (callback_)
212 callback_->OnError(this, err);
213 }
214
215 double CrasInputStream::GetMaxVolume() {
216 DCHECK(client_);
217
218 // Return the max volume as a double to match what the alsa input does.
219 return static_cast<double>(cras_client_get_system_max_capture_gain(client_));
220 }
221
222 void CrasInputStream::SetVolume(double volume) {
223 DCHECK(client_);
224
225 cras_client_set_system_capture_gain(client_, static_cast<long>(volume));
226
227 // Update the AGC volume level based on the last setting above. Note that,
228 // the volume-level resolution is not infinite and it is therefore not
229 // possible to assume that the volume provided as input parameter can be
230 // used directly. Instead, a new query to the audio hardware is required.
231 // This method does nothing if AGC is disabled.
232 UpdateAgcVolume();
233 }
234
235 double CrasInputStream::GetVolume() {
236 if (!client_)
237 return 0.0;
238
239 long current_volume = cras_client_get_system_capture_gain(client_);
240
241 // Only want the gain, limit reported level to zero.
242 if (current_volume < 0)
243 return 0.0;
244
245 return static_cast<double>(current_volume);
246 }
247
248 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698