summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorPhil Burk <philburk@google.com>2015-02-11 13:40:50 -0800
committerPhil Burk <philburk@google.com>2015-03-24 13:24:18 -0700
commit062e67a26e0553dd142be622821f493df541f0c6 (patch)
tree125d28264adfc5b7bd993bb343569eea63bfb95d /services
parent21b51b61ee52e6aa74d98b138d3dd4f0e17b1441 (diff)
downloadframeworks_av-062e67a26e0553dd142be622821f493df541f0c6.zip
frameworks_av-062e67a26e0553dd142be622821f493df541f0c6.tar.gz
frameworks_av-062e67a26e0553dd142be622821f493df541f0c6.tar.bz2
AudioFlinger: call SPDIF wrapper from AudioFlinger
Create an interface layer between the AudioFlinger and the HAL that manages the wrapping and format conversion. Removed unnecessary includes. Handle rate conversion in getRenderPosition(). Try to open HAL with encoded format before wrapping with SPDIF. Bug: 17566660 Change-Id: I00ad888ca15ff0f85b85efb8167c7f5ea761a244 Signed-off-by: Phil Burk <philburk@google.com>
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/Android.mk4
-rw-r--r--services/audioflinger/AudioFlinger.cpp31
-rw-r--r--services/audioflinger/AudioFlinger.h54
-rw-r--r--services/audioflinger/AudioHwDevice.cpp94
-rw-r--r--services/audioflinger/AudioHwDevice.h88
-rw-r--r--services/audioflinger/AudioStreamOut.cpp117
-rw-r--r--services/audioflinger/AudioStreamOut.h83
-rw-r--r--services/audioflinger/SpdifStreamOut.cpp166
-rw-r--r--services/audioflinger/SpdifStreamOut.h107
-rw-r--r--services/audioflinger/Threads.cpp30
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 d0b825c..54e0043 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, &timestamp.mTime);
+ int ret = mOutput->getPresentationPosition(&position64, &timestamp.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);