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 27 namespace android { 28 29 // ---------------------------------------------------------------------------- 30 AudioStreamOut::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 43 audio_hw_device_t *AudioStreamOut::hwDev() const 44 { 45 return audioHwDev->hwDevice(); 46 } 47 48 status_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 75 status_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 85 status_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 112 status_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 167 audio_format_t AudioStreamOut::getFormat() const 168 { 169 return stream->common.get_format(&stream->common); 170 } 171 172 uint32_t AudioStreamOut::getSampleRate() const 173 { 174 return stream->common.get_sample_rate(&stream->common); 175 } 176 177 audio_channel_mask_t AudioStreamOut::getChannelMask() const 178 { 179 return stream->common.get_channels(&stream->common); 180 } 181 182 int 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 194 int AudioStreamOut::standby() 195 { 196 ALOG_ASSERT(stream != NULL); 197 mRenderPosition = 0; 198 mFramesWrittenAtStandby = mFramesWritten; 199 return stream->common.standby(&stream->common); 200 } 201 202 ssize_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