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 <media/audiohal/DeviceHalInterface.h> 22 #include <media/audiohal/StreamHalInterface.h> 23 #include <system/audio.h> 24 #include <utils/Log.h> 25 26 #include "AudioHwDevice.h" 27 #include "AudioStreamOut.h" 28 29 namespace android { 30 31 // ---------------------------------------------------------------------------- 32 AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags) 33 : audioHwDev(dev) 34 , stream(NULL) 35 , flags(flags) 36 , mFramesWritten(0) 37 , mFramesWrittenAtStandby(0) 38 , mRenderPosition(0) 39 , mRateMultiplier(1) 40 , mHalFormatHasProportionalFrames(false) 41 , mHalFrameSize(0) 42 { 43 } 44 45 AudioStreamOut::~AudioStreamOut() 46 { 47 } 48 49 sp<DeviceHalInterface> AudioStreamOut::hwDev() const 50 { 51 return audioHwDev->hwDevice(); 52 } 53 54 status_t AudioStreamOut::getRenderPosition(uint64_t *frames) 55 { 56 if (stream == 0) { 57 return NO_INIT; 58 } 59 60 uint32_t halPosition = 0; 61 status_t status = stream->getRenderPosition(&halPosition); 62 if (status != NO_ERROR) { 63 return status; 64 } 65 66 // Maintain a 64-bit render position using the 32-bit result from the HAL. 67 // This delta calculation relies on the arithmetic overflow behavior 68 // of integers. For example (100 - 0xFFFFFFF0) = 116. 69 uint32_t truncatedPosition = (uint32_t)mRenderPosition; 70 int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition); 71 if (deltaHalPosition > 0) { 72 mRenderPosition += deltaHalPosition; 73 } 74 // Scale from HAL sample rate to application rate. 75 *frames = mRenderPosition / mRateMultiplier; 76 77 return status; 78 } 79 80 // return bottom 32-bits of the render position 81 status_t AudioStreamOut::getRenderPosition(uint32_t *frames) 82 { 83 uint64_t position64 = 0; 84 status_t status = getRenderPosition(&position64); 85 if (status == NO_ERROR) { 86 *frames = (uint32_t)position64; 87 } 88 return status; 89 } 90 91 status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) 92 { 93 if (stream == 0) { 94 return NO_INIT; 95 } 96 97 uint64_t halPosition = 0; 98 status_t status = stream->getPresentationPosition(&halPosition, timestamp); 99 if (status != NO_ERROR) { 100 return status; 101 } 102 103 // Adjust for standby using HAL rate frames. 104 // Only apply this correction if the HAL is getting PCM frames. 105 if (mHalFormatHasProportionalFrames) { 106 uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ? 107 0 : (halPosition - mFramesWrittenAtStandby); 108 // Scale from HAL sample rate to application rate. 109 *frames = adjustedPosition / mRateMultiplier; 110 } else { 111 // For offloaded MP3 and other compressed formats. 112 *frames = halPosition; 113 } 114 115 return status; 116 } 117 118 status_t AudioStreamOut::open( 119 audio_io_handle_t handle, 120 audio_devices_t devices, 121 struct audio_config *config, 122 const char *address) 123 { 124 sp<StreamOutHalInterface> outStream; 125 126 audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937) 127 ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO) 128 : flags; 129 130 int status = hwDev()->openOutputStream( 131 handle, 132 devices, 133 customFlags, 134 config, 135 address, 136 &outStream); 137 ALOGV("AudioStreamOut::open(), HAL returned " 138 " stream %p, sampleRate %d, Format %#x, " 139 "channelMask %#x, status %d", 140 outStream.get(), 141 config->sample_rate, 142 config->format, 143 config->channel_mask, 144 status); 145 146 // Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare 147 // it as PCM then it will probably work. 148 if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) { 149 struct audio_config customConfig = *config; 150 customConfig.format = AUDIO_FORMAT_PCM_16_BIT; 151 152 status = hwDev()->openOutputStream( 153 handle, 154 devices, 155 customFlags, 156 &customConfig, 157 address, 158 &outStream); 159 ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status); 160 } 161 162 if (status == NO_ERROR) { 163 stream = outStream; 164 mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format); 165 status = stream->getFrameSize(&mHalFrameSize); 166 } 167 168 return status; 169 } 170 171 audio_format_t AudioStreamOut::getFormat() const 172 { 173 audio_format_t result; 174 return stream->getFormat(&result) == OK ? result : AUDIO_FORMAT_INVALID; 175 } 176 177 uint32_t AudioStreamOut::getSampleRate() const 178 { 179 uint32_t result; 180 return stream->getSampleRate(&result) == OK ? result : 0; 181 } 182 183 audio_channel_mask_t AudioStreamOut::getChannelMask() const 184 { 185 audio_channel_mask_t result; 186 return stream->getChannelMask(&result) == OK ? result : AUDIO_CHANNEL_INVALID; 187 } 188 189 int AudioStreamOut::flush() 190 { 191 mRenderPosition = 0; 192 mFramesWritten = 0; 193 mFramesWrittenAtStandby = 0; 194 status_t result = stream->flush(); 195 return result != INVALID_OPERATION ? result : NO_ERROR; 196 } 197 198 int AudioStreamOut::standby() 199 { 200 mRenderPosition = 0; 201 mFramesWrittenAtStandby = mFramesWritten; 202 return stream->standby(); 203 } 204 205 ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes) 206 { 207 size_t bytesWritten; 208 status_t result = stream->write(buffer, numBytes, &bytesWritten); 209 if (result == OK && bytesWritten > 0 && mHalFrameSize > 0) { 210 mFramesWritten += bytesWritten / mHalFrameSize; 211 } 212 return result == OK ? bytesWritten : result; 213 } 214 215 } // namespace android 216