/* ** ** Copyright 2015, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "AudioFlinger" //#define LOG_NDEBUG 0 #include <hardware/audio.h> #include <utils/Log.h> #include "AudioHwDevice.h" #include "AudioStreamOut.h" namespace android { // ---------------------------------------------------------------------------- AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags) : audioHwDev(dev) , stream(NULL) , flags(flags) , mFramesWritten(0) , mFramesWrittenAtStandby(0) , mRenderPosition(0) , mRateMultiplier(1) , mHalFormatIsLinearPcm(false) , mHalFrameSize(0) { } audio_hw_device_t *AudioStreamOut::hwDev() const { return audioHwDev->hwDevice(); } status_t AudioStreamOut::getRenderPosition(uint64_t *frames) { if (stream == NULL) { return NO_INIT; } uint32_t halPosition = 0; status_t status = stream->get_render_position(stream, &halPosition); if (status != NO_ERROR) { return status; } // Maintain a 64-bit render position using the 32-bit result from the HAL. // This delta calculation relies on the arithmetic overflow behavior // of integers. For example (100 - 0xFFFFFFF0) = 116. uint32_t truncatedPosition = (uint32_t)mRenderPosition; int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition); if (deltaHalPosition > 0) { mRenderPosition += deltaHalPosition; } // Scale from HAL sample rate to application rate. *frames = mRenderPosition / mRateMultiplier; return status; } // return bottom 32-bits of the render position status_t AudioStreamOut::getRenderPosition(uint32_t *frames) { uint64_t position64 = 0; status_t status = getRenderPosition(&position64); if (status == NO_ERROR) { *frames = (uint32_t)position64; } return status; } status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { if (stream == NULL) { return NO_INIT; } uint64_t halPosition = 0; status_t status = stream->get_presentation_position(stream, &halPosition, timestamp); if (status != NO_ERROR) { return status; } // Adjust for standby using HAL rate frames. // Only apply this correction if the HAL is getting PCM frames. if (mHalFormatIsLinearPcm) { uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ? 0 : (halPosition - mFramesWrittenAtStandby); // Scale from HAL sample rate to application rate. *frames = adjustedPosition / mRateMultiplier; } else { // For offloaded MP3 and other compressed formats. *frames = halPosition; } return status; } status_t AudioStreamOut::open( audio_io_handle_t handle, audio_devices_t devices, struct audio_config *config, const char *address) { audio_stream_out_t *outStream; int status = hwDev()->open_output_stream( hwDev(), handle, devices, flags, config, &outStream, address); ALOGV("AudioStreamOut::open(), HAL open_output_stream returned " " %p, sampleRate %d, Format %#x, " "channelMask %#x, status %d", outStream, config->sample_rate, config->format, config->channel_mask, status); if (status == NO_ERROR) { stream = outStream; mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format); ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm); mHalFrameSize = audio_stream_out_frame_size(stream); } return status; } audio_format_t AudioStreamOut::getFormat() const { return stream->common.get_format(&stream->common); } uint32_t AudioStreamOut::getSampleRate() const { return stream->common.get_sample_rate(&stream->common); } audio_channel_mask_t AudioStreamOut::getChannelMask() const { return stream->common.get_channels(&stream->common); } int AudioStreamOut::flush() { ALOG_ASSERT(stream != NULL); mRenderPosition = 0; mFramesWritten = 0; mFramesWrittenAtStandby = 0; if (stream->flush != NULL) { return stream->flush(stream); } return NO_ERROR; } int AudioStreamOut::standby() { ALOG_ASSERT(stream != NULL); mRenderPosition = 0; mFramesWrittenAtStandby = mFramesWritten; return stream->common.standby(&stream->common); } ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes) { ALOG_ASSERT(stream != NULL); ssize_t bytesWritten = stream->write(stream, buffer, numBytes); if (bytesWritten > 0 && mHalFrameSize > 0) { mFramesWritten += bytesWritten / mHalFrameSize; } return bytesWritten; } } // namespace android