• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
20 #include <audio_utils/Metadata.h>
21 #include <hardware/audio.h>
22 #include <media/AudioParameter.h>
23 #include <utils/Log.h>
24 
25 #include "DeviceHalLocal.h"
26 #include "ParameterUtils.h"
27 #include "StreamHalLocal.h"
28 
29 namespace android {
30 namespace CPP_VERSION {
31 
StreamHalLocal(audio_stream_t * stream,sp<DeviceHalLocal> device)32 StreamHalLocal::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.
37     if (mStream != nullptr /* && mStreamPowerLog.isUserDebugOrEngBuild() */) {
38         mStreamPowerLog.init(mStream->get_sample_rate(mStream),
39                 mStream->get_channels(mStream),
40                 mStream->get_format(mStream));
41     }
42 }
43 
~StreamHalLocal()44 StreamHalLocal::~StreamHalLocal() {
45     mStream = 0;
46     mDevice.clear();
47 }
48 
getBufferSize(size_t * size)49 status_t StreamHalLocal::getBufferSize(size_t *size) {
50     *size = mStream->get_buffer_size(mStream);
51     return OK;
52 }
53 
getAudioProperties(audio_config_base_t * configBase)54 status_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);
58     return OK;
59 }
60 
setParameters(const String8 & kvPairs)61 status_t StreamHalLocal::setParameters(const String8& kvPairs) {
62     return mStream->set_parameters(mStream, kvPairs.string());
63 }
64 
getParameters(const String8 & keys,String8 * values)65 status_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 
addEffect(sp<EffectHalInterface>)76 status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) {
77     LOG_ALWAYS_FATAL("Local streams can not have effects");
78     return INVALID_OPERATION;
79 }
80 
removeEffect(sp<EffectHalInterface>)81 status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) {
82     LOG_ALWAYS_FATAL("Local streams can not have effects");
83     return INVALID_OPERATION;
84 }
85 
standby()86 status_t StreamHalLocal::standby() {
87     return mStream->standby(mStream);
88 }
89 
dump(int fd)90 status_t StreamHalLocal::dump(int fd) {
91     status_t status = mStream->dump(mStream, fd);
92     mStreamPowerLog.dump(fd);
93     return status;
94 }
95 
setHalThreadPriority(int)96 status_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 
StreamOutHalLocal(audio_stream_out_t * stream,sp<DeviceHalLocal> device)102 StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device)
103         : StreamHalLocal(&stream->common, device), mStream(stream) {
104 }
105 
~StreamOutHalLocal()106 StreamOutHalLocal::~StreamOutHalLocal() {
107     mCallback.clear();
108     mDevice->closeOutputStream(mStream);
109     mStream = 0;
110 }
111 
getFrameSize(size_t * size)112 status_t StreamOutHalLocal::getFrameSize(size_t *size) {
113     *size = audio_stream_out_frame_size(mStream);
114     return OK;
115 }
116 
getLatency(uint32_t * latency)117 status_t StreamOutHalLocal::getLatency(uint32_t *latency) {
118     *latency = mStream->get_latency(mStream);
119     return OK;
120 }
121 
setVolume(float left,float right)122 status_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 
selectPresentation(int presentationId,int programId)127 status_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 
write(const void * buffer,size_t bytes,size_t * written)134 status_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 
getRenderPosition(uint32_t * dspFrames)146 status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) {
147     return mStream->get_render_position(mStream, dspFrames);
148 }
149 
getNextWriteTimestamp(int64_t * timestamp)150 status_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 
setCallback(wp<StreamOutHalInterfaceCallback> callback)155 status_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
asyncCallback(stream_callback_event_t event,void *,void * cookie)165 int 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 
supportsPauseAndResume(bool * supportsPause,bool * supportsResume)193 status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
194     *supportsPause = mStream->pause != NULL;
195     *supportsResume = mStream->resume != NULL;
196     return OK;
197 }
198 
pause()199 status_t StreamOutHalLocal::pause() {
200     if (mStream->pause == NULL) return INVALID_OPERATION;
201     return mStream->pause(mStream);
202 }
203 
resume()204 status_t StreamOutHalLocal::resume() {
205     if (mStream->resume == NULL) return INVALID_OPERATION;
206     return mStream->resume(mStream);
207 }
208 
supportsDrain(bool * supportsDrain)209 status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) {
210     *supportsDrain = mStream->drain != NULL;
211     return OK;
212 }
213 
drain(bool earlyNotify)214 status_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 
flush()219 status_t StreamOutHalLocal::flush() {
220     if (mStream->flush == NULL) return INVALID_OPERATION;
221     return mStream->flush(mStream);
222 }
223 
getPresentationPosition(uint64_t * frames,struct timespec * timestamp)224 status_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 
doUpdateSourceMetadata(const SourceMetadata & sourceMetadata)229 void 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);
236     }
237     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
doUpdateSourceMetadataV7(const SourceMetadata & sourceMetadata)245 void StreamOutHalLocal::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
246     const source_metadata_v7_t metadata {
247         .track_count = sourceMetadata.tracks.size(),
248         // const cast is fine as it is in a const structure
249         .tracks = const_cast<playback_track_metadata_v7*>(sourceMetadata.tracks.data()),
250     };
251     mStream->update_source_metadata_v7(mStream, &metadata);
252 }
253 #endif
254 
updateSourceMetadata(const SourceMetadata & sourceMetadata)255 status_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
262     if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
263         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
274     return OK;
275 }
276 
277 
start()278 status_t StreamOutHalLocal::start() {
279     if (mStream->start == NULL) return INVALID_OPERATION;
280     return mStream->start(mStream);
281 }
282 
stop()283 status_t StreamOutHalLocal::stop() {
284     if (mStream->stop == NULL) return INVALID_OPERATION;
285     return mStream->stop(mStream);
286 }
287 
createMmapBuffer(int32_t minSizeFrames,struct audio_mmap_buffer_info * info)288 status_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 
getMmapPosition(struct audio_mmap_position * position)294 status_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 
getDualMonoMode(audio_dual_mono_mode_t * mode)299 status_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 
setDualMonoMode(audio_dual_mono_mode_t mode)304 status_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 
getAudioDescriptionMixLevel(float * leveldB)309 status_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 
setAudioDescriptionMixLevel(float leveldB)314 status_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 
getPlaybackRateParameters(audio_playback_rate_t * playbackRate)319 status_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 
setPlaybackRateParameters(const audio_playback_rate_t & playbackRate)324 status_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 
setEventCallback(const sp<StreamOutHalInterfaceEventCallback> & callback)329 status_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
asyncEventCallback(stream_event_callback_type_t event,void * param,void * cookie)344 int 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:
357             // 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)));
362             break;
363         default:
364             ALOGW("%s unknown event %d", __func__, event);
365             break;
366     }
367     return 0;
368 }
369 
StreamInHalLocal(audio_stream_in_t * stream,sp<DeviceHalLocal> device)370 StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
371         : StreamHalLocal(&stream->common, device), mStream(stream) {
372 }
373 
~StreamInHalLocal()374 StreamInHalLocal::~StreamInHalLocal() {
375     mDevice->closeInputStream(mStream);
376     mStream = 0;
377 }
378 
getFrameSize(size_t * size)379 status_t StreamInHalLocal::getFrameSize(size_t *size) {
380     *size = audio_stream_in_frame_size(mStream);
381     return OK;
382 }
383 
setGain(float gain)384 status_t StreamInHalLocal::setGain(float gain) {
385     return mStream->set_gain(mStream, gain);
386 }
387 
read(void * buffer,size_t bytes,size_t * read)388 status_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 
getInputFramesLost(uint32_t * framesLost)400 status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) {
401     *framesLost = mStream->get_input_frames_lost(mStream);
402     return OK;
403 }
404 
getCapturePosition(int64_t * frames,int64_t * time)405 status_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 
doUpdateSinkMetadata(const SinkMetadata & sinkMetadata)410 void 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);
417     }
418     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
doUpdateSinkMetadataV7(const SinkMetadata & sinkMetadata)426 void StreamInHalLocal::doUpdateSinkMetadataV7(const SinkMetadata& sinkMetadata) {
427     const sink_metadata_v7_t halMetadata {
428         .track_count = sinkMetadata.tracks.size(),
429         // const cast is fine as it is in a const structure
430         .tracks = const_cast<record_track_metadata_v7*>(sinkMetadata.tracks.data()),
431     };
432     mStream->update_sink_metadata_v7(mStream, &halMetadata);
433 }
434 #endif
435 
updateSinkMetadata(const SinkMetadata & sinkMetadata)436 status_t StreamInHalLocal::updateSinkMetadata(const SinkMetadata& sinkMetadata) {
437 #if MAJOR_VERSION < 7
438     if (mStream->update_sink_metadata == nullptr) {
439         return INVALID_OPERATION;  // not supported by the HAL
440     }
441     doUpdateSinkMetadata(sinkMetadata);
442 #else
443     if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
444         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
455     return OK;
456 }
457 
start()458 status_t StreamInHalLocal::start() {
459     if (mStream->start == NULL) return INVALID_OPERATION;
460     return mStream->start(mStream);
461 }
462 
stop()463 status_t StreamInHalLocal::stop() {
464     if (mStream->stop == NULL) return INVALID_OPERATION;
465     return mStream->stop(mStream);
466 }
467 
createMmapBuffer(int32_t minSizeFrames,struct audio_mmap_buffer_info * info)468 status_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 
getMmapPosition(struct audio_mmap_position * position)474 status_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 
479 #if MAJOR_VERSION == 2
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphones __unused)480 status_t StreamInHalLocal::getActiveMicrophones(
481         std::vector<media::MicrophoneInfo> *microphones __unused) {
482     return INVALID_OPERATION;
483 }
484 #elif MAJOR_VERSION >= 4
getActiveMicrophones(std::vector<media::MicrophoneInfo> * microphones)485 status_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 }
496 #endif
497 
498 #if MAJOR_VERSION < 5
setPreferredMicrophoneDirection(audio_microphone_direction_t direction __unused)499 status_t StreamInHalLocal::setPreferredMicrophoneDirection(
500             audio_microphone_direction_t direction __unused) {
501     return INVALID_OPERATION;
502 }
503 
setPreferredMicrophoneFieldDimension(float zoom __unused)504 status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom __unused) {
505     return INVALID_OPERATION;
506 }
507 #else
setPreferredMicrophoneDirection(audio_microphone_direction_t direction)508 status_t StreamInHalLocal::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) {
509     if (mStream->set_microphone_direction == NULL) return INVALID_OPERATION;
510     return mStream->set_microphone_direction(mStream, direction);
511 }
512 
setPreferredMicrophoneFieldDimension(float zoom)513 status_t StreamInHalLocal::setPreferredMicrophoneFieldDimension(float zoom) {
514     if (mStream->set_microphone_field_dimension == NULL) return INVALID_OPERATION;
515     return mStream->set_microphone_field_dimension(mStream, zoom);
516 
517 }
518 #endif
519 
520 } // namespace CPP_VERSION
521 } // namespace android
522 
523 
524