blob: dc17f5ce6c1df72d53b53ab880ce8bd252542a90 [file] [log] [blame]
Mikhail Naganov1dc98672016-08-18 17:50:29 -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
Mikhail Naganova0c91332016-09-19 10:01:12 -070017#define LOG_TAG "StreamHalLocal"
Mikhail Naganov1dc98672016-08-18 17:50:29 -070018//#define LOG_NDEBUG 0
19
Mikhail Naganovcbc8f612016-10-11 18:05:13 -070020#include <hardware/audio.h>
Mikhail Naganov1dc98672016-08-18 17:50:29 -070021#include <utils/Log.h>
22
23#include "DeviceHalLocal.h"
24#include "EffectHalLocal.h"
25#include "StreamHalLocal.h"
26
27namespace android {
28
29StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
Andy Hung953608f2017-06-13 15:21:49 -070030 : mDevice(device),
31 mStream(stream) {
32 // Instrument audio signal power logging.
33 // Note: This assumes channel mask, format, and sample rate do not change after creation.
34 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) {
35 mStreamPowerLog.init(mStream->get_sample_rate(mStream),
36 mStream->get_channels(mStream),
37 mStream->get_format(mStream));
38 }
Mikhail Naganov1dc98672016-08-18 17:50:29 -070039}
40
41StreamHalLocal::~StreamHalLocal() {
42 mStream = 0;
43 mDevice.clear();
44}
45
46status_t StreamHalLocal::getSampleRate(uint32_t *rate) {
47 *rate = mStream->get_sample_rate(mStream);
48 return OK;
49}
50
51status_t StreamHalLocal::getBufferSize(size_t *size) {
52 *size = mStream->get_buffer_size(mStream);
53 return OK;
54}
55
56status_t StreamHalLocal::getChannelMask(audio_channel_mask_t *mask) {
57 *mask = mStream->get_channels(mStream);
58 return OK;
59}
60
61status_t StreamHalLocal::getFormat(audio_format_t *format) {
62 *format = mStream->get_format(mStream);
63 return OK;
64}
65
66status_t StreamHalLocal::getAudioProperties(
67 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
68 *sampleRate = mStream->get_sample_rate(mStream);
69 *mask = mStream->get_channels(mStream);
70 *format = mStream->get_format(mStream);
71 return OK;
72}
73
74status_t StreamHalLocal::setParameters(const String8& kvPairs) {
75 return mStream->set_parameters(mStream, kvPairs.string());
76}
77
78status_t StreamHalLocal::getParameters(const String8& keys, String8 *values) {
79 char *halValues = mStream->get_parameters(mStream, keys.string());
80 if (halValues != NULL) {
81 values->setTo(halValues);
82 free(halValues);
83 } else {
84 values->clear();
85 }
86 return OK;
87}
88
89status_t StreamHalLocal::addEffect(sp<EffectHalInterface> effect) {
Mikhail Naganov6b111f32017-04-27 18:52:37 -070090 LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be added for a local stream");
Mikhail Naganov1dc98672016-08-18 17:50:29 -070091 return mStream->add_audio_effect(mStream,
92 static_cast<EffectHalLocal*>(effect.get())->handle());
93}
94
95status_t StreamHalLocal::removeEffect(sp<EffectHalInterface> effect) {
Mikhail Naganov6b111f32017-04-27 18:52:37 -070096 LOG_ALWAYS_FATAL_IF(!effect->isLocal(), "Only local effects can be removed for a local stream");
Mikhail Naganov1dc98672016-08-18 17:50:29 -070097 return mStream->remove_audio_effect(mStream,
98 static_cast<EffectHalLocal*>(effect.get())->handle());
99}
100
101status_t StreamHalLocal::standby() {
102 return mStream->standby(mStream);
103}
104
105status_t StreamHalLocal::dump(int fd) {
Andy Hung953608f2017-06-13 15:21:49 -0700106 status_t status = mStream->dump(mStream, fd);
107 mStreamPowerLog.dump(fd);
108 return status;
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700109}
110
Mikhail Naganove1c4b5d2016-12-22 09:22:45 -0800111status_t StreamHalLocal::setHalThreadPriority(int) {
112 // Don't need to do anything as local hal is executed by audioflinger directly
113 // on the same thread.
114 return OK;
115}
116
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700117StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device)
118 : StreamHalLocal(&stream->common, device), mStream(stream) {
119}
120
121StreamOutHalLocal::~StreamOutHalLocal() {
122 mCallback.clear();
123 mDevice->closeOutputStream(mStream);
124 mStream = 0;
125}
126
127status_t StreamOutHalLocal::getFrameSize(size_t *size) {
128 *size = audio_stream_out_frame_size(mStream);
129 return OK;
130}
131
132status_t StreamOutHalLocal::getLatency(uint32_t *latency) {
133 *latency = mStream->get_latency(mStream);
134 return OK;
135}
136
137status_t StreamOutHalLocal::setVolume(float left, float right) {
138 if (mStream->set_volume == NULL) return INVALID_OPERATION;
139 return mStream->set_volume(mStream, left, right);
140}
141
142status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
143 ssize_t writeResult = mStream->write(mStream, buffer, bytes);
144 if (writeResult > 0) {
145 *written = writeResult;
Andy Hung953608f2017-06-13 15:21:49 -0700146 mStreamPowerLog.log(buffer, *written);
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700147 return OK;
148 } else {
149 *written = 0;
150 return writeResult;
151 }
152}
153
154status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) {
155 return mStream->get_render_position(mStream, dspFrames);
156}
157
158status_t StreamOutHalLocal::getNextWriteTimestamp(int64_t *timestamp) {
159 if (mStream->get_next_write_timestamp == NULL) return INVALID_OPERATION;
160 return mStream->get_next_write_timestamp(mStream, timestamp);
161}
162
Mikhail Naganov15897e42016-09-30 16:16:41 -0700163status_t StreamOutHalLocal::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700164 if (mStream->set_callback == NULL) return INVALID_OPERATION;
165 status_t result = mStream->set_callback(mStream, StreamOutHalLocal::asyncCallback, this);
166 if (result == OK) {
167 mCallback = callback;
168 }
169 return result;
170}
171
172// static
173int StreamOutHalLocal::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
174 // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
175 // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
176 // already running, because the destructor is invoked after the refcount has been atomically
177 // decremented.
Mikhail Naganov6b111f32017-04-27 18:52:37 -0700178 wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700179 sp<StreamOutHalLocal> self = weakSelf.promote();
180 if (self == 0) return 0;
181 sp<StreamOutHalInterfaceCallback> callback = self->mCallback.promote();
182 if (callback == 0) return 0;
183 ALOGV("asyncCallback() event %d", event);
184 switch (event) {
185 case STREAM_CBK_EVENT_WRITE_READY:
186 callback->onWriteReady();
187 break;
188 case STREAM_CBK_EVENT_DRAIN_READY:
189 callback->onDrainReady();
190 break;
191 case STREAM_CBK_EVENT_ERROR:
192 callback->onError();
193 break;
194 default:
195 ALOGW("asyncCallback() unknown event %d", event);
196 break;
197 }
198 return 0;
199}
200
201status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
202 *supportsPause = mStream->pause != NULL;
203 *supportsResume = mStream->resume != NULL;
204 return OK;
205}
206
207status_t StreamOutHalLocal::pause() {
208 if (mStream->pause == NULL) return INVALID_OPERATION;
209 return mStream->pause(mStream);
210}
211
212status_t StreamOutHalLocal::resume() {
213 if (mStream->resume == NULL) return INVALID_OPERATION;
214 return mStream->resume(mStream);
215}
216
217status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) {
218 *supportsDrain = mStream->drain != NULL;
219 return OK;
220}
221
Mikhail Naganovcbc8f612016-10-11 18:05:13 -0700222status_t StreamOutHalLocal::drain(bool earlyNotify) {
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700223 if (mStream->drain == NULL) return INVALID_OPERATION;
Mikhail Naganovcbc8f612016-10-11 18:05:13 -0700224 return mStream->drain(mStream, earlyNotify ? AUDIO_DRAIN_EARLY_NOTIFY : AUDIO_DRAIN_ALL);
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700225}
226
227status_t StreamOutHalLocal::flush() {
228 if (mStream->flush == NULL) return INVALID_OPERATION;
229 return mStream->flush(mStream);
230}
231
232status_t StreamOutHalLocal::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
233 if (mStream->get_presentation_position == NULL) return INVALID_OPERATION;
234 return mStream->get_presentation_position(mStream, frames, timestamp);
235}
236
Eric Laurentaf35aad2016-12-15 14:25:36 -0800237status_t StreamOutHalLocal::start() {
238 if (mStream->start == NULL) return INVALID_OPERATION;
239 return mStream->start(mStream);
240}
241
242status_t StreamOutHalLocal::stop() {
243 if (mStream->stop == NULL) return INVALID_OPERATION;
244 return mStream->stop(mStream);
245}
246
247status_t StreamOutHalLocal::createMmapBuffer(int32_t minSizeFrames,
248 struct audio_mmap_buffer_info *info) {
249 if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
250 return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
251}
252
253status_t StreamOutHalLocal::getMmapPosition(struct audio_mmap_position *position) {
254 if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
255 return mStream->get_mmap_position(mStream, position);
256}
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700257
258StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
259 : StreamHalLocal(&stream->common, device), mStream(stream) {
260}
261
262StreamInHalLocal::~StreamInHalLocal() {
263 mDevice->closeInputStream(mStream);
264 mStream = 0;
265}
266
267status_t StreamInHalLocal::getFrameSize(size_t *size) {
268 *size = audio_stream_in_frame_size(mStream);
269 return OK;
270}
271
272status_t StreamInHalLocal::setGain(float gain) {
273 return mStream->set_gain(mStream, gain);
274}
275
276status_t StreamInHalLocal::read(void *buffer, size_t bytes, size_t *read) {
277 ssize_t readResult = mStream->read(mStream, buffer, bytes);
278 if (readResult > 0) {
279 *read = readResult;
Andy Hung953608f2017-06-13 15:21:49 -0700280 mStreamPowerLog.log( buffer, *read);
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700281 return OK;
282 } else {
283 *read = 0;
284 return readResult;
285 }
286}
287
288status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) {
289 *framesLost = mStream->get_input_frames_lost(mStream);
290 return OK;
291}
292
293status_t StreamInHalLocal::getCapturePosition(int64_t *frames, int64_t *time) {
294 if (mStream->get_capture_position == NULL) return INVALID_OPERATION;
295 return mStream->get_capture_position(mStream, frames, time);
296}
297
Eric Laurentaf35aad2016-12-15 14:25:36 -0800298status_t StreamInHalLocal::start() {
299 if (mStream->start == NULL) return INVALID_OPERATION;
300 return mStream->start(mStream);
301}
302
303status_t StreamInHalLocal::stop() {
304 if (mStream->stop == NULL) return INVALID_OPERATION;
305 return mStream->stop(mStream);
306}
307
308status_t StreamInHalLocal::createMmapBuffer(int32_t minSizeFrames,
309 struct audio_mmap_buffer_info *info) {
310 if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
311 return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
312}
313
314status_t StreamInHalLocal::getMmapPosition(struct audio_mmap_position *position) {
315 if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
316 return mStream->get_mmap_position(mStream, position);
317}
318
Mikhail Naganov1dc98672016-08-18 17:50:29 -0700319} // namespace android