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

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: new 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 params_(params),
24 stream_id_(0) {
25 DCHECK(audio_manager_);
26 }
27
28 CrasInputStream::~CrasInputStream() {
29 DCHECK(!client_);
30 }
31
32 bool CrasInputStream::Open() {
33 if (client_) {
34 NOTREACHED() << "CrasInputStream already open";
35 return false; // Already open.
36 }
37
38 // Sanity check input values.
39 if (params_.sample_rate() <= 0) {
40 DLOG(WARNING) << "Unsupported audio frequency.";
41 return false;
42 }
43
44 if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() &&
45 AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) {
46 DLOG(WARNING) << "Unsupported audio format.";
47 return false;
48 }
49
50 snd_pcm_format_t pcm_format =
51 alsa_util::BitsToFormat(params_.bits_per_sample());
52 if (pcm_format == SND_PCM_FORMAT_UNKNOWN) {
53 DLOG(WARNING) << "Unsupported bits/sample: " << params_.bits_per_sample();
54 return false;
55 }
56
57 // Create the client and connect to the CRAS server.
58 if (cras_client_create(&client_) < 0) {
59 DLOG(WARNING) << "Couldn't create CRAS client.\n";
60 client_ = NULL;
61 return false;
62 }
63
64 if (cras_client_connect(client_)) {
65 DLOG(WARNING) << "Couldn't connect CRAS client.\n";
66 cras_client_destroy(client_);
67 client_ = NULL;
68 return false;
69 }
70
71 // Then start running the client.
72 if (cras_client_run_thread(client_)) {
73 DLOG(WARNING) << "Couldn't run CRAS client.\n";
74 cras_client_destroy(client_);
75 client_ = NULL;
76 return false;
77 }
78
79 return true;
80 }
81
82 void CrasInputStream::Close() {
83 if (client_) {
84 cras_client_stop(client_);
85 cras_client_destroy(client_);
86 client_ = NULL;
87 }
88
89 if (callback_)
no longer working on chromium 2012/06/26 21:42:49 I think the speech recognition team needs this cal
90 callback_->OnClose(this);
91
92 // Signal to the manager that we're closed and can be removed.
93 // Should be last call in the method as it deletes "this".
94 audio_manager_->ReleaseInputStream(this);
95 }
96
97 void CrasInputStream::Start(AudioInputCallback* callback) {
98 DCHECK(client_);
99 DCHECK(!callback_);
100 DCHECK(callback);
no longer working on chromium 2012/06/25 15:59:27 Currently we don't have user case for it, but I th
dgreid 2012/06/25 21:29:28 Since this function is void I just automatically s
101
102 callback_ = callback;
103
104 // Prepare |audio_format| and |stream_params| for the stream we
105 // will create.
106 cras_audio_format* audio_format = cras_audio_format_create(
107 alsa_util::BitsToFormat(params_.bits_per_sample()),
108 params_.sample_rate(),
109 params_.channels());
110 if (!audio_format) {
111 DLOG(WARNING) << "Error setting up audio parameters.";
112 callback_->OnError(this, -ENOMEM);
113 callback_ = NULL;
114 return;
115 }
116
117 unsigned int frames_per_packet = params_.frames_per_buffer();
118 cras_stream_params* stream_params = cras_client_stream_params_create(
119 CRAS_STREAM_INPUT,
120 frames_per_packet, // Total latency.
121 frames_per_packet, // Call back when this many ready.
122 frames_per_packet, // Minimum Callback level ignored for capture streams.
123 CRAS_STREAM_TYPE_DEFAULT,
124 0, // Unused flags.
125 this,
126 CrasInputStream::SamplesReady,
127 CrasInputStream::StreamError,
128 audio_format);
129 if (!stream_params) {
130 DLOG(WARNING) << "Error setting up stream parameters.";
131 callback_->OnError(this, -ENOMEM);
132 callback_ = NULL;
133 cras_audio_format_destroy(audio_format);
134 return;
135 }
136
137 // Before starting the stream, save the number of bytes in a frame for use in
138 // the callback.
139 bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
140
141 // Adding the stream will start the audio callbacks.
142 if (cras_client_add_stream(client_, &stream_id_, stream_params) == 0) {
143 audio_manager_->IncreaseActiveInputStreamCount();
144 } else {
145 DLOG(WARNING) << "Failed to add the stream.";
146 callback_->OnError(this, -EIO);
147 callback_ = NULL;
148 }
149
150 // Done with config params.
151 cras_audio_format_destroy(audio_format);
152 cras_client_stream_params_destroy(stream_params);
153 }
154
155 void CrasInputStream::Stop() {
156 DCHECK(client_);
157
158 if (!callback_)
159 return;
160
161 // Removing the stream from the client stops audio.
162 cras_client_rm_stream(client_, stream_id_);
163
164 audio_manager_->DecreaseActiveInputStreamCount();
165 }
166
167 // Static callback asking for samples. Run on high priority thread.
168 int CrasInputStream::SamplesReady(cras_client* client,
169 cras_stream_id_t stream_id,
170 uint8* samples,
171 size_t frames,
172 const timespec* sample_ts,
173 void* arg) {
174 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
175 me->ReadAudio(frames, samples, sample_ts);
176 return frames;
177 }
178
179 // Static callback for stream errors.
180 int CrasInputStream::StreamError(cras_client* client,
181 cras_stream_id_t stream_id,
182 int err,
183 void* arg) {
184 CrasInputStream* me = static_cast<CrasInputStream*>(arg);
185 me->NotifyStreamError(err);
186 return 0;
187 }
188
189 void CrasInputStream::ReadAudio(size_t frames,
190 uint8* buffer,
191 const timespec* sample_ts) {
192 DCHECK(callback_);
193
194 timespec latency_ts = {0, 0};
195
196 // Determine latency and pass that on to the sink. sample_ts is the wall time
197 // indicating when the first sample in the buffer was captured. Convert that
198 // to latency in bytes.
199 cras_client_calc_capture_latency(sample_ts, &latency_ts);
200 double latency_usec =
201 latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
202 latency_ts.tv_nsec * base::Time::kNanosecondsPerMicrosecond;
203 double frames_latency =
204 latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
205 unsigned int bytes_latency =
206 static_cast<unsigned int>(frames_latency * bytes_per_frame_);
207
208 // Update the AGC volume level once every second. Note that, |volume| is
209 // also updated each time SetVolume() is called through IPC by the
210 // render-side AGC.
211 double normalized_volume = 0.0;
212 QueryAgcVolume(&normalized_volume);
213
214 callback_->OnData(this,
215 buffer,
216 frames * bytes_per_frame_,
217 bytes_latency,
218 normalized_volume);
219 }
220
221 void CrasInputStream::NotifyStreamError(int err) {
222 if (callback_)
223 callback_->OnError(this, err);
224 }
225
226 double CrasInputStream::GetMaxVolume() {
227 DCHECK(client_);
228
229 // Return the max volume as a double to match what the alsa input does.
230 return static_cast<double>(cras_client_get_system_max_capture_gain(client_));
231 }
232
233 void CrasInputStream::SetVolume(double volume) {
234 DCHECK(client_);
235
236 cras_client_set_system_capture_gain(client_, static_cast<long>(volume));
237
238 // Update the AGC volume level based on the last setting above. Note that,
239 // the volume-level resolution is not infinite and it is therefore not
240 // possible to assume that the volume provided as input parameter can be
241 // used directly. Instead, a new query to the audio hardware is required.
242 // This method does nothing if AGC is disabled.
243 UpdateAgcVolume();
244 }
245
246 double CrasInputStream::GetVolume() {
247 if (!client_)
248 return 0.0;
249
250 long current_volume = cras_client_get_system_capture_gain(client_);
251
252 // Only want the gain, limit reported level to zero.
253 if (current_volume < 0)
254 return 0.0;
255
256 return static_cast<double>(current_volume);
257 }
258
259 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698