SpdifStreamOut.cpp revision 23d8997f58bb9c59fa3a1b9a6b2edbf1b2b0f4c6
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#include <hardware/audio.h> 21#include <utils/Log.h> 22 23#include <audio_utils/spdif/SPDIFEncoder.h> 24 25#include "AudioHwDevice.h" 26#include "AudioStreamOut.h" 27#include "SpdifStreamOut.h" 28 29namespace android { 30 31/** 32 * If the AudioFlinger is processing encoded data and the HAL expects 33 * PCM then we need to wrap the data in an SPDIF wrapper. 34 */ 35SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev, 36 audio_output_flags_t flags, 37 audio_format_t format) 38 : AudioStreamOut(dev,flags) 39 , mRateMultiplier(1) 40 , mSpdifEncoder(this, format) 41 , mRenderPositionHal(0) 42 , mPreviousHalPosition32(0) 43{ 44} 45 46status_t SpdifStreamOut::open( 47 audio_io_handle_t handle, 48 audio_devices_t devices, 49 struct audio_config *config, 50 const char *address) 51{ 52 struct audio_config customConfig = *config; 53 54 // Some data bursts run at a higher sample rate. 55 // TODO Move this into the audio_utils as a static method. 56 switch(config->format) { 57 case AUDIO_FORMAT_E_AC3: 58 mRateMultiplier = 4; 59 break; 60 case AUDIO_FORMAT_AC3: 61 case AUDIO_FORMAT_DTS: 62 case AUDIO_FORMAT_DTS_HD: 63 mRateMultiplier = 1; 64 break; 65 default: 66 ALOGE("ERROR SpdifStreamOut::open() unrecognized format 0x%08X\n", 67 config->format); 68 return BAD_VALUE; 69 } 70 customConfig.sample_rate = config->sample_rate * mRateMultiplier; 71 72 customConfig.format = AUDIO_FORMAT_PCM_16_BIT; 73 customConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO; 74 75 // Always print this because otherwise it could be very confusing if the 76 // HAL and AudioFlinger are using different formats. 77 // Print before open() because HAL may modify customConfig. 78 ALOGI("SpdifStreamOut::open() AudioFlinger requested" 79 " sampleRate %d, format %#x, channelMask %#x", 80 config->sample_rate, 81 config->format, 82 config->channel_mask); 83 ALOGI("SpdifStreamOut::open() HAL configured for" 84 " sampleRate %d, format %#x, channelMask %#x", 85 customConfig.sample_rate, 86 customConfig.format, 87 customConfig.channel_mask); 88 89 status_t status = AudioStreamOut::open( 90 handle, 91 devices, 92 &customConfig, 93 address); 94 95 ALOGI("SpdifStreamOut::open() status = %d", status); 96 97 return status; 98} 99 100// Account for possibly higher sample rate. 101status_t SpdifStreamOut::getRenderPosition(uint32_t *frames) 102{ 103 uint32_t halPosition = 0; 104 status_t status = AudioStreamOut::getRenderPosition(&halPosition); 105 if (status != NO_ERROR) { 106 return status; 107 } 108 109 // Accumulate a 64-bit position so that we wrap at the right place. 110 if (mRateMultiplier != 1) { 111 // Maintain a 64-bit render position. 112 int32_t deltaHalPosition = (int32_t)(halPosition - mPreviousHalPosition32); 113 mPreviousHalPosition32 = halPosition; 114 mRenderPositionHal += deltaHalPosition; 115 116 // Scale from device sample rate to application rate. 117 uint64_t renderPositionApp = mRenderPositionHal / mRateMultiplier; 118 ALOGV("SpdifStreamOut::getRenderPosition() " 119 "renderPositionAppRate = %llu = %llu / %u\n", 120 renderPositionApp, mRenderPositionHal, mRateMultiplier); 121 122 *frames = (uint32_t)renderPositionApp; 123 } else { 124 *frames = halPosition; 125 } 126 return status; 127} 128 129int SpdifStreamOut::flush() 130{ 131 // FIXME Is there an issue here with flush being asynchronous? 132 mRenderPositionHal = 0; 133 mPreviousHalPosition32 = 0; 134 return AudioStreamOut::flush(); 135} 136 137int SpdifStreamOut::standby() 138{ 139 mRenderPositionHal = 0; 140 mPreviousHalPosition32 = 0; 141 return AudioStreamOut::standby(); 142} 143 144// Account for possibly higher sample rate. 145// This is much easier when all the values are 64-bit. 146status_t SpdifStreamOut::getPresentationPosition(uint64_t *frames, 147 struct timespec *timestamp) 148{ 149 uint64_t halFrames = 0; 150 status_t status = AudioStreamOut::getPresentationPosition(&halFrames, timestamp); 151 *frames = halFrames / mRateMultiplier; 152 return status; 153} 154 155size_t SpdifStreamOut::getFrameSize() 156{ 157 return sizeof(int8_t); 158} 159 160ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes) 161{ 162 return AudioStreamOut::write(buffer, bytes); 163} 164 165ssize_t SpdifStreamOut::write(const void* buffer, size_t bytes) 166{ 167 // Write to SPDIF wrapper. It will call back to writeDataBurst(). 168 return mSpdifEncoder.write(buffer, bytes); 169} 170 171} // namespace android 172