blob: 3d20d11dfb12bd4d1da35fe8dbabaeaa403e1097 [file] [log] [blame]
Mikhail Naganov10548292016-10-31 10:39:47 -07001/*
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 "StreamOutHAL"
Mikhail Naganov685f0e32016-12-16 17:18:08 -080018//#define LOG_NDEBUG 0
Mikhail Naganov10548292016-10-31 10:39:47 -070019
20#include <hardware/audio.h>
Yifan Hongf9d30342016-11-30 13:45:34 -080021#include <android/log.h>
Mikhail Naganov10548292016-10-31 10:39:47 -070022
23#include "StreamOut.h"
24
25namespace android {
26namespace hardware {
27namespace audio {
28namespace V2_0 {
29namespace implementation {
30
31StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream)
Eric Laurent7deb7da2016-12-15 19:15:45 -080032 : mDevice(device), mStream(stream),
33 mStreamCommon(new Stream(&stream->common)),
34 mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)) {
Mikhail Naganov10548292016-10-31 10:39:47 -070035}
36
37StreamOut::~StreamOut() {
38 mCallback.clear();
39 mDevice->close_output_stream(mDevice, mStream);
40 mStream = nullptr;
41 mDevice = nullptr;
42}
43
44// Methods from ::android::hardware::audio::V2_0::IStream follow.
45Return<uint64_t> StreamOut::getFrameSize() {
46 return audio_stream_out_frame_size(mStream);
47}
48
49Return<uint64_t> StreamOut::getFrameCount() {
50 return mStreamCommon->getFrameCount();
51}
52
53Return<uint64_t> StreamOut::getBufferSize() {
54 return mStreamCommon->getBufferSize();
55}
56
57Return<uint32_t> StreamOut::getSampleRate() {
58 return mStreamCommon->getSampleRate();
59}
60
61Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
62 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
63}
64
65Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
66 return mStreamCommon->setSampleRate(sampleRateHz);
67}
68
69Return<AudioChannelMask> StreamOut::getChannelMask() {
70 return mStreamCommon->getChannelMask();
71}
72
73Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
74 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
75}
76
77Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
78 return mStreamCommon->setChannelMask(mask);
79}
80
81Return<AudioFormat> StreamOut::getFormat() {
82 return mStreamCommon->getFormat();
83}
84
85Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
86 return mStreamCommon->getSupportedFormats(_hidl_cb);
87}
88
89Return<Result> StreamOut::setFormat(AudioFormat format) {
90 return mStreamCommon->setFormat(format);
91}
92
93Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
94 return mStreamCommon->getAudioProperties(_hidl_cb);
95}
96
97Return<Result> StreamOut::addEffect(uint64_t effectId) {
98 return mStreamCommon->addEffect(effectId);
99}
100
101Return<Result> StreamOut::removeEffect(uint64_t effectId) {
102 return mStreamCommon->removeEffect(effectId);
103}
104
105Return<Result> StreamOut::standby() {
106 return mStreamCommon->standby();
107}
108
109Return<AudioDevice> StreamOut::getDevice() {
110 return mStreamCommon->getDevice();
111}
112
113Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
114 return mStreamCommon->setDevice(address);
115}
116
117Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
118 return mStreamCommon->setConnectedState(address, connected);
119}
120
121Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
122 return mStreamCommon->setHwAvSync(hwAvSync);
123}
124
125Return<void> StreamOut::getParameters(
126 const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
127 return mStreamCommon->getParameters(keys, _hidl_cb);
128}
129
130Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
131 return mStreamCommon->setParameters(parameters);
132}
133
Martijn Coenen70b9a152016-11-18 15:29:32 +0100134Return<void> StreamOut::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700135 return mStreamCommon->debugDump(fd);
136}
137
Mikhail Naganov10548292016-10-31 10:39:47 -0700138// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
139Return<uint32_t> StreamOut::getLatency() {
140 return mStream->get_latency(mStream);
141}
142
143Return<Result> StreamOut::setVolume(float left, float right) {
144 Result retval(Result::NOT_SUPPORTED);
145 if (mStream->set_volume != NULL) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800146 retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700147 "set_volume", mStream->set_volume(mStream, left, right));
148 }
149 return retval;
150}
151
152Return<void> StreamOut::write(const hidl_vec<uint8_t>& data, write_cb _hidl_cb) {
153 // TODO(mnaganov): Replace with FMQ version.
154 Result retval(Result::OK);
155 uint64_t written = 0;
156 ssize_t writeResult = mStream->write(mStream, &data[0], data.size());
157 if (writeResult >= 0) {
158 written = writeResult;
159 } else {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800160 retval = Stream::analyzeStatus("write", writeResult);
Mikhail Naganov10548292016-10-31 10:39:47 -0700161 written = 0;
162 }
163 _hidl_cb(retval, written);
164 return Void();
165}
166
167Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
168 uint32_t halDspFrames;
Eric Laurent7deb7da2016-12-15 19:15:45 -0800169 Result retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700170 "get_render_position", mStream->get_render_position(mStream, &halDspFrames));
171 _hidl_cb(retval, halDspFrames);
172 return Void();
173}
174
175Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
176 Result retval(Result::NOT_SUPPORTED);
177 int64_t timestampUs = 0;
178 if (mStream->get_next_write_timestamp != NULL) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800179 retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700180 "get_next_write_timestamp",
181 mStream->get_next_write_timestamp(mStream, &timestampUs));
182 }
183 _hidl_cb(retval, timestampUs);
184 return Void();
185}
186
187Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
188 if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
189 int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
190 if (result == 0) {
191 mCallback = callback;
192 }
Eric Laurent7deb7da2016-12-15 19:15:45 -0800193 return Stream::analyzeStatus("set_callback", result);
Mikhail Naganov10548292016-10-31 10:39:47 -0700194}
195
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800196Return<Result> StreamOut::clearCallback() {
197 if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
198 mCallback.clear();
199 return Result::OK;
200}
201
Mikhail Naganov10548292016-10-31 10:39:47 -0700202// static
203int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
204 wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie));
205 sp<StreamOut> self = weakSelf.promote();
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800206 if (self == nullptr || self->mCallback == nullptr) return 0;
Mikhail Naganov10548292016-10-31 10:39:47 -0700207 ALOGV("asyncCallback() event %d", event);
208 switch (event) {
209 case STREAM_CBK_EVENT_WRITE_READY:
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800210 self->mCallback->onWriteReady();
Mikhail Naganov10548292016-10-31 10:39:47 -0700211 break;
212 case STREAM_CBK_EVENT_DRAIN_READY:
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800213 self->mCallback->onDrainReady();
Mikhail Naganov10548292016-10-31 10:39:47 -0700214 break;
215 case STREAM_CBK_EVENT_ERROR:
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800216 self->mCallback->onError();
Mikhail Naganov10548292016-10-31 10:39:47 -0700217 break;
218 default:
219 ALOGW("asyncCallback() unknown event %d", event);
220 break;
221 }
222 return 0;
223}
224
225Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
226 _hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
227 return Void();
228}
229
230Return<Result> StreamOut::pause() {
231 return mStream->pause != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800232 Stream::analyzeStatus("pause", mStream->pause(mStream)) :
Mikhail Naganov10548292016-10-31 10:39:47 -0700233 Result::NOT_SUPPORTED;
234}
235
236Return<Result> StreamOut::resume() {
237 return mStream->resume != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800238 Stream::analyzeStatus("resume", mStream->resume(mStream)) :
Mikhail Naganov10548292016-10-31 10:39:47 -0700239 Result::NOT_SUPPORTED;
240}
241
242Return<bool> StreamOut::supportsDrain() {
243 return mStream->drain != NULL;
244}
245
246Return<Result> StreamOut::drain(AudioDrain type) {
247 return mStream->drain != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800248 Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700249 "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) :
250 Result::NOT_SUPPORTED;
251}
252
253Return<Result> StreamOut::flush() {
254 return mStream->flush != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800255 Stream::analyzeStatus("flush", mStream->flush(mStream)) :
Mikhail Naganov10548292016-10-31 10:39:47 -0700256 Result::NOT_SUPPORTED;
257}
258
259Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
260 Result retval(Result::NOT_SUPPORTED);
261 uint64_t frames = 0;
262 TimeSpec timeStamp = { 0, 0 };
263 if (mStream->get_presentation_position != NULL) {
264 struct timespec halTimeStamp;
Eric Laurent7deb7da2016-12-15 19:15:45 -0800265 retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700266 "get_presentation_position",
Mikhail Naganov13f43f42016-12-07 17:05:40 -0800267 mStream->get_presentation_position(mStream, &frames, &halTimeStamp),
268 // Don't logspam on EINVAL--it's normal for get_presentation_position
269 // to return it sometimes.
270 EINVAL);
Mikhail Naganov10548292016-10-31 10:39:47 -0700271 if (retval == Result::OK) {
272 timeStamp.tvSec = halTimeStamp.tv_sec;
273 timeStamp.tvNSec = halTimeStamp.tv_nsec;
274 }
275 }
276 _hidl_cb(retval, frames, timeStamp);
277 return Void();
278}
279
Eric Laurent7deb7da2016-12-15 19:15:45 -0800280Return<Result> StreamOut::start() {
281 return mStreamMmap->start();
282}
283
284Return<Result> StreamOut::stop() {
285 return mStreamMmap->stop();
286}
287
288Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
289 return mStreamMmap->createMmapBuffer(
290 minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb);
291}
292
293Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
294 return mStreamMmap->getMmapPosition(_hidl_cb);
295}
296
Mikhail Naganov10548292016-10-31 10:39:47 -0700297} // namespace implementation
298} // namespace V2_0
299} // namespace audio
300} // namespace hardware
301} // namespace android