blob: 805734b76f41d742f7a7258f52c563e19c5a7087 [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)
32 : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)) {
33}
34
35StreamOut::~StreamOut() {
36 mCallback.clear();
37 mDevice->close_output_stream(mDevice, mStream);
38 mStream = nullptr;
39 mDevice = nullptr;
40}
41
42// Methods from ::android::hardware::audio::V2_0::IStream follow.
43Return<uint64_t> StreamOut::getFrameSize() {
44 return audio_stream_out_frame_size(mStream);
45}
46
47Return<uint64_t> StreamOut::getFrameCount() {
48 return mStreamCommon->getFrameCount();
49}
50
51Return<uint64_t> StreamOut::getBufferSize() {
52 return mStreamCommon->getBufferSize();
53}
54
55Return<uint32_t> StreamOut::getSampleRate() {
56 return mStreamCommon->getSampleRate();
57}
58
59Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
60 return mStreamCommon->getSupportedSampleRates(_hidl_cb);
61}
62
63Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
64 return mStreamCommon->setSampleRate(sampleRateHz);
65}
66
67Return<AudioChannelMask> StreamOut::getChannelMask() {
68 return mStreamCommon->getChannelMask();
69}
70
71Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
72 return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
73}
74
75Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
76 return mStreamCommon->setChannelMask(mask);
77}
78
79Return<AudioFormat> StreamOut::getFormat() {
80 return mStreamCommon->getFormat();
81}
82
83Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
84 return mStreamCommon->getSupportedFormats(_hidl_cb);
85}
86
87Return<Result> StreamOut::setFormat(AudioFormat format) {
88 return mStreamCommon->setFormat(format);
89}
90
91Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
92 return mStreamCommon->getAudioProperties(_hidl_cb);
93}
94
95Return<Result> StreamOut::addEffect(uint64_t effectId) {
96 return mStreamCommon->addEffect(effectId);
97}
98
99Return<Result> StreamOut::removeEffect(uint64_t effectId) {
100 return mStreamCommon->removeEffect(effectId);
101}
102
103Return<Result> StreamOut::standby() {
104 return mStreamCommon->standby();
105}
106
107Return<AudioDevice> StreamOut::getDevice() {
108 return mStreamCommon->getDevice();
109}
110
111Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
112 return mStreamCommon->setDevice(address);
113}
114
115Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
116 return mStreamCommon->setConnectedState(address, connected);
117}
118
119Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
120 return mStreamCommon->setHwAvSync(hwAvSync);
121}
122
123Return<void> StreamOut::getParameters(
124 const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
125 return mStreamCommon->getParameters(keys, _hidl_cb);
126}
127
128Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
129 return mStreamCommon->setParameters(parameters);
130}
131
Martijn Coenen70b9a152016-11-18 15:29:32 +0100132Return<void> StreamOut::debugDump(const hidl_handle& fd) {
Mikhail Naganov10548292016-10-31 10:39:47 -0700133 return mStreamCommon->debugDump(fd);
134}
135
136
137// 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) {
145 retval = mStreamCommon->analyzeStatus(
146 "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 {
159 retval = mStreamCommon->analyzeStatus("write", writeResult);
160 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;
168 Result retval = mStreamCommon->analyzeStatus(
169 "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) {
178 retval = mStreamCommon->analyzeStatus(
179 "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 }
192 return mStreamCommon->analyzeStatus("set_callback", result);
193}
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 ?
231 mStreamCommon->analyzeStatus("pause", mStream->pause(mStream)) :
232 Result::NOT_SUPPORTED;
233}
234
235Return<Result> StreamOut::resume() {
236 return mStream->resume != NULL ?
237 mStreamCommon->analyzeStatus("resume", mStream->resume(mStream)) :
238 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 ?
247 mStreamCommon->analyzeStatus(
248 "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 ?
254 mStreamCommon->analyzeStatus("flush", mStream->flush(mStream)) :
255 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;
264 retval = mStreamCommon->analyzeStatus(
265 "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
279} // namespace implementation
280} // namespace V2_0
281} // namespace audio
282} // namespace hardware
283} // namespace android