diff options
author | Phil Burk <philburk@google.com> | 2015-03-24 22:51:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-03-24 22:51:26 +0000 |
commit | ae9710473b88592c557488bfcae71616d9e9b75f (patch) | |
tree | 40878341868ee948401ae73696fa857d1ce7a156 /services | |
parent | 40272963eb8f8d8d7a1f39e6a25ae73bc755e553 (diff) | |
parent | 062e67a26e0553dd142be622821f493df541f0c6 (diff) | |
download | frameworks_av-ae9710473b88592c557488bfcae71616d9e9b75f.zip frameworks_av-ae9710473b88592c557488bfcae71616d9e9b75f.tar.gz frameworks_av-ae9710473b88592c557488bfcae71616d9e9b75f.tar.bz2 |
Merge "AudioFlinger: call SPDIF wrapper from AudioFlinger"
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/Android.mk | 4 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 31 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 54 | ||||
-rw-r--r-- | services/audioflinger/AudioHwDevice.cpp | 94 | ||||
-rw-r--r-- | services/audioflinger/AudioHwDevice.h | 88 | ||||
-rw-r--r-- | services/audioflinger/AudioStreamOut.cpp | 117 | ||||
-rw-r--r-- | services/audioflinger/AudioStreamOut.h | 83 | ||||
-rw-r--r-- | services/audioflinger/SpdifStreamOut.cpp | 166 | ||||
-rw-r--r-- | services/audioflinger/SpdifStreamOut.h | 107 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 30 |
10 files changed, 688 insertions, 86 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 642ff82..fee2347 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -39,6 +39,9 @@ LOCAL_SRC_FILES:= \ AudioFlinger.cpp \ Threads.cpp \ Tracks.cpp \ + AudioHwDevice.cpp \ + AudioStreamOut.cpp \ + SpdifStreamOut.cpp \ Effects.cpp \ AudioMixer.cpp.arm \ PatchPanel.cpp @@ -52,6 +55,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SHARED_LIBRARIES := \ libaudioresampler \ + libaudiospdif \ libaudioutils \ libcommon_time_client \ libcutils \ diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 461b5d3..f3206cb 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -272,7 +272,7 @@ static const char * const audio_interfaces[] = { }; #define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0]))) -AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l( +AudioHwDevice* AudioFlinger::findSuitableHwDev_l( audio_module_handle_t module, audio_devices_t devices) { @@ -1716,8 +1716,6 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_ mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; - audio_stream_out_t *outStream = NULL; - // FOR TESTING ONLY: // This if statement allows overriding the audio policy settings // and forcing a specific format or channel mask to the HAL/Sink device for testing. @@ -1739,25 +1737,18 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_ } } - status_t status = hwDevHal->open_output_stream(hwDevHal, - *output, - devices, - flags, - config, - &outStream, - address.string()); + AudioStreamOut *outputStream = NULL; + status_t status = outHwDev->openOutputStream( + &outputStream, + *output, + devices, + flags, + config, + address.string()); mHardwareStatus = AUDIO_HW_IDLE; - ALOGV("openOutput_l() openOutputStream returned output %p, sampleRate %d, Format %#x, " - "channelMask %#x, status %d", - outStream, - config->sample_rate, - config->format, - config->channel_mask, - status); - if (status == NO_ERROR && outStream != NULL) { - AudioStreamOut *outputStream = new AudioStreamOut(outHwDev, outStream, flags); + if (status == NO_ERROR) { PlaybackThread *thread; if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) { @@ -1787,7 +1778,7 @@ status_t AudioFlinger::openOutput(audio_module_handle_t module, uint32_t *latencyMs, audio_output_flags_t flags) { - ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x", + ALOGI("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x", module, (devices != NULL) ? *devices : 0, config->sample_rate, diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 7b76185..c7d9161 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -56,6 +56,9 @@ #include <media/nbaio/NBAIO.h> #include "AudioWatchdog.h" #include "AudioMixer.h" +#include "AudioStreamOut.h" +#include "SpdifStreamOut.h" +#include "AudioHwDevice.h" #include <powermanager/IPowerManager.h> @@ -311,7 +314,6 @@ public: wp<RefBase> cookie); private: - class AudioHwDevice; // fwd declaration for findSuitableHwDev_l audio_mode_t getMode() const { return mMode; } @@ -449,7 +451,7 @@ private: class EffectModule; class EffectHandle; class EffectChain; - struct AudioStreamOut; + struct AudioStreamIn; struct stream_type_t { @@ -586,57 +588,11 @@ private: // Return true if the effect was found in mOrphanEffectChains, false otherwise. bool updateOrphanEffectChains(const sp<EffectModule>& effect); - class AudioHwDevice { - public: - enum Flags { - AHWD_CAN_SET_MASTER_VOLUME = 0x1, - AHWD_CAN_SET_MASTER_MUTE = 0x2, - }; - - AudioHwDevice(audio_module_handle_t handle, - const char *moduleName, - audio_hw_device_t *hwDevice, - Flags flags) - : mHandle(handle), mModuleName(strdup(moduleName)) - , mHwDevice(hwDevice) - , mFlags(flags) { } - /*virtual*/ ~AudioHwDevice() { free((void *)mModuleName); } - - bool canSetMasterVolume() const { - return (0 != (mFlags & AHWD_CAN_SET_MASTER_VOLUME)); - } - - bool canSetMasterMute() const { - return (0 != (mFlags & AHWD_CAN_SET_MASTER_MUTE)); - } - - audio_module_handle_t handle() const { return mHandle; } - const char *moduleName() const { return mModuleName; } - audio_hw_device_t *hwDevice() const { return mHwDevice; } - uint32_t version() const { return mHwDevice->common.version; } - private: - const audio_module_handle_t mHandle; - const char * const mModuleName; - audio_hw_device_t * const mHwDevice; - const Flags mFlags; - }; - - // AudioStreamOut and AudioStreamIn are immutable, so their fields are const. + // AudioStreamIn is immutable, so their fields are const. // For emphasis, we could also make all pointers to them be "const *", // but that would clutter the code unnecessarily. - struct AudioStreamOut { - AudioHwDevice* const audioHwDev; - audio_stream_out_t* const stream; - const audio_output_flags_t flags; - - audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); } - - AudioStreamOut(AudioHwDevice *dev, audio_stream_out_t *out, audio_output_flags_t flags) : - audioHwDev(dev), stream(out), flags(flags) {} - }; - struct AudioStreamIn { AudioHwDevice* const audioHwDev; audio_stream_in_t* const stream; diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp new file mode 100644 index 0000000..09d86ea --- /dev/null +++ b/services/audioflinger/AudioHwDevice.cpp @@ -0,0 +1,94 @@ +/* +** +** Copyright 2007, 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 "AudioHwDevice" +//#define LOG_NDEBUG 0 + +#include <hardware/audio.h> +#include <utils/Log.h> + +#include <audio_utils/spdif/SPDIFEncoder.h> + +#include "AudioHwDevice.h" +#include "AudioStreamOut.h" +#include "SpdifStreamOut.h" + +namespace android { + +// ---------------------------------------------------------------------------- + +status_t AudioHwDevice::openOutputStream( + AudioStreamOut **ppStreamOut, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + const char *address) +{ + + struct audio_config originalConfig = *config; + AudioStreamOut *outputStream = new AudioStreamOut(this, flags); + + // Try to open the HAL first using the current format. + ALOGV("AudioHwDevice::openOutputStream(), try " + " sampleRate %d, Format %#x, " + "channelMask %#x", + config->sample_rate, + config->format, + config->channel_mask); + status_t status = outputStream->open(handle, devices, config, address); + + if (status != NO_ERROR) { + delete outputStream; + outputStream = NULL; + + // FIXME Look at any modification to the config. + // The HAL might modify the config to suggest a wrapped format. + // Log this so we can see what the HALs are doing. + ALOGI("AudioHwDevice::openOutputStream(), HAL returned" + " sampleRate %d, Format %#x, " + "channelMask %#x, status %d", + config->sample_rate, + config->format, + config->channel_mask, + status); + + // If the data is encoded then try again using wrapped PCM. + bool wrapperNeeded = !audio_is_linear_pcm(originalConfig.format) + && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) + && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0); + + // FIXME - Add isEncodingSupported() query to SPDIF wrapper then + // call it from here. + if (wrapperNeeded) { + outputStream = new SpdifStreamOut(this, flags); + status = outputStream->open(handle, devices, &originalConfig, address); + if (status != NO_ERROR) { + ALOGE("ERROR - AudioHwDevice::openOutputStream(), SPDIF open returned %d", + status); + delete outputStream; + outputStream = NULL; + } + } + } + + *ppStreamOut = outputStream; + return status; +} + + +}; // namespace android diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h new file mode 100644 index 0000000..b9f65c1 --- /dev/null +++ b/services/audioflinger/AudioHwDevice.h @@ -0,0 +1,88 @@ +/* +** +** Copyright 2007, 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. +*/ + +#ifndef ANDROID_AUDIO_HW_DEVICE_H +#define ANDROID_AUDIO_HW_DEVICE_H + +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> + +#include <hardware/audio.h> +#include <utils/Errors.h> +#include <system/audio.h> + + +namespace android { + +class AudioStreamOut; + +class AudioHwDevice { +public: + enum Flags { + AHWD_CAN_SET_MASTER_VOLUME = 0x1, + AHWD_CAN_SET_MASTER_MUTE = 0x2, + }; + + AudioHwDevice(audio_module_handle_t handle, + const char *moduleName, + audio_hw_device_t *hwDevice, + Flags flags) + : mHandle(handle) + , mModuleName(strdup(moduleName)) + , mHwDevice(hwDevice) + , mFlags(flags) { } + virtual ~AudioHwDevice() { free((void *)mModuleName); } + + bool canSetMasterVolume() const { + return (0 != (mFlags & AHWD_CAN_SET_MASTER_VOLUME)); + } + + bool canSetMasterMute() const { + return (0 != (mFlags & AHWD_CAN_SET_MASTER_MUTE)); + } + + audio_module_handle_t handle() const { return mHandle; } + const char *moduleName() const { return mModuleName; } + audio_hw_device_t *hwDevice() const { return mHwDevice; } + uint32_t version() const { return mHwDevice->common.version; } + + /** This method creates and opens the audio hardware output stream. + * The "address" parameter qualifies the "devices" audio device type if needed. + * The format format depends on the device type: + * - Bluetooth devices use the MAC address of the device in the form "00:11:22:AA:BB:CC" + * - USB devices use the ALSA card and device numbers in the form "card=X;device=Y" + * - Other devices may use a number or any other string. + */ + status_t openOutputStream( + AudioStreamOut **ppStreamOut, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + const char *address); + +private: + const audio_module_handle_t mHandle; + const char * const mModuleName; + audio_hw_device_t * const mHwDevice; + const Flags mFlags; +}; + +} // namespace android + +#endif // ANDROID_AUDIO_HW_DEVICE_H diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp new file mode 100644 index 0000000..e6d8f09 --- /dev/null +++ b/services/audioflinger/AudioStreamOut.cpp @@ -0,0 +1,117 @@ +/* +** +** 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) +{ +} + +audio_hw_device_t* AudioStreamOut::hwDev() const +{ + return audioHwDev->hwDevice(); +} + +status_t AudioStreamOut::getRenderPosition(uint32_t *frames) +{ + if (stream == NULL) { + return NO_INIT; + } + return stream->get_render_position(stream, frames); +} + +status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) +{ + if (stream == NULL) { + return NO_INIT; + } + return stream->get_presentation_position(stream, frames, timestamp); +} + +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; + } + + return status; +} + +size_t AudioStreamOut::getFrameSize() +{ + ALOG_ASSERT(stream != NULL); + return audio_stream_out_frame_size(stream); +} + +int AudioStreamOut::flush() +{ + ALOG_ASSERT(stream != NULL); + if (stream->flush != NULL) { + return stream->flush(stream); + } + return NO_ERROR; +} + +int AudioStreamOut::standby() +{ + ALOG_ASSERT(stream != NULL); + return stream->common.standby(&stream->common); +} + +ssize_t AudioStreamOut::write(const void* buffer, size_t bytes) +{ + ALOG_ASSERT(stream != NULL); + return stream->write(stream, buffer, bytes); +} + +} // namespace android diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h new file mode 100644 index 0000000..e91ca9c --- /dev/null +++ b/services/audioflinger/AudioStreamOut.h @@ -0,0 +1,83 @@ +/* +** +** 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. +*/ + +#ifndef ANDROID_AUDIO_STREAM_OUT_H +#define ANDROID_AUDIO_STREAM_OUT_H + +#include <stdint.h> +#include <sys/types.h> + +#include <system/audio.h> + +#include "AudioStreamOut.h" + +namespace android { + +class AudioHwDevice; + +/** + * Managed access to a HAL output stream. + */ +class AudioStreamOut { +public: +// AudioStreamOut is immutable, so its fields are const. +// For emphasis, we could also make all pointers to them be "const *", +// but that would clutter the code unnecessarily. + AudioHwDevice * const audioHwDev; + audio_stream_out_t *stream; + const audio_output_flags_t flags; + + audio_hw_device_t *hwDev() const; + + AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags); + + virtual status_t open( + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + const char *address); + + virtual ~AudioStreamOut() { } + + virtual status_t getRenderPosition(uint32_t *frames); + + virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp); + + /** + * Write audio buffer to driver. Returns number of bytes written, or a + * negative status_t. If at least one frame was written successfully prior to the error, + * it is suggested that the driver return that successful (short) byte count + * and then return an error in the subsequent call. + * + * If set_callback() has previously been called to enable non-blocking mode + * the write() is not allowed to block. It must write only the number of + * bytes that currently fit in the driver/hardware buffer and then return + * this byte count. If this is less than the requested write size the + * callback function must be called when more space is available in the + * driver/hardware buffer. + */ + virtual ssize_t write(const void *buffer, size_t bytes); + + virtual size_t getFrameSize(); + + virtual status_t flush(); + virtual status_t standby(); +}; + +} // namespace android + +#endif // ANDROID_AUDIO_STREAM_OUT_H diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp new file mode 100644 index 0000000..d23588e --- /dev/null +++ b/services/audioflinger/SpdifStreamOut.cpp @@ -0,0 +1,166 @@ +/* +** +** 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 <audio_utils/spdif/SPDIFEncoder.h> + +#include "AudioHwDevice.h" +#include "AudioStreamOut.h" +#include "SpdifStreamOut.h" + +namespace android { + +/** + * If the AudioFlinger is processing encoded data and the HAL expects + * PCM then we need to wrap the data in an SPDIF wrapper. + */ +SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev, audio_output_flags_t flags) + : AudioStreamOut(dev,flags) + , mRateMultiplier(1) + , mSpdifEncoder(this) + , mRenderPositionHal(0) + , mPreviousHalPosition32(0) +{ +} + +status_t SpdifStreamOut::open( + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + const char *address) +{ + struct audio_config customConfig = *config; + + customConfig.format = AUDIO_FORMAT_PCM_16_BIT; + customConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO; + + // Some data bursts run at a higher sample rate. + switch(config->format) { + case AUDIO_FORMAT_E_AC3: + mRateMultiplier = 4; + break; + case AUDIO_FORMAT_AC3: + mRateMultiplier = 1; + break; + default: + ALOGE("ERROR SpdifStreamOut::open() unrecognized format 0x%08X\n", + config->format); + return BAD_VALUE; + } + customConfig.sample_rate = config->sample_rate * mRateMultiplier; + + // Always print this because otherwise it could be very confusing if the + // HAL and AudioFlinger are using different formats. + // Print before open() because HAL may modify customConfig. + ALOGI("SpdifStreamOut::open() AudioFlinger requested" + " sampleRate %d, format %#x, channelMask %#x", + config->sample_rate, + config->format, + config->channel_mask); + ALOGI("SpdifStreamOut::open() HAL configured for" + " sampleRate %d, format %#x, channelMask %#x", + customConfig.sample_rate, + customConfig.format, + customConfig.channel_mask); + + status_t status = AudioStreamOut::open( + handle, + devices, + &customConfig, + address); + + ALOGI("SpdifStreamOut::open() status = %d", status); + + return status; +} + +// Account for possibly higher sample rate. +status_t SpdifStreamOut::getRenderPosition(uint32_t *frames) +{ + uint32_t halPosition = 0; + status_t status = AudioStreamOut::getRenderPosition(&halPosition); + if (status != NO_ERROR) { + return status; + } + + // Accumulate a 64-bit position so that we wrap at the right place. + if (mRateMultiplier != 1) { + // Maintain a 64-bit render position. + int32_t deltaHalPosition = (int32_t)(halPosition - mPreviousHalPosition32); + mPreviousHalPosition32 = halPosition; + mRenderPositionHal += deltaHalPosition; + + // Scale from device sample rate to application rate. + uint64_t renderPositionApp = mRenderPositionHal / mRateMultiplier; + ALOGV("SpdifStreamOut::getRenderPosition() " + "renderPositionAppRate = %llu = %llu / %u\n", + renderPositionApp, mRenderPositionHal, mRateMultiplier); + + *frames = (uint32_t)renderPositionApp; + } else { + *frames = halPosition; + } + return status; +} + +int SpdifStreamOut::flush() +{ + // FIXME Is there an issue here with flush being asynchronous? + mRenderPositionHal = 0; + mPreviousHalPosition32 = 0; + return AudioStreamOut::flush(); +} + +int SpdifStreamOut::standby() +{ + mRenderPositionHal = 0; + mPreviousHalPosition32 = 0; + return AudioStreamOut::standby(); +} + +// Account for possibly higher sample rate. +// This is much easier when all the values are 64-bit. +status_t SpdifStreamOut::getPresentationPosition(uint64_t *frames, + struct timespec *timestamp) +{ + uint64_t halFrames = 0; + status_t status = AudioStreamOut::getPresentationPosition(&halFrames, timestamp); + *frames = halFrames / mRateMultiplier; + return status; +} + +size_t SpdifStreamOut::getFrameSize() +{ + return sizeof(int8_t); +} + +ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes) +{ + return AudioStreamOut::write(buffer, bytes); +} + +ssize_t SpdifStreamOut::write(const void* buffer, size_t bytes) +{ + // Write to SPDIF wrapper. It will call back to writeDataBurst(). + return mSpdifEncoder.write(buffer, bytes); +} + +} // namespace android diff --git a/services/audioflinger/SpdifStreamOut.h b/services/audioflinger/SpdifStreamOut.h new file mode 100644 index 0000000..cb82ac7 --- /dev/null +++ b/services/audioflinger/SpdifStreamOut.h @@ -0,0 +1,107 @@ +/* +** +** 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. +*/ + +#ifndef ANDROID_SPDIF_STREAM_OUT_H +#define ANDROID_SPDIF_STREAM_OUT_H + +#include <stdint.h> +#include <sys/types.h> + +#include <system/audio.h> + +#include "AudioHwDevice.h" +#include "AudioStreamOut.h" +#include "SpdifStreamOut.h" + +#include <audio_utils/spdif/SPDIFEncoder.h> + +namespace android { + +/** + * Stream that is a PCM data burst in the HAL but looks like an encoded stream + * to the AudioFlinger. Wraps encoded data in an SPDIF wrapper per IEC61973-3. + */ +class SpdifStreamOut : public AudioStreamOut { +public: + + SpdifStreamOut(AudioHwDevice *dev, audio_output_flags_t flags); + + virtual ~SpdifStreamOut() { } + + virtual status_t open( + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + const char *address); + + virtual status_t getRenderPosition(uint32_t *frames); + + virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp); + + /** + * Write audio buffer to driver. Returns number of bytes written, or a + * negative status_t. If at least one frame was written successfully prior to the error, + * it is suggested that the driver return that successful (short) byte count + * and then return an error in the subsequent call. + * + * If set_callback() has previously been called to enable non-blocking mode + * the write() is not allowed to block. It must write only the number of + * bytes that currently fit in the driver/hardware buffer and then return + * this byte count. If this is less than the requested write size the + * callback function must be called when more space is available in the + * driver/hardware buffer. + */ + virtual ssize_t write(const void* buffer, size_t bytes); + + virtual size_t getFrameSize(); + + virtual status_t flush(); + virtual status_t standby(); + +private: + + class MySPDIFEncoder : public SPDIFEncoder + { + public: + MySPDIFEncoder(SpdifStreamOut *spdifStreamOut) + : mSpdifStreamOut(spdifStreamOut) + { + } + + virtual ssize_t writeOutput(const void* buffer, size_t bytes) + { + return mSpdifStreamOut->writeDataBurst(buffer, bytes); + } + protected: + SpdifStreamOut * const mSpdifStreamOut; + }; + + int mRateMultiplier; + MySPDIFEncoder mSpdifEncoder; + + // Used to implement getRenderPosition() + int64_t mRenderPositionHal; + uint32_t mPreviousHalPosition32; + + ssize_t writeDataBurst(const void* data, size_t bytes); + ssize_t writeInternal(const void* buffer, size_t bytes); + +}; + +} // namespace android + +#endif // ANDROID_SPDIF_STREAM_OUT_H diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 48bb21f..5988d2c 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2009,7 +2009,7 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() LOG_FATAL("HAL format %#x not supported for mixed output", mFormat); } - mFrameSize = audio_stream_out_frame_size(mOutput->stream); + mFrameSize = mOutput->getFrameSize(); mBufferSize = mOutput->stream->common.get_buffer_size(&mOutput->stream->common); mFrameCount = mBufferSize / mFrameSize; if (mFrameCount & 15) { @@ -2160,7 +2160,7 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui } else { status_t status; uint32_t frames; - status = mOutput->stream->get_render_position(mOutput->stream, &frames); + status = mOutput->getRenderPosition(&frames); *dspFrames = (size_t)frames; return status; } @@ -2202,13 +2202,13 @@ uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId) } -AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::getOutput() const +AudioStreamOut* AudioFlinger::PlaybackThread::getOutput() const { Mutex::Autolock _l(mLock); return mOutput; } -AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::clearOutput() +AudioStreamOut* AudioFlinger::PlaybackThread::clearOutput() { Mutex::Autolock _l(mLock); AudioStreamOut *output = mOutput; @@ -2354,8 +2354,7 @@ ssize_t AudioFlinger::PlaybackThread::threadLoop_write() } // FIXME We should have an implementation of timestamps for direct output threads. // They are used e.g for multichannel PCM playback over HDMI. - bytesWritten = mOutput->stream->write(mOutput->stream, - (char *)mSinkBuffer + offset, mBytesRemaining); + bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining); if (mUseAsyncWrite && ((bytesWritten < 0) || (bytesWritten == (ssize_t)mBytesRemaining))) { // do not wait for async callback in case of error of full write @@ -2908,8 +2907,7 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) if ((mType == OFFLOAD || mType == DIRECT) && mOutput != NULL && mOutput->stream->get_presentation_position) { uint64_t position64; - int ret = mOutput->stream->get_presentation_position( - mOutput->stream, &position64, ×tamp.mTime); + int ret = mOutput->getPresentationPosition(&position64, ×tamp.mTime); if (ret == 0) { timestamp.mPosition = (uint32_t)position64; return NO_ERROR; @@ -3289,7 +3287,7 @@ bool AudioFlinger::PlaybackThread::waitingAsyncCallback() void AudioFlinger::PlaybackThread::threadLoop_standby() { ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended); - mOutput->stream->common.standby(&mOutput->stream->common); + mOutput->standby(); if (mUseAsyncWrite != 0) { // discard any pending drain or write ack by incrementing sequence mWriteAckSequence = (mWriteAckSequence + 2) & ~1; @@ -4058,7 +4056,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa status = mOutput->stream->common.set_parameters(&mOutput->stream->common, keyValuePair.string()); if (!mStandby && status == INVALID_OPERATION) { - mOutput->stream->common.standby(&mOutput->stream->common); + mOutput->standby(); mStandby = true; mBytesWritten = 0; status = mOutput->stream->common.set_parameters(&mOutput->stream->common, @@ -4400,8 +4398,8 @@ void AudioFlinger::DirectOutputThread::threadLoop_mix() while (frameCount) { AudioBufferProvider::Buffer buffer; buffer.frameCount = frameCount; - mActiveTrack->getNextBuffer(&buffer); - if (buffer.raw == NULL) { + status_t status = mActiveTrack->getNextBuffer(&buffer); + if (status != NO_ERROR || buffer.raw == NULL) { memset(curBuf, 0, frameCount * mFrameSize); break; } @@ -4513,7 +4511,7 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& key status = mOutput->stream->common.set_parameters(&mOutput->stream->common, keyValuePair.string()); if (!mStandby && status == INVALID_OPERATION) { - mOutput->stream->common.standby(&mOutput->stream->common); + mOutput->standby(); mStandby = true; mBytesWritten = 0; status = mOutput->stream->common.set_parameters(&mOutput->stream->common, @@ -4576,9 +4574,7 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l() void AudioFlinger::DirectOutputThread::flushHw_l() { - if (mOutput->stream->flush != NULL) { - mOutput->stream->flush(mOutput->stream); - } + mOutput->flush(); mHwPaused = false; } @@ -4868,7 +4864,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr size_t audioHALFrames = (mOutput->stream->get_latency(mOutput->stream)*mSampleRate) / 1000; size_t framesWritten = - mBytesWritten / audio_stream_out_frame_size(mOutput->stream); + mBytesWritten / mOutput->getFrameSize(); track->presentationComplete(framesWritten, audioHALFrames); track->reset(); tracksToRemove->add(track); |