blob: 9383a3684ce8d9764fb507be9dcf75423e0bf6f9 [file] [log] [blame]
Mikhail Naganovf558e022016-11-14 17:45:17 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "StreamHalHidl"
18//#define LOG_NDEBUG 0
19
20#include <android/hardware/audio/2.0/IStreamOutCallback.h>
21#include <utils/Log.h>
22
23#include "DeviceHalHidl.h"
24#include "EffectHalHidl.h"
25#include "StreamHalHidl.h"
26
27using ::android::hardware::audio::common::V2_0::AudioChannelMask;
28using ::android::hardware::audio::common::V2_0::AudioFormat;
29using ::android::hardware::audio::V2_0::AudioDrain;
30using ::android::hardware::audio::V2_0::IStreamOutCallback;
31using ::android::hardware::audio::V2_0::ParameterValue;
32using ::android::hardware::audio::V2_0::Result;
33using ::android::hardware::audio::V2_0::TimeSpec;
34using ::android::hardware::Return;
35using ::android::hardware::Void;
36
37namespace android {
38
39StreamHalHidl::StreamHalHidl(IStream *stream)
40 : ConversionHelperHidl("Stream"), mStream(stream) {
41}
42
43StreamHalHidl::~StreamHalHidl() {
44 mStream = nullptr;
45}
46
47status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
48 if (!mStream) return NO_INIT;
49 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
50}
51
52status_t StreamHalHidl::getBufferSize(size_t *size) {
53 if (!mStream) return NO_INIT;
54 return processReturn("getBufferSize", mStream->getBufferSize(), size);
55}
56
57status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
58 if (!mStream) return NO_INIT;
59 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
60}
61
62status_t StreamHalHidl::getFormat(audio_format_t *format) {
63 if (!mStream) return NO_INIT;
64 return processReturn("getFormat", mStream->getFormat(), format);
65}
66
67status_t StreamHalHidl::getAudioProperties(
68 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
69 if (!mStream) return NO_INIT;
70 Return<void> ret = mStream->getAudioProperties(
71 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
72 *sampleRate = sr;
73 *mask = static_cast<audio_channel_mask_t>(m);
74 *format = static_cast<audio_format_t>(f);
75 });
76 return processReturn("getAudioProperties", ret);
77}
78
79status_t StreamHalHidl::setParameters(const String8& kvPairs) {
80 if (!mStream) return NO_INIT;
81 hidl_vec<ParameterValue> hidlParams;
82 status_t status = parametersFromHal(kvPairs, &hidlParams);
83 if (status != OK) return status;
84 return processReturn("setParameters", mStream->setParameters(hidlParams));
85}
86
87status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
88 values->clear();
89 if (!mStream) return NO_INIT;
90 hidl_vec<hidl_string> hidlKeys;
91 status_t status = keysFromHal(keys, &hidlKeys);
92 if (status != OK) return status;
93 Result retval;
94 Return<void> ret = mStream->getParameters(
95 hidlKeys,
96 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
97 retval = r;
98 if (retval == Result::OK) {
99 parametersToHal(parameters, values);
100 }
101 });
102 return processReturn("getParameters", ret, retval);
103}
104
105status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
106 if (!mStream) return NO_INIT;
107 return processReturn("addEffect", mStream->addEffect(
108 static_cast<EffectHalHidl*>(effect.get())->effectId()));
109}
110
111status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
112 if (!mStream) return NO_INIT;
113 return processReturn("removeEffect", mStream->removeEffect(
114 static_cast<EffectHalHidl*>(effect.get())->effectId()));
115}
116
117status_t StreamHalHidl::standby() {
118 if (!mStream) return NO_INIT;
119 return processReturn("standby", mStream->standby());
120}
121
122status_t StreamHalHidl::dump(int fd) {
123 if (!mStream) return NO_INIT;
124 native_handle_t* hidlHandle = native_handle_create(1, 0);
125 hidlHandle->data[0] = fd;
126 Return<void> ret = mStream->debugDump(hidlHandle);
127 native_handle_delete(hidlHandle);
128 return processReturn("dump", ret);
129}
130
131
132namespace {
133
134/* Notes on callback ownership.
135
136This is how (Hw)Binder ownership model looks like. The server implementation
137is owned by Binder framework (via sp<>). Proxies are owned by clients.
138When the last proxy disappears, Binder framework releases the server impl.
139
140Thus, it is not needed to keep any references to StreamOutCallback (this is
141the server impl) -- it will live as long as HAL server holds a strong ref to
142IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
143from the destructor of StreamOutHalHidl.
144
145The callback only keeps a weak reference to the stream. The stream is owned
146by AudioFlinger.
147
148*/
149
150struct StreamOutCallback : public IStreamOutCallback {
151 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
152
153 // IStreamOutCallback implementation
154 Return<void> onWriteReady() override {
155 sp<StreamOutHalHidl> stream = mStream.promote();
156 if (stream != 0) {
157 stream->onWriteReady();
158 }
159 return Void();
160 }
161
162 Return<void> onDrainReady() override {
163 sp<StreamOutHalHidl> stream = mStream.promote();
164 if (stream != 0) {
165 stream->onDrainReady();
166 }
167 return Void();
168 }
169
170 Return<void> onError() override {
171 sp<StreamOutHalHidl> stream = mStream.promote();
172 if (stream != 0) {
173 stream->onError();
174 }
175 return Void();
176 }
177
178 private:
179 wp<StreamOutHalHidl> mStream;
180};
181
182} // namespace
183
184StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
185 : StreamHalHidl(stream.get()), mStream(stream) {
186}
187
188StreamOutHalHidl::~StreamOutHalHidl() {
189 if (mCallback.unsafe_get() && mStream != 0) {
190 processReturn("clearCallback", mStream->clearCallback());
191 }
192 mCallback.clear();
193}
194
195status_t StreamOutHalHidl::getFrameSize(size_t *size) {
196 if (mStream == 0) return NO_INIT;
197 return processReturn("getFrameSize", mStream->getFrameSize(), size);
198}
199
200status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
201 if (mStream == 0) return NO_INIT;
202 return processReturn("getLatency", mStream->getLatency(), latency);
203}
204
205status_t StreamOutHalHidl::setVolume(float left, float right) {
206 if (mStream == 0) return NO_INIT;
207 return processReturn("setVolume", mStream->setVolume(left, right));
208}
209
210status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
211 if (mStream == 0) return NO_INIT;
212 hidl_vec<uint8_t> hidlData;
213 hidlData.setToExternal(static_cast<uint8_t*>(const_cast<void*>(buffer)), bytes);
214 Result retval;
215 Return<void> ret = mStream->write(
216 hidlData,
217 [&](Result r, uint64_t w) {
218 retval = r;
219 *written = w;
220 });
221 return processReturn("write", ret, retval);
222}
223
224status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
225 if (mStream == 0) return NO_INIT;
226 Result retval;
227 Return<void> ret = mStream->getRenderPosition(
228 [&](Result r, uint32_t d) {
229 retval = r;
230 if (retval == Result::OK) {
231 *dspFrames = d;
232 }
233 });
234 return processReturn("getRenderPosition", ret, retval);
235}
236
237status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
238 if (mStream == 0) return NO_INIT;
239 Result retval;
240 Return<void> ret = mStream->getNextWriteTimestamp(
241 [&](Result r, int64_t t) {
242 retval = r;
243 if (retval == Result::OK) {
244 *timestamp = t;
245 }
246 });
247 return processReturn("getRenderPosition", ret, retval);
248}
249
250status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
251 if (mStream == 0) return NO_INIT;
252 status_t status = processReturn(
253 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
254 if (status == OK) {
255 mCallback = callback;
256 }
257 return status;
258}
259
260status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
261 if (mStream == 0) return NO_INIT;
262 Return<void> ret = mStream->supportsPauseAndResume(
263 [&](bool p, bool r) {
264 *supportsPause = p;
265 *supportsResume = r;
266 });
267 return processReturn("supportsPauseAndResume", ret);
268}
269
270status_t StreamOutHalHidl::pause() {
271 if (mStream == 0) return NO_INIT;
272 return processReturn("pause", mStream->pause());
273}
274
275status_t StreamOutHalHidl::resume() {
276 if (mStream == 0) return NO_INIT;
277 return processReturn("pause", mStream->resume());
278}
279
280status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
281 if (mStream == 0) return NO_INIT;
282 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
283}
284
285status_t StreamOutHalHidl::drain(bool earlyNotify) {
286 if (mStream == 0) return NO_INIT;
287 return processReturn(
288 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
289}
290
291status_t StreamOutHalHidl::flush() {
292 if (mStream == 0) return NO_INIT;
293 return processReturn("pause", mStream->flush());
294}
295
296status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
297 if (mStream == 0) return NO_INIT;
298 Result retval;
299 Return<void> ret = mStream->getPresentationPosition(
300 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
301 retval = r;
302 if (retval == Result::OK) {
303 *frames = hidlFrames;
304 timestamp->tv_sec = hidlTimeStamp.tvSec;
305 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
306 }
307 });
308 return processReturn("getPresentationPosition", ret, retval);
309}
310
311void StreamOutHalHidl::onWriteReady() {
312 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
313 if (callback == 0) return;
314 ALOGV("asyncCallback onWriteReady");
315 callback->onWriteReady();
316}
317
318void StreamOutHalHidl::onDrainReady() {
319 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
320 if (callback == 0) return;
321 ALOGV("asyncCallback onDrainReady");
322 callback->onDrainReady();
323}
324
325void StreamOutHalHidl::onError() {
326 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
327 if (callback == 0) return;
328 ALOGV("asyncCallback onError");
329 callback->onError();
330}
331
332
333StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
334 : StreamHalHidl(stream.get()), mStream(stream) {
335}
336
337StreamInHalHidl::~StreamInHalHidl() {
338}
339
340status_t StreamInHalHidl::getFrameSize(size_t *size) {
341 if (mStream == 0) return NO_INIT;
342 return processReturn("getFrameSize", mStream->getFrameSize(), size);
343}
344
345status_t StreamInHalHidl::setGain(float gain) {
346 if (mStream == 0) return NO_INIT;
347 return processReturn("setGain", mStream->setGain(gain));
348}
349
350status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
351 if (mStream == 0) return NO_INIT;
352 Result retval;
353 Return<void> ret = mStream->read(
354 bytes,
355 [&](Result r, const hidl_vec<uint8_t>& hidlData) {
356 retval = r;
357 *read = std::min(hidlData.size(), bytes);
358 if (retval == Result::OK) {
359 memcpy(buffer, &hidlData[0], *read);
360 }
361 });
362 return processReturn("read", ret, retval);
363}
364
365status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
366 if (mStream == 0) return NO_INIT;
367 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
368}
369
370status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
371 if (mStream == 0) return NO_INIT;
372 Result retval;
373 Return<void> ret = mStream->getCapturePosition(
374 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
375 retval = r;
376 if (retval == Result::OK) {
377 *frames = hidlFrames;
378 *time = hidlTime;
379 }
380 });
381 return processReturn("getCapturePosition", ret, retval);
382}
383
384} // namespace android