blob: 34bd5df4d27f5704b4ed42affd8d58939655c891 [file] [log] [blame]
Kevin Rocard4bcd67f2018-02-28 14:33:38 -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 "StreamHalLocal"
18//#define LOG_NDEBUG 0
19
Andy Hung82d276a2021-05-03 14:19:16 -070020#include <audio_utils/Metadata.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080021#include <hardware/audio.h>
Mikhail Naganovac917ac2018-11-28 14:03:52 -080022#include <media/AudioParameter.h>
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080023#include <utils/Log.h>
24
25#include "DeviceHalLocal.h"
Mikhail Naganovcc73ef02020-11-06 10:09:52 -080026#include "ParameterUtils.h"
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080027#include "StreamHalLocal.h"
28
29namespace android {
Kevin Rocard070e7512018-05-22 09:29:13 -070030namespace CPP_VERSION {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080031
32StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
33 : mDevice(device),
34 mStream(stream) {
35 // Instrument audio signal power logging.
36 // Note: This assumes channel mask, format, and sample rate do not change after creation.
Andy Hung8c2e5822019-04-01 18:09:07 -070037 if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080038 mStreamPowerLog.init(mStream->get_sample_rate(mStream),
39 mStream->get_channels(mStream),
40 mStream->get_format(mStream));
41 }
42}
43
44StreamHalLocal::~StreamHalLocal() {
45 mStream = 0;
46 mDevice.clear();
47}
48
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080049status_t StreamHalLocal::getBufferSize(size_t *size) {
50 *size = mStream->get_buffer_size(mStream);
51 return OK;
52}
53
Mikhail Naganov560637e2021-03-31 22:40:13 +000054status_t StreamHalLocal::getAudioProperties(audio_config_base_t *configBase) {
55 configBase->sample_rate = mStream->get_sample_rate(mStream);
56 configBase->channel_mask = mStream->get_channels(mStream);
57 configBase->format = mStream->get_format(mStream);
Kevin Rocard4bcd67f2018-02-28 14:33:38 -080058 return OK;
59}
60
61status_t StreamHalLocal::setParameters(const String8& kvPairs) {
62 return mStream->set_parameters(mStream, kvPairs.string());
63}
64
65status_t StreamHalLocal::getParameters(const String8& keys, String8 *values) {
66 char *halValues = mStream->get_parameters(mStream, keys.string());
67 if (halValues != NULL) {
68 values->setTo(halValues);
69 free(halValues);
70 } else {
71 values->clear();
72 }
73 return OK;
74}
75
76status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
77 LOG_ALWAYS_FATAL("Local streams can not have effects");
78 return INVALID_OPERATION;
79}
80
81status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
82 LOG_ALWAYS_FATAL("Local streams can not have effects");
83 return INVALID_OPERATION;
84}
85
86status_t StreamHalLocal::standby() {
87 return mStream->standby(mStream);
88}
89
90status_t StreamHalLocal::dump(int fd) {
91 status_t status = mStream->dump(mStream, fd);
92 mStreamPowerLog.dump(fd);
93 return status;
94}
95
96status_t StreamHalLocal::setHalThreadPriority(int) {
97 // Don't need to do anything as local hal is executed by audioflinger directly
98 // on the same thread.
99 return OK;
100}
101
102StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device)
103 : StreamHalLocal(&stream->common, device), mStream(stream) {
104}
105
106StreamOutHalLocal::~StreamOutHalLocal() {
107 mCallback.clear();
108 mDevice->closeOutputStream(mStream);
109 mStream = 0;
110}
111
112status_t StreamOutHalLocal::getFrameSize(size_t *size) {
113 *size = audio_stream_out_frame_size(mStream);
114 return OK;
115}
116
117status_t StreamOutHalLocal::getLatency(uint32_t *latency) {
118 *latency = mStream->get_latency(mStream);
119 return OK;
120}
121
122status_t StreamOutHalLocal::setVolume(float left, float right) {
123 if (mStream->set_volume == NULL) return INVALID_OPERATION;
124 return mStream->set_volume(mStream, left, right);
125}
126
Mikhail Naganovac917ac2018-11-28 14:03:52 -0800127status_t StreamOutHalLocal::selectPresentation(int presentationId, int programId) {
128 AudioParameter param;
129 param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
130 param.addInt(String8(AudioParameter::keyProgramId), programId);
131 return setParameters(param.toString());
132}
133
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800134status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
135 ssize_t writeResult = mStream->write(mStream, buffer, bytes);
136 if (writeResult > 0) {
137 *written = writeResult;
138 mStreamPowerLog.log(buffer, *written);
139 return OK;
140 } else {
141 *written = 0;
142 return writeResult;
143 }
144}
145
146status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) {
147 return mStream->get_render_position(mStream, dspFrames);
148}
149
150status_t StreamOutHalLocal::getNextWriteTimestamp(int64_t *timestamp) {
151 if (mStream->get_next_write_timestamp == NULL) return INVALID_OPERATION;
152 return mStream->get_next_write_timestamp(mStream, timestamp);
153}
154
155status_t StreamOutHalLocal::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
156 if (mStream->set_callback == NULL) return INVALID_OPERATION;
157 status_t result = mStream->set_callback(mStream, StreamOutHalLocal::asyncCallback, this);
158 if (result == OK) {
159 mCallback = callback;
160 }
161 return result;
162}
163
164// static
165int StreamOutHalLocal::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
166 // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
167 // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
168 // already running, because the destructor is invoked after the refcount has been atomically
169 // decremented.
170 wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
171 sp<StreamOutHalLocal> self = weakSelf.promote();
172 if (self == 0) return 0;
173 sp<StreamOutHalInterfaceCallback> callback = self->mCallback.promote();
174 if (callback == 0) return 0;
175 ALOGV("asyncCallback() event %d", event);
176 switch (event) {
177 case STREAM_CBK_EVENT_WRITE_READY:
178 callback->onWriteReady();
179 break;
180 case STREAM_CBK_EVENT_DRAIN_READY:
181 callback->onDrainReady();
182 break;
183 case STREAM_CBK_EVENT_ERROR:
184 callback->onError();
185 break;
186 default:
187 ALOGW("asyncCallback() unknown event %d", event);
188 break;
189 }
190 return 0;
191}
192
193status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
194 *supportsPause = mStream->pause != NULL;
195 *supportsResume = mStream->resume != NULL;
196 return OK;
197}
198
199status_t StreamOutHalLocal::pause() {
200 if (mStream->pause == NULL) return INVALID_OPERATION;
201 return mStream->pause(mStream);
202}
203
204status_t StreamOutHalLocal::resume() {
205 if (mStream->resume == NULL) return INVALID_OPERATION;
206 return mStream->resume(mStream);
207}
208
209status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) {
210 *supportsDrain = mStream->drain != NULL;
211 return OK;
212}
213
214status_t StreamOutHalLocal::drain(bool earlyNotify) {
215 if (mStream->drain == NULL) return INVALID_OPERATION;
216 return mStream->drain(mStream, earlyNotify ? AUDIO_DRAIN_EARLY_NOTIFY : AUDIO_DRAIN_ALL);
217}
218
219status_t StreamOutHalLocal::flush() {
220 if (mStream->flush == NULL) return INVALID_OPERATION;
221 return mStream->flush(mStream);
222}
223
224status_t StreamOutHalLocal::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
225 if (mStream->get_presentation_position == NULL) return INVALID_OPERATION;
226 return mStream->get_presentation_position(mStream, frames, timestamp);
227}
228
Eric Laurent6109cdb2020-11-20 18:41:04 +0100229void StreamOutHalLocal::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) {
230 std::vector<playback_track_metadata> halTracks;
231 halTracks.reserve(sourceMetadata.tracks.size());
232 for (auto& metadata : sourceMetadata.tracks) {
233 playback_track_metadata halTrackMetadata;
234 playback_track_metadata_from_v7(&halTrackMetadata, &metadata);
235 halTracks.push_back(halTrackMetadata);
Kevin Rocarda8975a72018-03-27 10:16:52 -0700236 }
Eric Laurent6109cdb2020-11-20 18:41:04 +0100237 const source_metadata_t halMetadata = {
238 .track_count = halTracks.size(),
239 .tracks = halTracks.data(),
240 };
241 mStream->update_source_metadata(mStream, &halMetadata);
242}
243
244#if MAJOR_VERSION >= 7
245void StreamOutHalLocal::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800246 const source_metadata_v7_t metadata {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700247 .track_count = sourceMetadata.tracks.size(),
248 // const cast is fine as it is in a const structure
Eric Laurent6109cdb2020-11-20 18:41:04 +0100249 .tracks = const_cast<playback_track_metadata_v7*>(sourceMetadata.tracks.data()),
Kevin Rocarda8975a72018-03-27 10:16:52 -0700250 };
Eric Laurent6109cdb2020-11-20 18:41:04 +0100251 mStream->update_source_metadata_v7(mStream, &metadata);
252}
253#endif
254
255status_t StreamOutHalLocal::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
256#if MAJOR_VERSION < 7
257 if (mStream->update_source_metadata == nullptr) {
258 return INVALID_OPERATION;
259 }
260 doUpdateSourceMetadata(sourceMetadata);
261#else
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800262 if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
Eric Laurent6109cdb2020-11-20 18:41:04 +0100263 if (mStream->update_source_metadata == nullptr) {
264 return INVALID_OPERATION;
265 }
266 doUpdateSourceMetadata(sourceMetadata);
267 } else {
268 if (mStream->update_source_metadata_v7 == nullptr) {
269 return INVALID_OPERATION;
270 }
271 doUpdateSourceMetadataV7(sourceMetadata);
272 }
273#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700274 return OK;
275}
276
Eric Laurent6109cdb2020-11-20 18:41:04 +0100277
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800278status_t StreamOutHalLocal::start() {
279 if (mStream->start == NULL) return INVALID_OPERATION;
280 return mStream->start(mStream);
281}
282
283status_t StreamOutHalLocal::stop() {
284 if (mStream->stop == NULL) return INVALID_OPERATION;
285 return mStream->stop(mStream);
286}
287
288status_t StreamOutHalLocal::createMmapBuffer(int32_t minSizeFrames,
289 struct audio_mmap_buffer_info *info) {
290 if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
291 return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
292}
293
294status_t StreamOutHalLocal::getMmapPosition(struct audio_mmap_position *position) {
295 if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
296 return mStream->get_mmap_position(mStream, position);
297}
298
Kuowei Li3bea3a42020-08-13 14:44:25 +0800299status_t StreamOutHalLocal::getDualMonoMode(audio_dual_mono_mode_t* mode) {
300 if (mStream->get_dual_mono_mode == nullptr) return INVALID_OPERATION;
301 return mStream->get_dual_mono_mode(mStream, mode);
302}
303
304status_t StreamOutHalLocal::setDualMonoMode(audio_dual_mono_mode_t mode) {
305 if (mStream->set_dual_mono_mode == nullptr) return INVALID_OPERATION;
306 return mStream->set_dual_mono_mode(mStream, mode);
307}
308
309status_t StreamOutHalLocal::getAudioDescriptionMixLevel(float* leveldB) {
310 if (mStream->get_audio_description_mix_level == nullptr) return INVALID_OPERATION;
311 return mStream->get_audio_description_mix_level(mStream, leveldB);
312}
313
314status_t StreamOutHalLocal::setAudioDescriptionMixLevel(float leveldB) {
315 if (mStream->set_audio_description_mix_level == nullptr) return INVALID_OPERATION;
316 return mStream->set_audio_description_mix_level(mStream, leveldB);
317}
318
319status_t StreamOutHalLocal::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) {
320 if (mStream->get_playback_rate_parameters == nullptr) return INVALID_OPERATION;
321 return mStream->get_playback_rate_parameters(mStream, playbackRate);
322}
323
324status_t StreamOutHalLocal::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) {
325 if (mStream->set_playback_rate_parameters == nullptr) return INVALID_OPERATION;
326 return mStream->set_playback_rate_parameters(mStream, &playbackRate);
327}
328
jiabinf6eb4c32020-02-25 14:06:25 -0800329status_t StreamOutHalLocal::setEventCallback(
330 const sp<StreamOutHalInterfaceEventCallback>& callback) {
331 if (mStream->set_event_callback == nullptr) {
332 return INVALID_OPERATION;
333 }
334 stream_event_callback_t asyncCallback =
335 callback == nullptr ? nullptr : StreamOutHalLocal::asyncEventCallback;
336 status_t result = mStream->set_event_callback(mStream, asyncCallback, this);
337 if (result == OK) {
338 mEventCallback = callback;
339 }
340 return result;
341}
342
343// static
344int StreamOutHalLocal::asyncEventCallback(
345 stream_event_callback_type_t event, void *param, void *cookie) {
346 // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
347 // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
348 // already running, because the destructor is invoked after the refcount has been atomically
349 // decremented.
350 wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
351 sp<StreamOutHalLocal> self = weakSelf.promote();
352 if (self == nullptr) return 0;
353 sp<StreamOutHalInterfaceEventCallback> callback = self->mEventCallback.promote();
354 if (callback.get() == nullptr) return 0;
355 switch (event) {
356 case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED:
Andy Hung82d276a2021-05-03 14:19:16 -0700357 // void* param is the byte string buffer from byte_string_from_audio_metadata().
358 // As the byte string buffer may have embedded zeroes, we cannot use strlen()
359 callback->onCodecFormatChanged(std::basic_string<uint8_t>(
360 (const uint8_t*)param,
361 audio_utils::metadata::dataByteStringLen((const uint8_t*)param)));
jiabinf6eb4c32020-02-25 14:06:25 -0800362 break;
363 default:
364 ALOGW("%s unknown event %d", __func__, event);
365 break;
366 }
367 return 0;
368}
369
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800370StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
371 : StreamHalLocal(&stream->common, device), mStream(stream) {
372}
373
374StreamInHalLocal::~StreamInHalLocal() {
375 mDevice->closeInputStream(mStream);
376 mStream = 0;
377}
378
379status_t StreamInHalLocal::getFrameSize(size_t *size) {
380 *size = audio_stream_in_frame_size(mStream);
381 return OK;
382}
383
384status_t StreamInHalLocal::setGain(float gain) {
385 return mStream->set_gain(mStream, gain);
386}
387
388status_t StreamInHalLocal::read(void *buffer, size_t bytes, size_t *read) {
389 ssize_t readResult = mStream->read(mStream, buffer, bytes);
390 if (readResult > 0) {
391 *read = readResult;
392 mStreamPowerLog.log( buffer, *read);
393 return OK;
394 } else {
395 *read = 0;
396 return readResult;
397 }
398}
399
400status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) {
401 *framesLost = mStream->get_input_frames_lost(mStream);
402 return OK;
403}
404
405status_t StreamInHalLocal::getCapturePosition(int64_t *frames, int64_t *time) {
406 if (mStream->get_capture_position == NULL) return INVALID_OPERATION;
407 return mStream->get_capture_position(mStream, frames, time);
408}
409
Eric Laurent6109cdb2020-11-20 18:41:04 +0100410void StreamInHalLocal::doUpdateSinkMetadata(const SinkMetadata& sinkMetadata) {
411 std::vector<record_track_metadata> halTracks;
412 halTracks.reserve(sinkMetadata.tracks.size());
413 for (auto& metadata : sinkMetadata.tracks) {
414 record_track_metadata halTrackMetadata;
415 record_track_metadata_from_v7(&halTrackMetadata, &metadata);
416 halTracks.push_back(halTrackMetadata);
Kevin Rocarda8975a72018-03-27 10:16:52 -0700417 }
Eric Laurent6109cdb2020-11-20 18:41:04 +0100418 const sink_metadata_t halMetadata = {
419 .track_count = halTracks.size(),
420 .tracks = halTracks.data(),
421 };
422 mStream->update_sink_metadata(mStream, &halMetadata);
423}
424
425#if MAJOR_VERSION >= 7
426void StreamInHalLocal::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
427 const sink_metadata_v7_t halMetadata {
Kevin Rocarda8975a72018-03-27 10:16:52 -0700428 .track_count = sinkMetadata.tracks.size(),
429 // const cast is fine as it is in a const structure
Eric Laurent6109cdb2020-11-20 18:41:04 +0100430 .tracks = const_cast<record_track_metadata_v7*>(sinkMetadata.tracks.data()),
Kevin Rocarda8975a72018-03-27 10:16:52 -0700431 };
Eric Laurent6109cdb2020-11-20 18:41:04 +0100432 mStream->update_sink_metadata_v7(mStream, &halMetadata);
433}
434#endif
435
436status_t StreamInHalLocal::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
437#if MAJOR_VERSION < 7
Eric Laurent6109cdb2020-11-20 18:41:04 +0100438 if (mStream->update_sink_metadata == nullptr) {
439 return INVALID_OPERATION; // not supported by the HAL
440 }
441 doUpdateSinkMetadata(sinkMetadata);
442#else
Mikhail Naganovcc73ef02020-11-06 10:09:52 -0800443 if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
Eric Laurent6109cdb2020-11-20 18:41:04 +0100444 if (mStream->update_sink_metadata == nullptr) {
445 return INVALID_OPERATION; // not supported by the HAL
446 }
447 doUpdateSinkMetadata(sinkMetadata);
448 } else {
449 if (mStream->update_sink_metadata_v7 == nullptr) {
450 return INVALID_OPERATION; // not supported by the HAL
451 }
452 doUpdateSinkMetadataV7(sinkMetadata);
453 }
454#endif
Kevin Rocarda8975a72018-03-27 10:16:52 -0700455 return OK;
456}
457
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800458status_t StreamInHalLocal::start() {
459 if (mStream->start == NULL) return INVALID_OPERATION;
460 return mStream->start(mStream);
461}
462
463status_t StreamInHalLocal::stop() {
464 if (mStream->stop == NULL) return INVALID_OPERATION;
465 return mStream->stop(mStream);
466}
467
468status_t StreamInHalLocal::createMmapBuffer(int32_t minSizeFrames,
469 struct audio_mmap_buffer_info *info) {
470 if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION;
471 return mStream->create_mmap_buffer(mStream, minSizeFrames, info);
472}
473
474status_t StreamInHalLocal::getMmapPosition(struct audio_mmap_position *position) {
475 if (mStream->get_mmap_position == NULL) return INVALID_OPERATION;
476 return mStream->get_mmap_position(mStream, position);
477}
478
Kevin Rocard070e7512018-05-22 09:29:13 -0700479#if MAJOR_VERSION == 2
480status_t StreamInHalLocal::getActiveMicrophones(
481 std::vector<media::MicrophoneInfo> *microphones __unused) {
482 return INVALID_OPERATION;
483}
Kevin Rocard3d48dce2018-11-08 17:16:57 -0800484#elif MAJOR_VERSION >= 4
jiabin9ff780e2018-03-19 18:19:52 -0700485status_t StreamInHalLocal::getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) {
486 if (mStream->get_active_microphones == NULL) return INVALID_OPERATION;
487 size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT;
488 audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT];
489 status_t status = mStream->get_active_microphones(mStream, &mic_array[0], &actual_mics);
490 for (size_t i = 0; i < actual_mics; i++) {
491 media::MicrophoneInfo microphoneInfo = media::MicrophoneInfo(mic_array[i]);
492 microphones->push_back(microphoneInfo);
493 }
494 return status;
495}
Kevin Rocard070e7512018-05-22 09:29:13 -0700496#endif
jiabin9ff780e2018-03-19 18:19:52 -0700497
Paul McLean03a6e6a2018-12-04 10:54:13 -0700498#if MAJOR_VERSION < 5
Paul McLean12340082019-03-19 09:35:05 -0600499status_t StreamInHalLocal::setPreferredMicrophoneDirection(
500 audio_microphone_direction_t direction __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700501 return INVALID_OPERATION;
502}
503
Paul McLean12340082019-03-19 09:35:05 -0600504status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom __unused) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700505 return INVALID_OPERATION;
506}
507#else
Paul McLean12340082019-03-19 09:35:05 -0600508status_t StreamInHalLocal::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700509 if (mStream->set_microphone_direction == NULL) return INVALID_OPERATION;
510 return mStream->set_microphone_direction(mStream, direction);
511}
512
Paul McLean12340082019-03-19 09:35:05 -0600513status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom) {
Paul McLean03a6e6a2018-12-04 10:54:13 -0700514 if (mStream->set_microphone_field_dimension == NULL) return INVALID_OPERATION;
515 return mStream->set_microphone_field_dimension(mStream, zoom);
516
517}
518#endif
519
Kevin Rocard070e7512018-05-22 09:29:13 -0700520} // namespace CPP_VERSION
Kevin Rocard4bcd67f2018-02-28 14:33:38 -0800521} // namespace android
Paul McLean12340082019-03-19 09:35:05 -0600522
523