blob: 2c6e564e12d150d968bcd247a03ae3cd8c6f463c [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;
Eric Laurentaf35aad2016-12-15 14:25:36 -080034using ::android::hardware::audio::V2_0::MmapBufferInfo;
35using ::android::hardware::audio::V2_0::MmapPosition;
Mikhail Naganovf558e022016-11-14 17:45:17 -080036using ::android::hardware::Return;
37using ::android::hardware::Void;
38
39namespace android {
40
41StreamHalHidl::StreamHalHidl(IStream *stream)
42 : ConversionHelperHidl("Stream"), mStream(stream) {
43}
44
45StreamHalHidl::~StreamHalHidl() {
46 mStream = nullptr;
47}
48
49status_t StreamHalHidl::getSampleRate(uint32_t *rate) {
50 if (!mStream) return NO_INIT;
51 return processReturn("getSampleRate", mStream->getSampleRate(), rate);
52}
53
54status_t StreamHalHidl::getBufferSize(size_t *size) {
55 if (!mStream) return NO_INIT;
56 return processReturn("getBufferSize", mStream->getBufferSize(), size);
57}
58
59status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) {
60 if (!mStream) return NO_INIT;
61 return processReturn("getChannelMask", mStream->getChannelMask(), mask);
62}
63
64status_t StreamHalHidl::getFormat(audio_format_t *format) {
65 if (!mStream) return NO_INIT;
66 return processReturn("getFormat", mStream->getFormat(), format);
67}
68
69status_t StreamHalHidl::getAudioProperties(
70 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
71 if (!mStream) return NO_INIT;
72 Return<void> ret = mStream->getAudioProperties(
73 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) {
74 *sampleRate = sr;
75 *mask = static_cast<audio_channel_mask_t>(m);
76 *format = static_cast<audio_format_t>(f);
77 });
78 return processReturn("getAudioProperties", ret);
79}
80
81status_t StreamHalHidl::setParameters(const String8& kvPairs) {
82 if (!mStream) return NO_INIT;
83 hidl_vec<ParameterValue> hidlParams;
84 status_t status = parametersFromHal(kvPairs, &hidlParams);
85 if (status != OK) return status;
86 return processReturn("setParameters", mStream->setParameters(hidlParams));
87}
88
89status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
90 values->clear();
91 if (!mStream) return NO_INIT;
92 hidl_vec<hidl_string> hidlKeys;
93 status_t status = keysFromHal(keys, &hidlKeys);
94 if (status != OK) return status;
95 Result retval;
96 Return<void> ret = mStream->getParameters(
97 hidlKeys,
98 [&](Result r, const hidl_vec<ParameterValue>& parameters) {
99 retval = r;
100 if (retval == Result::OK) {
101 parametersToHal(parameters, values);
102 }
103 });
104 return processReturn("getParameters", ret, retval);
105}
106
107status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) {
108 if (!mStream) return NO_INIT;
109 return processReturn("addEffect", mStream->addEffect(
110 static_cast<EffectHalHidl*>(effect.get())->effectId()));
111}
112
113status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) {
114 if (!mStream) return NO_INIT;
115 return processReturn("removeEffect", mStream->removeEffect(
116 static_cast<EffectHalHidl*>(effect.get())->effectId()));
117}
118
119status_t StreamHalHidl::standby() {
120 if (!mStream) return NO_INIT;
121 return processReturn("standby", mStream->standby());
122}
123
124status_t StreamHalHidl::dump(int fd) {
125 if (!mStream) return NO_INIT;
126 native_handle_t* hidlHandle = native_handle_create(1, 0);
127 hidlHandle->data[0] = fd;
128 Return<void> ret = mStream->debugDump(hidlHandle);
129 native_handle_delete(hidlHandle);
130 return processReturn("dump", ret);
131}
132
Eric Laurentaf35aad2016-12-15 14:25:36 -0800133status_t StreamHalHidl::start() {
134 if (!mStream) return NO_INIT;
135 return processReturn("start", mStream->start());
136}
137
138status_t StreamHalHidl::stop() {
139 if (!mStream) return NO_INIT;
140 return processReturn("stop", mStream->stop());
141}
142
143status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames,
144 struct audio_mmap_buffer_info *info) {
145 Result retval;
146 Return<void> ret = mStream->createMmapBuffer(
147 minSizeFrames,
148 [&](Result r, const MmapBufferInfo& hidlInfo) {
149 retval = r;
150 if (retval == Result::OK) {
Eric Laurentb8753072016-12-21 12:04:10 -0800151 const native_handle *handle = hidlInfo.sharedMemory.handle();
Eric Laurentaf35aad2016-12-15 14:25:36 -0800152 if (handle->numFds > 0) {
153 info->shared_memory_fd = dup(handle->data[0]);
154 info->buffer_size_frames = hidlInfo.bufferSizeFrames;
155 info->burst_size_frames = hidlInfo.burstSizeFrames;
156 // info->shared_memory_address is not needed in HIDL context
157 info->shared_memory_address = NULL;
158 } else {
159 retval = Result::NOT_INITIALIZED;
160 }
161 }
162 });
163 return processReturn("createMmapBuffer", ret, retval);
164}
165
166status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) {
167 Result retval;
168 Return<void> ret = mStream->getMmapPosition(
169 [&](Result r, const MmapPosition& hidlPosition) {
170 retval = r;
171 if (retval == Result::OK) {
172 position->time_nanoseconds = hidlPosition.timeNanoseconds;
173 position->position_frames = hidlPosition.positionFrames;
174 }
175 });
176 return processReturn("getMmapPosition", ret, retval);
177}
Mikhail Naganovf558e022016-11-14 17:45:17 -0800178
179namespace {
180
181/* Notes on callback ownership.
182
183This is how (Hw)Binder ownership model looks like. The server implementation
184is owned by Binder framework (via sp<>). Proxies are owned by clients.
185When the last proxy disappears, Binder framework releases the server impl.
186
187Thus, it is not needed to keep any references to StreamOutCallback (this is
188the server impl) -- it will live as long as HAL server holds a strong ref to
189IStreamOutCallback proxy. We clear that reference by calling 'clearCallback'
190from the destructor of StreamOutHalHidl.
191
192The callback only keeps a weak reference to the stream. The stream is owned
193by AudioFlinger.
194
195*/
196
197struct StreamOutCallback : public IStreamOutCallback {
198 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
199
200 // IStreamOutCallback implementation
201 Return<void> onWriteReady() override {
202 sp<StreamOutHalHidl> stream = mStream.promote();
203 if (stream != 0) {
204 stream->onWriteReady();
205 }
206 return Void();
207 }
208
209 Return<void> onDrainReady() override {
210 sp<StreamOutHalHidl> stream = mStream.promote();
211 if (stream != 0) {
212 stream->onDrainReady();
213 }
214 return Void();
215 }
216
217 Return<void> onError() override {
218 sp<StreamOutHalHidl> stream = mStream.promote();
219 if (stream != 0) {
220 stream->onError();
221 }
222 return Void();
223 }
224
225 private:
226 wp<StreamOutHalHidl> mStream;
227};
228
229} // namespace
230
231StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
232 : StreamHalHidl(stream.get()), mStream(stream) {
233}
234
235StreamOutHalHidl::~StreamOutHalHidl() {
236 if (mCallback.unsafe_get() && mStream != 0) {
237 processReturn("clearCallback", mStream->clearCallback());
238 }
239 mCallback.clear();
240}
241
242status_t StreamOutHalHidl::getFrameSize(size_t *size) {
243 if (mStream == 0) return NO_INIT;
244 return processReturn("getFrameSize", mStream->getFrameSize(), size);
245}
246
247status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
248 if (mStream == 0) return NO_INIT;
249 return processReturn("getLatency", mStream->getLatency(), latency);
250}
251
252status_t StreamOutHalHidl::setVolume(float left, float right) {
253 if (mStream == 0) return NO_INIT;
254 return processReturn("setVolume", mStream->setVolume(left, right));
255}
256
257status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
258 if (mStream == 0) return NO_INIT;
259 hidl_vec<uint8_t> hidlData;
260 hidlData.setToExternal(static_cast<uint8_t*>(const_cast<void*>(buffer)), bytes);
261 Result retval;
262 Return<void> ret = mStream->write(
263 hidlData,
264 [&](Result r, uint64_t w) {
265 retval = r;
266 *written = w;
267 });
268 return processReturn("write", ret, retval);
269}
270
271status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) {
272 if (mStream == 0) return NO_INIT;
273 Result retval;
274 Return<void> ret = mStream->getRenderPosition(
275 [&](Result r, uint32_t d) {
276 retval = r;
277 if (retval == Result::OK) {
278 *dspFrames = d;
279 }
280 });
281 return processReturn("getRenderPosition", ret, retval);
282}
283
284status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) {
285 if (mStream == 0) return NO_INIT;
286 Result retval;
287 Return<void> ret = mStream->getNextWriteTimestamp(
288 [&](Result r, int64_t t) {
289 retval = r;
290 if (retval == Result::OK) {
291 *timestamp = t;
292 }
293 });
294 return processReturn("getRenderPosition", ret, retval);
295}
296
297status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
298 if (mStream == 0) return NO_INIT;
299 status_t status = processReturn(
300 "setCallback", mStream->setCallback(new StreamOutCallback(this)));
301 if (status == OK) {
302 mCallback = callback;
303 }
304 return status;
305}
306
307status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
308 if (mStream == 0) return NO_INIT;
309 Return<void> ret = mStream->supportsPauseAndResume(
310 [&](bool p, bool r) {
311 *supportsPause = p;
312 *supportsResume = r;
313 });
314 return processReturn("supportsPauseAndResume", ret);
315}
316
317status_t StreamOutHalHidl::pause() {
318 if (mStream == 0) return NO_INIT;
319 return processReturn("pause", mStream->pause());
320}
321
322status_t StreamOutHalHidl::resume() {
323 if (mStream == 0) return NO_INIT;
324 return processReturn("pause", mStream->resume());
325}
326
327status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) {
328 if (mStream == 0) return NO_INIT;
329 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain);
330}
331
332status_t StreamOutHalHidl::drain(bool earlyNotify) {
333 if (mStream == 0) return NO_INIT;
334 return processReturn(
335 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL));
336}
337
338status_t StreamOutHalHidl::flush() {
339 if (mStream == 0) return NO_INIT;
340 return processReturn("pause", mStream->flush());
341}
342
343status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
344 if (mStream == 0) return NO_INIT;
345 Result retval;
346 Return<void> ret = mStream->getPresentationPosition(
347 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
348 retval = r;
349 if (retval == Result::OK) {
350 *frames = hidlFrames;
351 timestamp->tv_sec = hidlTimeStamp.tvSec;
352 timestamp->tv_nsec = hidlTimeStamp.tvNSec;
353 }
354 });
355 return processReturn("getPresentationPosition", ret, retval);
356}
357
358void StreamOutHalHidl::onWriteReady() {
359 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
360 if (callback == 0) return;
361 ALOGV("asyncCallback onWriteReady");
362 callback->onWriteReady();
363}
364
365void StreamOutHalHidl::onDrainReady() {
366 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
367 if (callback == 0) return;
368 ALOGV("asyncCallback onDrainReady");
369 callback->onDrainReady();
370}
371
372void StreamOutHalHidl::onError() {
373 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
374 if (callback == 0) return;
375 ALOGV("asyncCallback onError");
376 callback->onError();
377}
378
379
380StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
381 : StreamHalHidl(stream.get()), mStream(stream) {
382}
383
384StreamInHalHidl::~StreamInHalHidl() {
385}
386
387status_t StreamInHalHidl::getFrameSize(size_t *size) {
388 if (mStream == 0) return NO_INIT;
389 return processReturn("getFrameSize", mStream->getFrameSize(), size);
390}
391
392status_t StreamInHalHidl::setGain(float gain) {
393 if (mStream == 0) return NO_INIT;
394 return processReturn("setGain", mStream->setGain(gain));
395}
396
397status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) {
398 if (mStream == 0) return NO_INIT;
399 Result retval;
400 Return<void> ret = mStream->read(
401 bytes,
402 [&](Result r, const hidl_vec<uint8_t>& hidlData) {
403 retval = r;
404 *read = std::min(hidlData.size(), bytes);
405 if (retval == Result::OK) {
406 memcpy(buffer, &hidlData[0], *read);
407 }
408 });
409 return processReturn("read", ret, retval);
410}
411
412status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) {
413 if (mStream == 0) return NO_INIT;
414 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost);
415}
416
417status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
418 if (mStream == 0) return NO_INIT;
419 Result retval;
420 Return<void> ret = mStream->getCapturePosition(
421 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
422 retval = r;
423 if (retval == Result::OK) {
424 *frames = hidlFrames;
425 *time = hidlTime;
426 }
427 });
428 return processReturn("getCapturePosition", ret, retval);
429}
430
431} // namespace android