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