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 <hardware/audio.h> 21#include <utils/Log.h> 22 23#include "DeviceHalLocal.h" 24#include "StreamHalLocal.h" 25#include "VersionUtils.h" 26 27namespace android { 28namespace V4_0 { 29 30StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device) 31 : mDevice(device), 32 mStream(stream) { 33 // Instrument audio signal power logging. 34 // Note: This assumes channel mask, format, and sample rate do not change after creation. 35 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) { 36 mStreamPowerLog.init(mStream->get_sample_rate(mStream), 37 mStream->get_channels(mStream), 38 mStream->get_format(mStream)); 39 } 40} 41 42StreamHalLocal::~StreamHalLocal() { 43 mStream = 0; 44 mDevice.clear(); 45} 46 47status_t StreamHalLocal::getSampleRate(uint32_t *rate) { 48 *rate = mStream->get_sample_rate(mStream); 49 return OK; 50} 51 52status_t StreamHalLocal::getBufferSize(size_t *size) { 53 *size = mStream->get_buffer_size(mStream); 54 return OK; 55} 56 57status_t StreamHalLocal::getChannelMask(audio_channel_mask_t *mask) { 58 *mask = mStream->get_channels(mStream); 59 return OK; 60} 61 62status_t StreamHalLocal::getFormat(audio_format_t *format) { 63 *format = mStream->get_format(mStream); 64 return OK; 65} 66 67status_t StreamHalLocal::getAudioProperties( 68 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) { 69 *sampleRate = mStream->get_sample_rate(mStream); 70 *mask = mStream->get_channels(mStream); 71 *format = mStream->get_format(mStream); 72 return OK; 73} 74 75status_t StreamHalLocal::setParameters(const String8& kvPairs) { 76 return mStream->set_parameters(mStream, kvPairs.string()); 77} 78 79status_t StreamHalLocal::getParameters(const String8& keys, String8 *values) { 80 char *halValues = mStream->get_parameters(mStream, keys.string()); 81 if (halValues != NULL) { 82 values->setTo(halValues); 83 free(halValues); 84 } else { 85 values->clear(); 86 } 87 return OK; 88} 89 90status_t StreamHalLocal::addEffect(sp<EffectHalInterface>) { 91 LOG_ALWAYS_FATAL("Local streams can not have effects"); 92 return INVALID_OPERATION; 93} 94 95status_t StreamHalLocal::removeEffect(sp<EffectHalInterface>) { 96 LOG_ALWAYS_FATAL("Local streams can not have effects"); 97 return INVALID_OPERATION; 98} 99 100status_t StreamHalLocal::standby() { 101 return mStream->standby(mStream); 102} 103 104status_t StreamHalLocal::dump(int fd) { 105 status_t status = mStream->dump(mStream, fd); 106 mStreamPowerLog.dump(fd); 107 return status; 108} 109 110status_t StreamHalLocal::setHalThreadPriority(int) { 111 // Don't need to do anything as local hal is executed by audioflinger directly 112 // on the same thread. 113 return OK; 114} 115 116StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device) 117 : StreamHalLocal(&stream->common, device), mStream(stream) { 118} 119 120StreamOutHalLocal::~StreamOutHalLocal() { 121 mCallback.clear(); 122 mDevice->closeOutputStream(mStream); 123 mStream = 0; 124} 125 126status_t StreamOutHalLocal::getFrameSize(size_t *size) { 127 *size = audio_stream_out_frame_size(mStream); 128 return OK; 129} 130 131status_t StreamOutHalLocal::getLatency(uint32_t *latency) { 132 *latency = mStream->get_latency(mStream); 133 return OK; 134} 135 136status_t StreamOutHalLocal::setVolume(float left, float right) { 137 if (mStream->set_volume == NULL) return INVALID_OPERATION; 138 return mStream->set_volume(mStream, left, right); 139} 140 141status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) { 142 ssize_t writeResult = mStream->write(mStream, buffer, bytes); 143 if (writeResult > 0) { 144 *written = writeResult; 145 mStreamPowerLog.log(buffer, *written); 146 return OK; 147 } else { 148 *written = 0; 149 return writeResult; 150 } 151} 152 153status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) { 154 return mStream->get_render_position(mStream, dspFrames); 155} 156 157status_t StreamOutHalLocal::getNextWriteTimestamp(int64_t *timestamp) { 158 if (mStream->get_next_write_timestamp == NULL) return INVALID_OPERATION; 159 return mStream->get_next_write_timestamp(mStream, timestamp); 160} 161 162status_t StreamOutHalLocal::setCallback(wp<StreamOutHalInterfaceCallback> callback) { 163 if (mStream->set_callback == NULL) return INVALID_OPERATION; 164 status_t result = mStream->set_callback(mStream, StreamOutHalLocal::asyncCallback, this); 165 if (result == OK) { 166 mCallback = callback; 167 } 168 return result; 169} 170 171// static 172int StreamOutHalLocal::asyncCallback(stream_callback_event_t event, void*, void *cookie) { 173 // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle 174 // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is 175 // already running, because the destructor is invoked after the refcount has been atomically 176 // decremented. 177 wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie)); 178 sp<StreamOutHalLocal> self = weakSelf.promote(); 179 if (self == 0) return 0; 180 sp<StreamOutHalInterfaceCallback> callback = self->mCallback.promote(); 181 if (callback == 0) return 0; 182 ALOGV("asyncCallback() event %d", event); 183 switch (event) { 184 case STREAM_CBK_EVENT_WRITE_READY: 185 callback->onWriteReady(); 186 break; 187 case STREAM_CBK_EVENT_DRAIN_READY: 188 callback->onDrainReady(); 189 break; 190 case STREAM_CBK_EVENT_ERROR: 191 callback->onError(); 192 break; 193 default: 194 ALOGW("asyncCallback() unknown event %d", event); 195 break; 196 } 197 return 0; 198} 199 200status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) { 201 *supportsPause = mStream->pause != NULL; 202 *supportsResume = mStream->resume != NULL; 203 return OK; 204} 205 206status_t StreamOutHalLocal::pause() { 207 if (mStream->pause == NULL) return INVALID_OPERATION; 208 return mStream->pause(mStream); 209} 210 211status_t StreamOutHalLocal::resume() { 212 if (mStream->resume == NULL) return INVALID_OPERATION; 213 return mStream->resume(mStream); 214} 215 216status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) { 217 *supportsDrain = mStream->drain != NULL; 218 return OK; 219} 220 221status_t StreamOutHalLocal::drain(bool earlyNotify) { 222 if (mStream->drain == NULL) return INVALID_OPERATION; 223 return mStream->drain(mStream, earlyNotify ? AUDIO_DRAIN_EARLY_NOTIFY : AUDIO_DRAIN_ALL); 224} 225 226status_t StreamOutHalLocal::flush() { 227 if (mStream->flush == NULL) return INVALID_OPERATION; 228 return mStream->flush(mStream); 229} 230 231status_t StreamOutHalLocal::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { 232 if (mStream->get_presentation_position == NULL) return INVALID_OPERATION; 233 return mStream->get_presentation_position(mStream, frames, timestamp); 234} 235 236status_t StreamOutHalLocal::updateSourceMetadata(const SourceMetadata& sourceMetadata) { 237 if (mStream->update_source_metadata == nullptr) { 238 return INVALID_OPERATION; 239 } 240 const source_metadata_t metadata { 241 .track_count = sourceMetadata.tracks.size(), 242 // const cast is fine as it is in a const structure 243 .tracks = const_cast<playback_track_metadata*>(sourceMetadata.tracks.data()), 244 }; 245 mStream->update_source_metadata(mStream, &metadata); 246 return OK; 247} 248 249status_t StreamOutHalLocal::start() { 250 if (mStream->start == NULL) return INVALID_OPERATION; 251 return mStream->start(mStream); 252} 253 254status_t StreamOutHalLocal::stop() { 255 if (mStream->stop == NULL) return INVALID_OPERATION; 256 return mStream->stop(mStream); 257} 258 259status_t StreamOutHalLocal::createMmapBuffer(int32_t minSizeFrames, 260 struct audio_mmap_buffer_info *info) { 261 if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION; 262 return mStream->create_mmap_buffer(mStream, minSizeFrames, info); 263} 264 265status_t StreamOutHalLocal::getMmapPosition(struct audio_mmap_position *position) { 266 if (mStream->get_mmap_position == NULL) return INVALID_OPERATION; 267 return mStream->get_mmap_position(mStream, position); 268} 269 270StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device) 271 : StreamHalLocal(&stream->common, device), mStream(stream) { 272} 273 274StreamInHalLocal::~StreamInHalLocal() { 275 mDevice->closeInputStream(mStream); 276 mStream = 0; 277} 278 279status_t StreamInHalLocal::getFrameSize(size_t *size) { 280 *size = audio_stream_in_frame_size(mStream); 281 return OK; 282} 283 284status_t StreamInHalLocal::setGain(float gain) { 285 return mStream->set_gain(mStream, gain); 286} 287 288status_t StreamInHalLocal::read(void *buffer, size_t bytes, size_t *read) { 289 ssize_t readResult = mStream->read(mStream, buffer, bytes); 290 if (readResult > 0) { 291 *read = readResult; 292 mStreamPowerLog.log( buffer, *read); 293 return OK; 294 } else { 295 *read = 0; 296 return readResult; 297 } 298} 299 300status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) { 301 *framesLost = mStream->get_input_frames_lost(mStream); 302 return OK; 303} 304 305status_t StreamInHalLocal::getCapturePosition(int64_t *frames, int64_t *time) { 306 if (mStream->get_capture_position == NULL) return INVALID_OPERATION; 307 return mStream->get_capture_position(mStream, frames, time); 308} 309 310status_t StreamInHalLocal::updateSinkMetadata(const SinkMetadata& sinkMetadata) { 311 if (mStream->update_sink_metadata == nullptr) { 312 return INVALID_OPERATION; 313 } 314 const sink_metadata_t metadata { 315 .track_count = sinkMetadata.tracks.size(), 316 // const cast is fine as it is in a const structure 317 .tracks = const_cast<record_track_metadata*>(sinkMetadata.tracks.data()), 318 }; 319 mStream->update_sink_metadata(mStream, &metadata); 320 return OK; 321} 322 323status_t StreamInHalLocal::start() { 324 if (mStream->start == NULL) return INVALID_OPERATION; 325 return mStream->start(mStream); 326} 327 328status_t StreamInHalLocal::stop() { 329 if (mStream->stop == NULL) return INVALID_OPERATION; 330 return mStream->stop(mStream); 331} 332 333status_t StreamInHalLocal::createMmapBuffer(int32_t minSizeFrames, 334 struct audio_mmap_buffer_info *info) { 335 if (mStream->create_mmap_buffer == NULL) return INVALID_OPERATION; 336 return mStream->create_mmap_buffer(mStream, minSizeFrames, info); 337} 338 339status_t StreamInHalLocal::getMmapPosition(struct audio_mmap_position *position) { 340 if (mStream->get_mmap_position == NULL) return INVALID_OPERATION; 341 return mStream->get_mmap_position(mStream, position); 342} 343 344status_t StreamInHalLocal::getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) { 345 if (mStream->get_active_microphones == NULL) return INVALID_OPERATION; 346 size_t actual_mics = AUDIO_MICROPHONE_MAX_COUNT; 347 audio_microphone_characteristic_t mic_array[AUDIO_MICROPHONE_MAX_COUNT]; 348 status_t status = mStream->get_active_microphones(mStream, &mic_array[0], &actual_mics); 349 for (size_t i = 0; i < actual_mics; i++) { 350 media::MicrophoneInfo microphoneInfo = media::MicrophoneInfo(mic_array[i]); 351 microphones->push_back(microphoneInfo); 352 } 353 return status; 354} 355 356} // namespace V4_0 357} // namespace android 358