1/* 2** 3** Copyright 2015, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#define LOG_TAG "AudioFlinger" 19//#define LOG_NDEBUG 0 20 21#include <hardware/audio.h> 22#include <utils/Log.h> 23 24#include "AudioHwDevice.h" 25#include "AudioStreamOut.h" 26 27namespace android { 28 29// ---------------------------------------------------------------------------- 30AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags) 31 : audioHwDev(dev) 32 , stream(NULL) 33 , flags(flags) 34 , mFramesWritten(0) 35 , mFramesWrittenAtStandby(0) 36 , mRenderPosition(0) 37 , mRateMultiplier(1) 38 , mHalFormatHasProportionalFrames(false) 39 , mHalFrameSize(0) 40{ 41} 42 43audio_hw_device_t *AudioStreamOut::hwDev() const 44{ 45 return audioHwDev->hwDevice(); 46} 47 48status_t AudioStreamOut::getRenderPosition(uint64_t *frames) 49{ 50 if (stream == NULL) { 51 return NO_INIT; 52 } 53 54 uint32_t halPosition = 0; 55 status_t status = stream->get_render_position(stream, &halPosition); 56 if (status != NO_ERROR) { 57 return status; 58 } 59 60 // Maintain a 64-bit render position using the 32-bit result from the HAL. 61 // This delta calculation relies on the arithmetic overflow behavior 62 // of integers. For example (100 - 0xFFFFFFF0) = 116. 63 uint32_t truncatedPosition = (uint32_t)mRenderPosition; 64 int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition); 65 if (deltaHalPosition > 0) { 66 mRenderPosition += deltaHalPosition; 67 } 68 // Scale from HAL sample rate to application rate. 69 *frames = mRenderPosition / mRateMultiplier; 70 71 return status; 72} 73 74// return bottom 32-bits of the render position 75status_t AudioStreamOut::getRenderPosition(uint32_t *frames) 76{ 77 uint64_t position64 = 0; 78 status_t status = getRenderPosition(&position64); 79 if (status == NO_ERROR) { 80 *frames = (uint32_t)position64; 81 } 82 return status; 83} 84 85status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) 86{ 87 if (stream == NULL) { 88 return NO_INIT; 89 } 90 91 uint64_t halPosition = 0; 92 status_t status = stream->get_presentation_position(stream, &halPosition, timestamp); 93 if (status != NO_ERROR) { 94 return status; 95 } 96 97 // Adjust for standby using HAL rate frames. 98 // Only apply this correction if the HAL is getting PCM frames. 99 if (mHalFormatHasProportionalFrames) { 100 uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ? 101 0 : (halPosition - mFramesWrittenAtStandby); 102 // Scale from HAL sample rate to application rate. 103 *frames = adjustedPosition / mRateMultiplier; 104 } else { 105 // For offloaded MP3 and other compressed formats. 106 *frames = halPosition; 107 } 108 109 return status; 110} 111 112status_t AudioStreamOut::open( 113 audio_io_handle_t handle, 114 audio_devices_t devices, 115 struct audio_config *config, 116 const char *address) 117{ 118 audio_stream_out_t *outStream; 119 120 audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937) 121 ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) 122 : flags; 123 124 int status = hwDev()->open_output_stream( 125 hwDev(), 126 handle, 127 devices, 128 customFlags, 129 config, 130 &outStream, 131 address); 132 ALOGV("AudioStreamOut::open(), HAL returned " 133 " stream %p, sampleRate %d, Format %#x, " 134 "channelMask %#x, status %d", 135 outStream, 136 config->sample_rate, 137 config->format, 138 config->channel_mask, 139 status); 140 141 // Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare 142 // it as PCM then it will probably work. 143 if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) { 144 struct audio_config customConfig = *config; 145 customConfig.format = AUDIO_FORMAT_PCM_16_BIT; 146 147 status = hwDev()->open_output_stream( 148 hwDev(), 149 handle, 150 devices, 151 customFlags, 152 &customConfig, 153 &outStream, 154 address); 155 ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status); 156 } 157 158 if (status == NO_ERROR) { 159 stream = outStream; 160 mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format); 161 mHalFrameSize = audio_stream_out_frame_size(stream); 162 } 163 164 return status; 165} 166 167audio_format_t AudioStreamOut::getFormat() const 168{ 169 return stream->common.get_format(&stream->common); 170} 171 172uint32_t AudioStreamOut::getSampleRate() const 173{ 174 return stream->common.get_sample_rate(&stream->common); 175} 176 177audio_channel_mask_t AudioStreamOut::getChannelMask() const 178{ 179 return stream->common.get_channels(&stream->common); 180} 181 182int AudioStreamOut::flush() 183{ 184 ALOG_ASSERT(stream != NULL); 185 mRenderPosition = 0; 186 mFramesWritten = 0; 187 mFramesWrittenAtStandby = 0; 188 if (stream->flush != NULL) { 189 return stream->flush(stream); 190 } 191 return NO_ERROR; 192} 193 194int AudioStreamOut::standby() 195{ 196 ALOG_ASSERT(stream != NULL); 197 mRenderPosition = 0; 198 mFramesWrittenAtStandby = mFramesWritten; 199 return stream->common.standby(&stream->common); 200} 201 202ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes) 203{ 204 ALOG_ASSERT(stream != NULL); 205 ssize_t bytesWritten = stream->write(stream, buffer, numBytes); 206 if (bytesWritten > 0 && mHalFrameSize > 0) { 207 mFramesWritten += bytesWritten / mHalFrameSize; 208 } 209 return bytesWritten; 210} 211 212} // namespace android 213