blob: 1ccd2a9c92173a3c5f0e37a1361ead9b4624b18d [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"
18
19#include <hardware/audio.h>
Yifan Hongf9d30342016-11-30 13:45:34 -080020#include <android/log.h>
Mikhail Naganov10548292016-10-31 10:39:47 -070021
22#include "StreamOut.h"
23
24namespace android {
25namespace hardware {
26namespace audio {
27namespace V2_0 {
28namespace implementation {
29
30StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream)
Eric Laurent7deb7da2016-12-15 19:15:45 -080031 : mDevice(device), mStream(stream),
32 mStreamCommon(new Stream(&stream->common)),
33 mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)) {
Mikhail Naganov10548292016-10-31 10:39:47 -070034}
35
36StreamOut::~StreamOut() {
37 mCallback.clear();
38 mDevice->close_output_stream(mDevice, mStream);
39 mStream = nullptr;
40 mDevice = nullptr;
41}
42
43// Methods from ::android::hardware::audio::V2_0::IStream follow.
44Return<uint64_t> StreamOut::getFrameSize() {
45 return audio_stream_out_frame_size(mStream);
46}
47
48Return<uint64_t> StreamOut::getFrameCount() {
49 return mStreamCommon->getFrameCount();
50}
51
52Return<uint64_t> StreamOut::getBufferSize() {
53 return mStreamCommon->getBufferSize();
54}
55
56Return<uint32_t> StreamOut::getSampleRate() {
57 return mStreamCommon->getSampleRate();
58}
59
60Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
61 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
62}
63
64Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
65 return mStreamCommon->setSampleRate(sampleRateHz);
66}
67
68Return<AudioChannelMask> StreamOut::getChannelMask() {
69 return mStreamCommon->getChannelMask();
70}
71
72Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
73 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
74}
75
76Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
77 return mStreamCommon->setChannelMask(mask);
78}
79
80Return<AudioFormat> StreamOut::getFormat() {
81 return mStreamCommon->getFormat();
82}
83
84Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
85 return mStreamCommon->getSupportedFormats(_hidl_cb);
86}
87
88Return<Result> StreamOut::setFormat(AudioFormat format) {
89 return mStreamCommon->setFormat(format);
90}
91
92Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
93 return mStreamCommon->getAudioProperties(_hidl_cb);
94}
95
96Return<Result> StreamOut::addEffect(uint64_t effectId) {
97 return mStreamCommon->addEffect(effectId);
98}
99
100Return<Result> StreamOut::removeEffect(uint64_t effectId) {
101 return mStreamCommon->removeEffect(effectId);
102}
103
104Return<Result> StreamOut::standby() {
105 return mStreamCommon->standby();
106}
107
108Return<AudioDevice> StreamOut::getDevice() {
109 return mStreamCommon->getDevice();
110}
111
112Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
113 return mStreamCommon->setDevice(address);
114}
115
116Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
117 return mStreamCommon->setConnectedState(address, connected);
118}
119
120Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
121 return mStreamCommon->setHwAvSync(hwAvSync);
122}
123
124Return<void> StreamOut::getParameters(
125 const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
126 return mStreamCommon->getParameters(keys, _hidl_cb);
127}
128
129Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
130 return mStreamCommon->setParameters(parameters);
131}
132
Martijn Coenen70b9a152016-11-18 15:29:32 +0100133Return<void> StreamOut::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700134 return mStreamCommon->debugDump(fd);
135}
136
Mikhail Naganov10548292016-10-31 10:39:47 -0700137// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
138Return<uint32_t> StreamOut::getLatency() {
139 return mStream->get_latency(mStream);
140}
141
142Return<Result> StreamOut::setVolume(float left, float right) {
143 Result retval(Result::NOT_SUPPORTED);
144 if (mStream->set_volume != NULL) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800145 retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700146 "set_volume", mStream->set_volume(mStream, left, right));
147 }
148 return retval;
149}
150
151Return<void> StreamOut::write(const hidl_vec<uint8_t>& data, write_cb _hidl_cb) {
152 // TODO(mnaganov): Replace with FMQ version.
153 Result retval(Result::OK);
154 uint64_t written = 0;
155 ssize_t writeResult = mStream->write(mStream, &data[0], data.size());
156 if (writeResult >= 0) {
157 written = writeResult;
158 } else {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800159 retval = Stream::analyzeStatus("write", writeResult);
Mikhail Naganov10548292016-10-31 10:39:47 -0700160 written = 0;
161 }
162 _hidl_cb(retval, written);
163 return Void();
164}
165
166Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
167 uint32_t halDspFrames;
Eric Laurent7deb7da2016-12-15 19:15:45 -0800168 Result retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700169 "get_render_position", mStream->get_render_position(mStream, &halDspFrames));
170 _hidl_cb(retval, halDspFrames);
171 return Void();
172}
173
174Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
175 Result retval(Result::NOT_SUPPORTED);
176 int64_t timestampUs = 0;
177 if (mStream->get_next_write_timestamp != NULL) {
Eric Laurent7deb7da2016-12-15 19:15:45 -0800178 retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700179 "get_next_write_timestamp",
180 mStream->get_next_write_timestamp(mStream, &timestampUs));
181 }
182 _hidl_cb(retval, timestampUs);
183 return Void();
184}
185
186Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
187 if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
188 int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
189 if (result == 0) {
190 mCallback = callback;
191 }
Eric Laurent7deb7da2016-12-15 19:15:45 -0800192 return Stream::analyzeStatus("set_callback", result);
Mikhail Naganov10548292016-10-31 10:39:47 -0700193}
194
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800195Return<Result> StreamOut::clearCallback() {
196 if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
197 mCallback.clear();
198 return Result::OK;
199}
200
Mikhail Naganov10548292016-10-31 10:39:47 -0700201// static
202int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
203 wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie));
204 sp<StreamOut> self = weakSelf.promote();
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800205 if (self == nullptr || self->mCallback == nullptr) return 0;
Mikhail Naganov10548292016-10-31 10:39:47 -0700206 ALOGV("asyncCallback() event %d", event);
207 switch (event) {
208 case STREAM_CBK_EVENT_WRITE_READY:
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800209 self->mCallback->onWriteReady();
Mikhail Naganov10548292016-10-31 10:39:47 -0700210 break;
211 case STREAM_CBK_EVENT_DRAIN_READY:
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800212 self->mCallback->onDrainReady();
Mikhail Naganov10548292016-10-31 10:39:47 -0700213 break;
214 case STREAM_CBK_EVENT_ERROR:
Mikhail Naganov6e81e9b2016-11-16 16:30:17 -0800215 self->mCallback->onError();
Mikhail Naganov10548292016-10-31 10:39:47 -0700216 break;
217 default:
218 ALOGW("asyncCallback() unknown event %d", event);
219 break;
220 }
221 return 0;
222}
223
224Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
225 _hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
226 return Void();
227}
228
229Return<Result> StreamOut::pause() {
230 return mStream->pause != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800231 Stream::analyzeStatus("pause", mStream->pause(mStream)) :
Mikhail Naganov10548292016-10-31 10:39:47 -0700232 Result::NOT_SUPPORTED;
233}
234
235Return<Result> StreamOut::resume() {
236 return mStream->resume != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800237 Stream::analyzeStatus("resume", mStream->resume(mStream)) :
Mikhail Naganov10548292016-10-31 10:39:47 -0700238 Result::NOT_SUPPORTED;
239}
240
241Return<bool> StreamOut::supportsDrain() {
242 return mStream->drain != NULL;
243}
244
245Return<Result> StreamOut::drain(AudioDrain type) {
246 return mStream->drain != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800247 Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700248 "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) :
249 Result::NOT_SUPPORTED;
250}
251
252Return<Result> StreamOut::flush() {
253 return mStream->flush != NULL ?
Eric Laurent7deb7da2016-12-15 19:15:45 -0800254 Stream::analyzeStatus("flush", mStream->flush(mStream)) :
Mikhail Naganov10548292016-10-31 10:39:47 -0700255 Result::NOT_SUPPORTED;
256}
257
258Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
259 Result retval(Result::NOT_SUPPORTED);
260 uint64_t frames = 0;
261 TimeSpec timeStamp = { 0, 0 };
262 if (mStream->get_presentation_position != NULL) {
263 struct timespec halTimeStamp;
Eric Laurent7deb7da2016-12-15 19:15:45 -0800264 retval = Stream::analyzeStatus(
Mikhail Naganov10548292016-10-31 10:39:47 -0700265 "get_presentation_position",
Mikhail Naganov13f43f42016-12-07 17:05:40 -0800266 mStream->get_presentation_position(mStream, &frames, &halTimeStamp),
267 // Don't logspam on EINVAL--it's normal for get_presentation_position
268 // to return it sometimes.
269 EINVAL);
Mikhail Naganov10548292016-10-31 10:39:47 -0700270 if (retval == Result::OK) {
271 timeStamp.tvSec = halTimeStamp.tv_sec;
272 timeStamp.tvNSec = halTimeStamp.tv_nsec;
273 }
274 }
275 _hidl_cb(retval, frames, timeStamp);
276 return Void();
277}
278
Eric Laurent7deb7da2016-12-15 19:15:45 -0800279Return<Result> StreamOut::start() {
280 return mStreamMmap->start();
281}
282
283Return<Result> StreamOut::stop() {
284 return mStreamMmap->stop();
285}
286
287Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
288 return mStreamMmap->createMmapBuffer(
289 minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb);
290}
291
292Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
293 return mStreamMmap->getMmapPosition(_hidl_cb);
294}
295
Mikhail Naganov10548292016-10-31 10:39:47 -0700296} // namespace implementation
297} // namespace V2_0
298} // namespace audio
299} // namespace hardware
300} // namespace android