Abstract away access to audio streams HAL in AudioFlinger

In this CL all direct access to audio_stream_t, audio_stream_out_t, and
audio_stream_in_t their functions is encapsulated within the new
hierarchy of Stream[In|Out]HalLocal classes.  AudioFlinger uses
interface classes Stream[In|Out]HalInterface to access these functions.

Note that NBAIO still receives raw HAL stream handles and needs to be
converted separately.

Bug: 30222631
Test: manual with Loopback app

Change-Id: I6388cfa2006791c9c0aa7bb186719209726a2d48
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 068b917..c89b732 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -27,6 +27,7 @@
     AudioHwDevice.cpp           \
     AudioStreamOut.cpp          \
     SpdifStreamOut.cpp          \
+    StreamHalLocal.cpp          \
     DeviceHalLocal.cpp          \
     DevicesFactoryHalLocal.cpp	\
     EffectHalLocal.cpp          \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b5ab782..81f59de 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -48,8 +48,6 @@
 #include "DevicesFactoryHalInterface.h"
 #include "EffectsFactoryHalInterface.h"
 #include "ServiceUtilities.h"
-// FIXME: Remove after streams HAL is componentized
-#include "DeviceHalLocal.h"
 
 #include <media/AudioResamplerPublic.h>
 
@@ -399,7 +397,7 @@
             write(fd, result.string(), result.size());
         }
 
-        if (mEffectsFactoryHal.get() != NULL) {
+        if (mEffectsFactoryHal != 0) {
             mEffectsFactoryHal->dumpEffects(fd);
         } else {
             String8 result(kNoEffectsFactory);
@@ -2013,7 +2011,6 @@
     AudioStreamOut *out = thread->clearOutput();
     ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
     // from now on thread->mOutput is NULL
-    static_cast<DeviceHalLocal*>(out->hwDev().get())->closeOutputStream(out->stream);
     delete out;
 }
 
@@ -2109,12 +2106,12 @@
 
     audio_config_t halconfig = *config;
     sp<DeviceHalInterface> inHwHal = inHwDev->hwDevice();
-    audio_stream_in_t *inStream = NULL;
-    status_t status = static_cast<DeviceHalLocal*>(inHwHal.get())->openInputStream(
+    sp<StreamInHalInterface> inStream;
+    status_t status = inHwHal->openInputStream(
             *input, devices, &halconfig, flags, address.string(), source, &inStream);
     ALOGV("openInput_l() openInputStream returned input %p, SamplingRate %d"
            ", Format %#x, Channels %x, flags %#x, status %d addr %s",
-            inStream,
+            inStream.get(),
             halconfig.sample_rate,
             halconfig.format,
             halconfig.channel_mask,
@@ -2131,13 +2128,13 @@
         (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_8)) {
         // FIXME describe the change proposed by HAL (save old values so we can log them here)
         ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
-        inStream = NULL;
-        status = static_cast<DeviceHalLocal*>(inHwHal.get())->openInputStream(
+        inStream.clear();
+        status = inHwHal->openInputStream(
                 *input, devices, &halconfig, flags, address.string(), source, &inStream);
         // FIXME log this new status; HAL should not propose any further changes
     }
 
-    if (status == NO_ERROR && inStream != NULL) {
+    if (status == NO_ERROR && inStream != 0) {
 
 #ifdef TEE_SINK
         // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
@@ -2284,7 +2281,6 @@
     AudioStreamIn *in = thread->clearInput();
     ALOG_ASSERT(in != NULL, "in shouldn't be NULL");
     // from now on thread->mInput is NULL
-    static_cast<DeviceHalLocal*>(in->hwDev().get())->closeInputStream(in->stream);
     delete in;
 }
 
@@ -2649,7 +2645,7 @@
         goto Exit;
     }
 
-    if (mEffectsFactoryHal.get() == NULL) {
+    if (mEffectsFactoryHal == 0) {
         lStatus = NO_INIT;
         goto Exit;
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1890c94..bf8aaf7 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -58,6 +58,7 @@
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
 #include "LinearMap.h"
+#include "StreamHalInterface.h"
 
 #include <powermanager/IPowerManager.h>
 
@@ -615,12 +616,12 @@
 
     struct AudioStreamIn {
         AudioHwDevice* const audioHwDev;
-        audio_stream_in_t* const stream;
+        sp<StreamInHalInterface> stream;
         audio_input_flags_t flags;
 
         sp<DeviceHalInterface> hwDev() const { return audioHwDev->hwDevice(); }
 
-        AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in, audio_input_flags_t flags) :
+        AudioStreamIn(AudioHwDevice *dev, sp<StreamInHalInterface> in, audio_input_flags_t flags) :
             audioHwDev(dev), stream(in), flags(flags) {}
     };
 
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index 4839480..5a07b7f 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -24,9 +24,8 @@
 #include "AudioHwDevice.h"
 #include "AudioStreamOut.h"
 #include "DeviceHalInterface.h"
+#include "StreamHalInterface.h"
 
-// FIXME: Remove after streams HAL is componentized
-#include "DeviceHalLocal.h"
 
 namespace android {
 
@@ -44,6 +43,10 @@
 {
 }
 
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
 sp<DeviceHalInterface> AudioStreamOut::hwDev() const
 {
     return audioHwDev->hwDevice();
@@ -51,12 +54,12 @@
 
 status_t AudioStreamOut::getRenderPosition(uint64_t *frames)
 {
-    if (stream == NULL) {
+    if (stream == 0) {
         return NO_INIT;
     }
 
     uint32_t halPosition = 0;
-    status_t status = stream->get_render_position(stream, &halPosition);
+    status_t status = stream->getRenderPosition(&halPosition);
     if (status != NO_ERROR) {
         return status;
     }
@@ -88,12 +91,12 @@
 
 status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp)
 {
-    if (stream == NULL) {
+    if (stream == 0) {
         return NO_INIT;
     }
 
     uint64_t halPosition = 0;
-    status_t status = stream->get_presentation_position(stream, &halPosition, timestamp);
+    status_t status = stream->getPresentationPosition(&halPosition, timestamp);
     if (status != NO_ERROR) {
         return status;
     }
@@ -119,13 +122,13 @@
         struct audio_config *config,
         const char *address)
 {
-    audio_stream_out_t *outStream;
+    sp<StreamOutHalInterface> outStream;
 
     audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
                 ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
                 : flags;
 
-    int status = static_cast<DeviceHalLocal*>(hwDev().get())->openOutputStream(
+    int status = hwDev()->openOutputStream(
             handle,
             devices,
             customFlags,
@@ -135,7 +138,7 @@
     ALOGV("AudioStreamOut::open(), HAL returned "
             " stream %p, sampleRate %d, Format %#x, "
             "channelMask %#x, status %d",
-            outStream,
+            outStream.get(),
             config->sample_rate,
             config->format,
             config->channel_mask,
@@ -147,7 +150,7 @@
         struct audio_config customConfig = *config;
         customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
 
-        status = static_cast<DeviceHalLocal*>(hwDev().get())->openOutputStream(
+        status = hwDev()->openOutputStream(
                 handle,
                 devices,
                 customFlags,
@@ -160,7 +163,7 @@
     if (status == NO_ERROR) {
         stream = outStream;
         mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
-        mHalFrameSize = audio_stream_out_frame_size(stream);
+        status = stream->getFrameSize(&mHalFrameSize);
     }
 
     return status;
@@ -168,47 +171,46 @@
 
 audio_format_t AudioStreamOut::getFormat() const
 {
-    return stream->common.get_format(&stream->common);
+    audio_format_t result;
+    return stream->getFormat(&result) == OK ? result : AUDIO_FORMAT_INVALID;
 }
 
 uint32_t AudioStreamOut::getSampleRate() const
 {
-    return stream->common.get_sample_rate(&stream->common);
+    uint32_t result;
+    return stream->getSampleRate(&result) == OK ? result : 0;
 }
 
 audio_channel_mask_t AudioStreamOut::getChannelMask() const
 {
-    return stream->common.get_channels(&stream->common);
+    audio_channel_mask_t result;
+    return stream->getChannelMask(&result) == OK ? result : AUDIO_CHANNEL_INVALID;
 }
 
 int AudioStreamOut::flush()
 {
-    ALOG_ASSERT(stream != NULL);
     mRenderPosition = 0;
     mFramesWritten = 0;
     mFramesWrittenAtStandby = 0;
-    if (stream->flush != NULL) {
-        return stream->flush(stream);
-    }
-    return NO_ERROR;
+    status_t result = stream->flush();
+    return result != INVALID_OPERATION ? result : NO_ERROR;
 }
 
 int AudioStreamOut::standby()
 {
-    ALOG_ASSERT(stream != NULL);
     mRenderPosition = 0;
     mFramesWrittenAtStandby = mFramesWritten;
-    return stream->common.standby(&stream->common);
+    return stream->standby();
 }
 
 ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes)
 {
-    ALOG_ASSERT(stream != NULL);
-    ssize_t bytesWritten = stream->write(stream, buffer, numBytes);
-    if (bytesWritten > 0 && mHalFrameSize > 0) {
+    size_t bytesWritten;
+    status_t result = stream->write(buffer, numBytes, &bytesWritten);
+    if (result == OK && bytesWritten > 0 && mHalFrameSize > 0) {
         mFramesWritten += bytesWritten / mHalFrameSize;
     }
-    return bytesWritten;
+    return result == OK ? bytesWritten : result;
 }
 
 } // namespace android
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index d132f6f..b16b1af 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -27,6 +27,7 @@
 
 class AudioHwDevice;
 class DeviceHalInterface;
+class StreamOutHalInterface;
 
 /**
  * Managed access to a HAL output stream.
@@ -37,7 +38,7 @@
 // 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;
+    sp<StreamOutHalInterface> stream;
     const audio_output_flags_t flags;
 
     sp<DeviceHalInterface> hwDev() const;
@@ -50,7 +51,7 @@
             struct audio_config *config,
             const char *address);
 
-    virtual ~AudioStreamOut() { }
+    virtual ~AudioStreamOut();
 
     // Get the bottom 32-bits of the 64-bit render position.
     status_t getRenderPosition(uint32_t *frames);
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index c1ff1af..204fa17 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -151,7 +151,7 @@
         return;
     }
     mEffectsFactory = EffectsFactoryHalInterface::create();
-    if (mEffectsFactory.get() == NULL) {
+    if (mEffectsFactory == 0) {
         ALOGE("DownmixerBufferProvider() error: could not obtain the effects factory");
         return;
     }
@@ -257,7 +257,7 @@
 {
     // find multichannel downmix effect if we have to play multichannel content
     sp<EffectsFactoryHalInterface> effectsFactory = EffectsFactoryHalInterface::create();
-    if (effectsFactory.get() == NULL) {
+    if (effectsFactory == 0) {
         ALOGE("AudioMixer() error: could not obtain the effects factory");
         return NO_INIT;
     }
diff --git a/services/audioflinger/DeviceHalInterface.h b/services/audioflinger/DeviceHalInterface.h
index ea682f0..b5767ef 100644
--- a/services/audioflinger/DeviceHalInterface.h
+++ b/services/audioflinger/DeviceHalInterface.h
@@ -24,12 +24,12 @@
 
 namespace android {
 
+class StreamInHalInterface;
+class StreamOutHalInterface;
+
 class DeviceHalInterface : public RefBase
 {
   public:
-    // The destructor automatically closes the device.
-    virtual ~DeviceHalInterface() {}
-
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
     virtual status_t getSupportedDevices(uint32_t *devices) = 0;
 
@@ -69,26 +69,24 @@
 
     // Creates and opens the audio hardware output stream. The stream is closed
     // by releasing all references to the returned object.
-    // FIXME: Enable when StreamOutHalInterface is introduced.
-    // virtual status_t openOutputStream(
-    //         audio_io_handle_t handle,
-    //         audio_devices_t devices,
-    //         audio_output_flags_t flags,
-    //         struct audio_config *config,
-    //         const char *address,
-    //         sp<StreamOutHalInterface> *outStream) = 0;
+    virtual status_t openOutputStream(
+            audio_io_handle_t handle,
+            audio_devices_t devices,
+            audio_output_flags_t flags,
+            struct audio_config *config,
+            const char *address,
+            sp<StreamOutHalInterface> *outStream) = 0;
 
     // Creates and opens the audio hardware input stream. The stream is closed
     // by releasing all references to the returned object.
-    // FIXME: Enable when StreamInHalInterface is introduced.
-    // virtual status_t openInputStream(
-    //         audio_io_handle_t handle,
-    //         audio_devices_t devices,
-    //         struct audio_config *config,
-    //         audio_input_flags_t flags,
-    //         const char *address,
-    //         audio_source_t source,
-    //         sp<StreamInHalInterface> *inStream) = 0;
+    virtual status_t openInputStream(
+            audio_io_handle_t handle,
+            audio_devices_t devices,
+            struct audio_config *config,
+            audio_input_flags_t flags,
+            const char *address,
+            audio_source_t source,
+            sp<StreamInHalInterface> *inStream) = 0;
 
     // Creates an audio patch between several source and sink ports.
     virtual status_t createAudioPatch(
@@ -112,6 +110,9 @@
   protected:
     // Subclasses can not be constructed directly by clients.
     DeviceHalInterface() {}
+
+    // The destructor automatically closes the device.
+    virtual ~DeviceHalInterface() {}
 };
 
 } // namespace android
diff --git a/services/audioflinger/DeviceHalLocal.cpp b/services/audioflinger/DeviceHalLocal.cpp
index b602f16..160eb4a 100644
--- a/services/audioflinger/DeviceHalLocal.cpp
+++ b/services/audioflinger/DeviceHalLocal.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 
 #include "DeviceHalLocal.h"
+#include "StreamHalLocal.h"
 
 namespace android {
 
@@ -89,10 +90,10 @@
 }
 
 status_t DeviceHalLocal::getParameters(const String8& keys, String8 *values) {
-    char *c_values = mDev->get_parameters(mDev, keys.string());
-    if (c_values != NULL) {
-        values->setTo(c_values);
-        free(c_values);
+    char *halValues = mDev->get_parameters(mDev, keys.string());
+    if (halValues != NULL) {
+        values->setTo(halValues);
+        free(halValues);
     } else {
         values->clear();
     }
@@ -105,6 +106,39 @@
     return OK;
 }
 
+status_t DeviceHalLocal::openOutputStream(
+        audio_io_handle_t handle,
+        audio_devices_t devices,
+        audio_output_flags_t flags,
+        struct audio_config *config,
+        const char *address,
+        sp<StreamOutHalInterface> *outStream) {
+    audio_stream_out_t *halStream;
+    int openResut = mDev->open_output_stream(
+            mDev, handle, devices, flags, config, &halStream, address);
+    if (openResut == OK) {
+        *outStream = new StreamOutHalLocal(halStream, this);
+    }
+    return openResut;
+}
+
+status_t DeviceHalLocal::openInputStream(
+        audio_io_handle_t handle,
+        audio_devices_t devices,
+        struct audio_config *config,
+        audio_input_flags_t flags,
+        const char *address,
+        audio_source_t source,
+        sp<StreamInHalInterface> *inStream) {
+    audio_stream_in_t *halStream;
+    int openResult = mDev->open_input_stream(
+            mDev, handle, devices, config, &halStream, flags, address, source);
+    if (openResult == OK) {
+        *inStream = new StreamInHalLocal(halStream, this);
+    }
+    return openResult;
+}
+
 status_t DeviceHalLocal::createAudioPatch(
         unsigned int num_sources,
         const struct audio_port_config *sources,
@@ -130,36 +164,12 @@
     return mDev->dump(mDev, fd);
 }
 
-status_t DeviceHalLocal::openOutputStream(
-        audio_io_handle_t handle,
-        audio_devices_t devices,
-        audio_output_flags_t flags,
-        struct audio_config *config,
-        const char *address,
-        struct audio_stream_out **stream_out) {
-    return mDev->open_output_stream(mDev, handle, devices, flags, config, stream_out, address);
-}
-
-status_t DeviceHalLocal::closeOutputStream(struct audio_stream_out *stream_out) {
+void DeviceHalLocal::closeOutputStream(struct audio_stream_out *stream_out) {
     mDev->close_output_stream(mDev, stream_out);
-    return OK;
 }
 
-status_t DeviceHalLocal::openInputStream(
-        audio_io_handle_t handle,
-        audio_devices_t devices,
-        struct audio_config *config,
-        audio_input_flags_t flags,
-        const char *address,
-        audio_source_t source,
-        struct audio_stream_in **stream_in) {
-    return mDev->open_input_stream(
-            mDev, handle, devices, config, stream_in, flags, address, source);
-}
-
-status_t DeviceHalLocal::closeInputStream(struct audio_stream_in *stream_in) {
+void DeviceHalLocal::closeInputStream(struct audio_stream_in *stream_in) {
     mDev->close_input_stream(mDev, stream_in);
-    return OK;
 }
 
 } // namespace android
diff --git a/services/audioflinger/DeviceHalLocal.h b/services/audioflinger/DeviceHalLocal.h
index cc53e9c..1f808cf 100644
--- a/services/audioflinger/DeviceHalLocal.h
+++ b/services/audioflinger/DeviceHalLocal.h
@@ -24,9 +24,6 @@
 class DeviceHalLocal : public DeviceHalInterface
 {
   public:
-    // The destructor automatically closes the device.
-    virtual ~DeviceHalLocal();
-
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
     virtual status_t getSupportedDevices(uint32_t *devices);
 
@@ -66,26 +63,24 @@
 
     // Creates and opens the audio hardware output stream. The stream is closed
     // by releasing all references to the returned object.
-    // FIXME: Enable when StreamOutHalInterface is introduced.
-    // virtual status_t openOutputStream(
-    //         audio_io_handle_t handle,
-    //         audio_devices_t devices,
-    //         audio_output_flags_t flags,
-    //         struct audio_config *config,
-    //         const char *address,
-    //         sp<StreamOutHalInterface> *outStream);
+    virtual status_t openOutputStream(
+            audio_io_handle_t handle,
+            audio_devices_t devices,
+            audio_output_flags_t flags,
+            struct audio_config *config,
+            const char *address,
+            sp<StreamOutHalInterface> *outStream);
 
     // Creates and opens the audio hardware input stream. The stream is closed
     // by releasing all references to the returned object.
-    // FIXME: Enable when StreamInHalInterface is introduced.
-    // virtual status_t openInputStream(
-    //         audio_io_handle_t handle,
-    //         audio_devices_t devices,
-    //         struct audio_config *config,
-    //         audio_input_flags_t flags,
-    //         const char *address,
-    //         audio_source_t source,
-    //         sp<StreamInHalInterface> *inStream);
+    virtual status_t openInputStream(
+            audio_io_handle_t handle,
+            audio_devices_t devices,
+            struct audio_config *config,
+            audio_input_flags_t flags,
+            const char *address,
+            audio_source_t source,
+            sp<StreamInHalInterface> *inStream);
 
     // Creates an audio patch between several source and sink ports.
     virtual status_t createAudioPatch(
@@ -106,30 +101,8 @@
 
     virtual status_t dump(int fd);
 
-    // FIXME: Remove when StreamOutHalInterface is introduced.
-    status_t openOutputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            audio_output_flags_t flags,
-            struct audio_config *config,
-            const char *address,
-            struct audio_stream_out **stream_out);
-
-    // FIXME: Remove when StreamOutHalInterface is introduced.
-    status_t closeOutputStream(struct audio_stream_out *stream_out);
-
-    // FIXME: Remove when StreamInHalInterface is introduced.
-    status_t openInputStream(
-            audio_io_handle_t handle,
-            audio_devices_t devices,
-            struct audio_config *config,
-            audio_input_flags_t flags,
-            const char *address,
-            audio_source_t source,
-            struct audio_stream_in **stream_in);
-
-    // FIXME: Remove when StreamInHalInterface is introduced.
-    status_t closeInputStream(struct audio_stream_in *stream_in);
+    void closeOutputStream(struct audio_stream_out *stream_out);
+    void closeInputStream(struct audio_stream_in *stream_in);
 
   private:
     audio_hw_device_t *mDev;
@@ -138,6 +111,9 @@
 
     // Can not be constructed directly by clients.
     explicit DeviceHalLocal(audio_hw_device_t *dev);
+
+    // The destructor automatically closes the device.
+    virtual ~DeviceHalLocal();
 };
 
 } // namespace android
diff --git a/services/audioflinger/EffectHalInterface.h b/services/audioflinger/EffectHalInterface.h
index e774520..4bde112 100644
--- a/services/audioflinger/EffectHalInterface.h
+++ b/services/audioflinger/EffectHalInterface.h
@@ -26,9 +26,6 @@
 class EffectHalInterface : public RefBase
 {
   public:
-    // The destructor automatically releases the effect.
-    virtual ~EffectHalInterface() {}
-
     // Effect process function. Takes input samples as specified
     // in input buffer descriptor and output processed samples as specified
     // in output buffer descriptor.
@@ -48,6 +45,9 @@
   protected:
     // Subclasses can not be constructed directly by clients.
     EffectHalInterface() {}
+
+    // The destructor automatically releases the effect.
+    virtual ~EffectHalInterface() {}
 };
 
 } // namespace android
diff --git a/services/audioflinger/EffectHalLocal.h b/services/audioflinger/EffectHalLocal.h
index 92b2153..73ba6d5 100644
--- a/services/audioflinger/EffectHalLocal.h
+++ b/services/audioflinger/EffectHalLocal.h
@@ -24,9 +24,6 @@
 class EffectHalLocal : public EffectHalInterface
 {
   public:
-    // The destructor automatically releases the effect.
-    virtual ~EffectHalLocal();
-
     // Effect process function. Takes input samples as specified
     // in input buffer descriptor and output processed samples as specified
     // in output buffer descriptor.
@@ -43,7 +40,6 @@
     // Returns the effect descriptor.
     virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
 
-    // FIXME: Remove after converting the main audio HAL
     effect_handle_t handle() const { return mHandle; }
 
   private:
@@ -53,6 +49,9 @@
 
     // Can not be constructed directly by clients.
     explicit EffectHalLocal(effect_handle_t handle);
+
+    // The destructor automatically releases the effect.
+    virtual ~EffectHalLocal();
 };
 
 } // namespace android
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 25c1dbb..d4035d6 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -28,8 +28,6 @@
 
 #include "AudioFlinger.h"
 #include "EffectHalInterface.h"
-// FIXME: Remove after converting the main audio HAL
-#include "EffectHalLocal.h"
 #include "EffectsFactoryHalInterface.h"
 #include "ServiceUtilities.h"
 
@@ -80,9 +78,9 @@
     // create effect engine from effect factory
     mStatus = -ENODEV;
     sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
-    if (audioFlinger.get() != NULL) {
+    if (audioFlinger != 0) {
         sp<EffectsFactoryHalInterface> effectsFactory = audioFlinger->getEffectsFactory();
-        if (effectsFactory.get() != NULL) {
+        if (effectsFactory != 0) {
             mStatus = effectsFactory->createEffect(
                     &desc->uuid, sessionId, thread->id(), &mEffectInterface);
         }
@@ -107,7 +105,7 @@
 AudioFlinger::EffectModule::~EffectModule()
 {
     ALOGV("Destructor %p", this);
-    if (mEffectInterface.get() != NULL) {
+    if (mEffectInterface != 0) {
         remove_effect_from_hal_l();
         // release effect engine
         mEffectInterface.clear();
@@ -276,7 +274,7 @@
 {
     Mutex::Autolock _l(mLock);
 
-    if (mState == DESTROYED || mEffectInterface.get() == NULL ||
+    if (mState == DESTROYED || mEffectInterface == 0 ||
             mConfig.inputCfg.buffer.raw == NULL ||
             mConfig.outputCfg.buffer.raw == NULL) {
         return;
@@ -338,7 +336,7 @@
 
 void AudioFlinger::EffectModule::reset_l()
 {
-    if (mStatus != NO_ERROR || mEffectInterface.get() == NULL) {
+    if (mStatus != NO_ERROR || mEffectInterface == 0) {
         return;
     }
     mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, 0, NULL);
@@ -351,7 +349,7 @@
     uint32_t size;
     audio_channel_mask_t channelMask;
 
-    if (mEffectInterface.get() == NULL) {
+    if (mEffectInterface == 0) {
         status = NO_INIT;
         goto exit;
     }
@@ -458,7 +456,7 @@
 status_t AudioFlinger::EffectModule::init()
 {
     Mutex::Autolock _l(mLock);
-    if (mEffectInterface.get() == NULL) {
+    if (mEffectInterface == 0) {
         return NO_INIT;
     }
     status_t cmdStatus;
@@ -480,10 +478,10 @@
          (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            audio_stream_t *stream = thread->stream();
-            if (stream != NULL) {
-                stream->add_audio_effect(stream,
-                        static_cast<EffectHalLocal*>(mEffectInterface.get())->handle());
+            sp<StreamHalInterface> stream = thread->stream();
+            if (stream != 0) {
+                status_t result = stream->addEffect(mEffectInterface);
+                ALOGE_IF(result != OK, "Error when adding effect: %d", result);
             }
         }
     }
@@ -509,7 +507,7 @@
 
 status_t AudioFlinger::EffectModule::start_l()
 {
-    if (mEffectInterface.get() == NULL) {
+    if (mEffectInterface == 0) {
         return NO_INIT;
     }
     if (mStatus != NO_ERROR) {
@@ -539,7 +537,7 @@
 
 status_t AudioFlinger::EffectModule::stop_l()
 {
-    if (mEffectInterface.get() == NULL) {
+    if (mEffectInterface == 0) {
         return NO_INIT;
     }
     if (mStatus != NO_ERROR) {
@@ -567,10 +565,10 @@
              (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            audio_stream_t *stream = thread->stream();
-            if (stream != NULL) {
-                stream->remove_audio_effect(stream,
-                        static_cast<EffectHalLocal*>(mEffectInterface.get())->handle());
+            sp<StreamHalInterface> stream = thread->stream();
+            if (stream != 0) {
+                status_t result = stream->removeEffect(mEffectInterface);
+                ALOGE_IF(result != OK, "Error when removing effect: %d", result);
             }
         }
     }
@@ -593,7 +591,7 @@
     Mutex::Autolock _l(mLock);
     ALOGVV("command(), cmdCode: %d, mEffectInterface: %p", cmdCode, mEffectInterface.get());
 
-    if (mState == DESTROYED || mEffectInterface.get() == NULL) {
+    if (mState == DESTROYED || mEffectInterface == 0) {
         return NO_INIT;
     }
     if (mStatus != NO_ERROR) {
diff --git a/services/audioflinger/EffectsFactoryHalInterface.h b/services/audioflinger/EffectsFactoryHalInterface.h
index a865dd1..9a08f68 100644
--- a/services/audioflinger/EffectsFactoryHalInterface.h
+++ b/services/audioflinger/EffectsFactoryHalInterface.h
@@ -28,8 +28,6 @@
 class EffectsFactoryHalInterface : public RefBase
 {
   public:
-    virtual ~EffectsFactoryHalInterface() {}
-
     // Returns the number of different effects in all loaded libraries.
     virtual status_t queryNumberEffects(uint32_t *pNumEffects) = 0;
 
@@ -57,6 +55,8 @@
   protected:
     // Subclasses can not be constructed directly by clients.
     EffectsFactoryHalInterface() {}
+
+    virtual ~EffectsFactoryHalInterface() {}
 };
 
 } // namespace android
diff --git a/services/audioflinger/EffectsFactoryHalLocal.h b/services/audioflinger/EffectsFactoryHalLocal.h
index 244176a..9f6b5ce 100644
--- a/services/audioflinger/EffectsFactoryHalLocal.h
+++ b/services/audioflinger/EffectsFactoryHalLocal.h
@@ -24,8 +24,6 @@
 class EffectsFactoryHalLocal : public EffectsFactoryHalInterface
 {
   public:
-    virtual ~EffectsFactoryHalLocal() {}
-
     // Returns the number of different effects in all loaded libraries.
     virtual status_t queryNumberEffects(uint32_t *pNumEffects);
 
@@ -50,6 +48,8 @@
 
     // Can not be constructed directly by clients.
     EffectsFactoryHalLocal() {}
+
+    virtual ~EffectsFactoryHalLocal() {}
 };
 
 } // namespace android
diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp
index 004a068..b9260f8 100644
--- a/services/audioflinger/SpdifStreamOut.cpp
+++ b/services/audioflinger/SpdifStreamOut.cpp
@@ -23,7 +23,6 @@
 #include <audio_utils/spdif/SPDIFEncoder.h>
 
 #include "AudioHwDevice.h"
-#include "AudioStreamOut.h"
 #include "SpdifStreamOut.h"
 
 namespace android {
diff --git a/services/audioflinger/SpdifStreamOut.h b/services/audioflinger/SpdifStreamOut.h
index 801c1f0..fc9bb6e 100644
--- a/services/audioflinger/SpdifStreamOut.h
+++ b/services/audioflinger/SpdifStreamOut.h
@@ -23,7 +23,6 @@
 
 #include <system/audio.h>
 
-#include "AudioHwDevice.h"
 #include "AudioStreamOut.h"
 
 #include <audio_utils/spdif/SPDIFEncoder.h>
diff --git a/services/audioflinger/StreamHalInterface.h b/services/audioflinger/StreamHalInterface.h
new file mode 100644
index 0000000..0339069
--- /dev/null
+++ b/services/audioflinger/StreamHalInterface.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 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_HARDWARE_STREAM_HAL_INTERFACE_H
+#define ANDROID_HARDWARE_STREAM_HAL_INTERFACE_H
+
+#include <hardware/audio_effect.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include "EffectHalInterface.h"
+
+namespace android {
+
+class StreamHalInterface : public virtual RefBase
+{
+  public:
+    // Return the sampling rate in Hz - eg. 44100.
+    virtual status_t getSampleRate(uint32_t *rate) = 0;
+
+    // Return size of input/output buffer in bytes for this stream - eg. 4800.
+    virtual status_t getBufferSize(size_t *size) = 0;
+
+    // Return the channel mask.
+    virtual status_t getChannelMask(audio_channel_mask_t *mask) = 0;
+
+    // Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT.
+    virtual status_t getFormat(audio_format_t *format) = 0;
+
+    // Convenience method.
+    virtual status_t getAudioProperties(
+            uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) = 0;
+
+    // Set audio stream parameters.
+    virtual status_t setParameters(const String8& kvPairs) = 0;
+
+    // Get audio stream parameters.
+    virtual status_t getParameters(const String8& keys, String8 *values) = 0;
+
+    // Return the frame size (number of bytes per sample) of a stream.
+    virtual status_t getFrameSize(size_t *size) = 0;
+
+    // Add or remove the effect on the stream.
+    virtual status_t addEffect(sp<EffectHalInterface> effect) = 0;
+    virtual status_t removeEffect(sp<EffectHalInterface> effect) = 0;
+
+    // Put the audio hardware input/output into standby mode.
+    virtual status_t standby() = 0;
+
+    virtual status_t dump(int fd) = 0;
+
+  protected:
+    // Subclasses can not be constructed directly by clients.
+    StreamHalInterface() {}
+
+    // The destructor automatically closes the stream.
+    virtual ~StreamHalInterface() {}
+};
+
+class StreamOutHalInterfaceCallback : public virtual RefBase {
+  public:
+    virtual void onWriteReady() {}
+    virtual void onDrainReady() {}
+    virtual void onError() {}
+
+  protected:
+    StreamOutHalInterfaceCallback() {}
+    virtual ~StreamOutHalInterfaceCallback() {}
+};
+
+class StreamOutHalInterface : public virtual StreamHalInterface {
+  public:
+    // Return the audio hardware driver estimated latency in milliseconds.
+    virtual status_t getLatency(uint32_t *latency) = 0;
+
+    // Use this method in situations where audio mixing is done in the hardware.
+    virtual status_t setVolume(float left, float right) = 0;
+
+    // Write audio buffer to driver.
+    virtual status_t write(const void *buffer, size_t bytes, size_t *written) = 0;
+
+    // Return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby.
+    virtual status_t getRenderPosition(uint32_t *dspFrames) = 0;
+
+    // Get the local time at which the next write to the audio driver will be presented.
+    virtual status_t getNextWriteTimestamp(int64_t *timestamp) = 0;
+
+    // Set the callback for notifying completion of non-blocking write and drain.
+    // The callback must be owned by someone else. The output stream does not own it
+    // to avoid strong pointer loops.
+    virtual status_t setCallback(sp<StreamOutHalInterfaceCallback> callback) = 0;
+
+    // Returns whether pause and resume operations are supported.
+    virtual status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume) = 0;
+
+    // Notifies to the audio driver to resume playback following a pause.
+    virtual status_t pause() = 0;
+
+    // Notifies to the audio driver to resume playback following a pause.
+    virtual status_t resume() = 0;
+
+    // Returns whether drain operation is supported.
+    virtual status_t supportsDrain(bool *supportsDrain) = 0;
+
+    // Requests notification when data buffered by the driver/hardware has been played.
+    virtual status_t drain(audio_drain_type_t type) = 0;
+
+    // Notifies to the audio driver to flush the queued data.
+    virtual status_t flush() = 0;
+
+    // Return a recent count of the number of audio frames presented to an external observer.
+    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp) = 0;
+
+  protected:
+    virtual ~StreamOutHalInterface() {}
+};
+
+class StreamInHalInterface : public virtual StreamHalInterface {
+  public:
+    // Set the input gain for the audio driver.
+    virtual status_t setGain(float gain) = 0;
+
+    // Read audio buffer in from driver.
+    virtual status_t read(void *buffer, size_t bytes, size_t *read) = 0;
+
+    // Return the amount of input frames lost in the audio driver.
+    virtual status_t getInputFramesLost(uint32_t *framesLost) = 0;
+
+    // Return a recent count of the number of audio frames received and
+    // the clock time associated with that frame count.
+    virtual status_t getCapturePosition(int64_t *frames, int64_t *time) = 0;
+
+  protected:
+    virtual ~StreamInHalInterface() {}
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_STREAM_HAL_INTERFACE_H
diff --git a/services/audioflinger/StreamHalLocal.cpp b/services/audioflinger/StreamHalLocal.cpp
new file mode 100644
index 0000000..cdd714b
--- /dev/null
+++ b/services/audioflinger/StreamHalLocal.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 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::StreamHalLocal"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "DeviceHalLocal.h"
+#include "EffectHalLocal.h"
+#include "StreamHalLocal.h"
+
+namespace android {
+
+StreamHalLocal::StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device)
+        : mDevice(device), mStream(stream) {
+}
+
+StreamHalLocal::~StreamHalLocal() {
+    mStream = 0;
+    mDevice.clear();
+}
+
+status_t StreamHalLocal::getSampleRate(uint32_t *rate) {
+    *rate = mStream->get_sample_rate(mStream);
+    return OK;
+}
+
+status_t StreamHalLocal::getBufferSize(size_t *size) {
+    *size = mStream->get_buffer_size(mStream);
+    return OK;
+}
+
+status_t StreamHalLocal::getChannelMask(audio_channel_mask_t *mask) {
+    *mask = mStream->get_channels(mStream);
+    return OK;
+}
+
+status_t StreamHalLocal::getFormat(audio_format_t *format) {
+    *format = mStream->get_format(mStream);
+    return OK;
+}
+
+status_t StreamHalLocal::getAudioProperties(
+        uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) {
+    *sampleRate = mStream->get_sample_rate(mStream);
+    *mask = mStream->get_channels(mStream);
+    *format = mStream->get_format(mStream);
+    return OK;
+}
+
+status_t StreamHalLocal::setParameters(const String8& kvPairs) {
+    return mStream->set_parameters(mStream, kvPairs.string());
+}
+
+status_t StreamHalLocal::getParameters(const String8& keys, String8 *values) {
+    char *halValues = mStream->get_parameters(mStream, keys.string());
+    if (halValues != NULL) {
+        values->setTo(halValues);
+        free(halValues);
+    } else {
+        values->clear();
+    }
+    return OK;
+}
+
+status_t StreamHalLocal::addEffect(sp<EffectHalInterface> effect) {
+    return mStream->add_audio_effect(mStream,
+            static_cast<EffectHalLocal*>(effect.get())->handle());
+}
+
+status_t StreamHalLocal::removeEffect(sp<EffectHalInterface> effect) {
+    return mStream->remove_audio_effect(mStream,
+            static_cast<EffectHalLocal*>(effect.get())->handle());
+}
+
+status_t StreamHalLocal::standby() {
+    return mStream->standby(mStream);
+}
+
+status_t StreamHalLocal::dump(int fd) {
+    return mStream->dump(mStream, fd);
+}
+
+StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device)
+        : StreamHalLocal(&stream->common, device), mStream(stream) {
+}
+
+StreamOutHalLocal::~StreamOutHalLocal() {
+    mCallback.clear();
+    mDevice->closeOutputStream(mStream);
+    mStream = 0;
+}
+
+status_t StreamOutHalLocal::getFrameSize(size_t *size) {
+    *size = audio_stream_out_frame_size(mStream);
+    return OK;
+}
+
+status_t StreamOutHalLocal::getLatency(uint32_t *latency) {
+    *latency = mStream->get_latency(mStream);
+    return OK;
+}
+
+status_t StreamOutHalLocal::setVolume(float left, float right) {
+    if (mStream->set_volume == NULL) return INVALID_OPERATION;
+    return mStream->set_volume(mStream, left, right);
+}
+
+status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
+    ssize_t writeResult = mStream->write(mStream, buffer, bytes);
+    if (writeResult > 0) {
+        *written = writeResult;
+        return OK;
+    } else {
+        *written = 0;
+        return writeResult;
+    }
+}
+
+status_t StreamOutHalLocal::getRenderPosition(uint32_t *dspFrames) {
+    return mStream->get_render_position(mStream, dspFrames);
+}
+
+status_t StreamOutHalLocal::getNextWriteTimestamp(int64_t *timestamp) {
+    if (mStream->get_next_write_timestamp == NULL) return INVALID_OPERATION;
+    return mStream->get_next_write_timestamp(mStream, timestamp);
+}
+
+status_t StreamOutHalLocal::setCallback(sp<StreamOutHalInterfaceCallback> callback) {
+    if (mStream->set_callback == NULL) return INVALID_OPERATION;
+    status_t result = mStream->set_callback(mStream, StreamOutHalLocal::asyncCallback, this);
+    if (result == OK) {
+        mCallback = callback;
+    }
+    return result;
+}
+
+// static
+int StreamOutHalLocal::asyncCallback(stream_callback_event_t event, void*, void *cookie) {
+    // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
+    // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
+    // already running, because the destructor is invoked after the refcount has been atomically
+    // decremented.
+    wp<StreamOutHalLocal> weakSelf(reinterpret_cast<StreamOutHalLocal*>(cookie));
+    sp<StreamOutHalLocal> self = weakSelf.promote();
+    if (self == 0) return 0;
+    sp<StreamOutHalInterfaceCallback> callback = self->mCallback.promote();
+    if (callback == 0) return 0;
+    ALOGV("asyncCallback() event %d", event);
+    switch (event) {
+        case STREAM_CBK_EVENT_WRITE_READY:
+            callback->onWriteReady();
+            break;
+        case STREAM_CBK_EVENT_DRAIN_READY:
+            callback->onDrainReady();
+            break;
+        case STREAM_CBK_EVENT_ERROR:
+            callback->onError();
+            break;
+        default:
+            ALOGW("asyncCallback() unknown event %d", event);
+            break;
+    }
+    return 0;
+}
+
+status_t StreamOutHalLocal::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
+    *supportsPause = mStream->pause != NULL;
+    *supportsResume = mStream->resume != NULL;
+    return OK;
+}
+
+status_t StreamOutHalLocal::pause() {
+    if (mStream->pause == NULL) return INVALID_OPERATION;
+    return mStream->pause(mStream);
+}
+
+status_t StreamOutHalLocal::resume() {
+    if (mStream->resume == NULL) return INVALID_OPERATION;
+    return mStream->resume(mStream);
+}
+
+status_t StreamOutHalLocal::supportsDrain(bool *supportsDrain) {
+    *supportsDrain = mStream->drain != NULL;
+    return OK;
+}
+
+status_t StreamOutHalLocal::drain(audio_drain_type_t type) {
+    if (mStream->drain == NULL) return INVALID_OPERATION;
+    return mStream->drain(mStream, type);
+}
+
+status_t StreamOutHalLocal::flush() {
+    if (mStream->flush == NULL) return INVALID_OPERATION;
+    return mStream->flush(mStream);
+}
+
+status_t StreamOutHalLocal::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
+    if (mStream->get_presentation_position == NULL) return INVALID_OPERATION;
+    return mStream->get_presentation_position(mStream, frames, timestamp);
+}
+
+
+StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
+        : StreamHalLocal(&stream->common, device), mStream(stream) {
+}
+
+StreamInHalLocal::~StreamInHalLocal() {
+    mDevice->closeInputStream(mStream);
+    mStream = 0;
+}
+
+status_t StreamInHalLocal::getFrameSize(size_t *size) {
+    *size = audio_stream_in_frame_size(mStream);
+    return OK;
+}
+
+status_t StreamInHalLocal::setGain(float gain) {
+    return mStream->set_gain(mStream, gain);
+}
+
+status_t StreamInHalLocal::read(void *buffer, size_t bytes, size_t *read) {
+    ssize_t readResult = mStream->read(mStream, buffer, bytes);
+    if (readResult > 0) {
+        *read = readResult;
+        return OK;
+    } else {
+        *read = 0;
+        return readResult;
+    }
+}
+
+status_t StreamInHalLocal::getInputFramesLost(uint32_t *framesLost) {
+    *framesLost = mStream->get_input_frames_lost(mStream);
+    return OK;
+}
+
+status_t StreamInHalLocal::getCapturePosition(int64_t *frames, int64_t *time) {
+    if (mStream->get_capture_position == NULL) return INVALID_OPERATION;
+    return mStream->get_capture_position(mStream, frames, time);
+}
+
+} // namespace android
diff --git a/services/audioflinger/StreamHalLocal.h b/services/audioflinger/StreamHalLocal.h
new file mode 100644
index 0000000..d8c30d3
--- /dev/null
+++ b/services/audioflinger/StreamHalLocal.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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_HARDWARE_STREAM_HAL_LOCAL_H
+#define ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
+
+#include "StreamHalInterface.h"
+
+namespace android {
+
+class DeviceHalLocal;
+
+class StreamHalLocal : public virtual StreamHalInterface
+{
+  public:
+    // Return the sampling rate in Hz - eg. 44100.
+    virtual status_t getSampleRate(uint32_t *rate);
+
+    // Return size of input/output buffer in bytes for this stream - eg. 4800.
+    virtual status_t getBufferSize(size_t *size);
+
+    // Return the channel mask.
+    virtual status_t getChannelMask(audio_channel_mask_t *mask);
+
+    // Return the audio format - e.g. AUDIO_FORMAT_PCM_16_BIT.
+    virtual status_t getFormat(audio_format_t *format);
+
+    // Convenience method.
+    virtual status_t getAudioProperties(
+            uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format);
+
+    // Set audio stream parameters.
+    virtual status_t setParameters(const String8& kvPairs);
+
+    // Get audio stream parameters.
+    virtual status_t getParameters(const String8& keys, String8 *values);
+
+    // Add or remove the effect on the stream.
+    virtual status_t addEffect(sp<EffectHalInterface> effect);
+    virtual status_t removeEffect(sp<EffectHalInterface> effect);
+
+    // Put the audio hardware input/output into standby mode.
+    virtual status_t standby();
+
+    virtual status_t dump(int fd);
+
+  protected:
+    // Subclasses can not be constructed directly by clients.
+    StreamHalLocal(audio_stream_t *stream, sp<DeviceHalLocal> device);
+
+    // The destructor automatically closes the stream.
+    virtual ~StreamHalLocal();
+
+    sp<DeviceHalLocal> mDevice;
+
+  private:
+    audio_stream_t *mStream;
+};
+
+class StreamOutHalLocal : public StreamOutHalInterface, public StreamHalLocal {
+  public:
+    // Return the frame size (number of bytes per sample) of a stream.
+    virtual status_t getFrameSize(size_t *size);
+
+    // Return the audio hardware driver estimated latency in milliseconds.
+    virtual status_t getLatency(uint32_t *latency);
+
+    // Use this method in situations where audio mixing is done in the hardware.
+    virtual status_t setVolume(float left, float right);
+
+    // Write audio buffer to driver.
+    virtual status_t write(const void *buffer, size_t bytes, size_t *written);
+
+    // Return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby.
+    virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+    // Get the local time at which the next write to the audio driver will be presented.
+    virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+
+    // Set the callback for notifying completion of non-blocking write and drain.
+    virtual status_t setCallback(sp<StreamOutHalInterfaceCallback> callback);
+
+    // Returns whether pause and resume operations are supported.
+    virtual status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume);
+
+    // Notifies to the audio driver to resume playback following a pause.
+    virtual status_t pause();
+
+    // Notifies to the audio driver to resume playback following a pause.
+    virtual status_t resume();
+
+    // Returns whether drain operation is supported.
+    virtual status_t supportsDrain(bool *supportsDrain);
+
+    // Requests notification when data buffered by the driver/hardware has been played.
+    virtual status_t drain(audio_drain_type_t type);
+
+    // Notifies to the audio driver to flush the queued data.
+    virtual status_t flush();
+
+    // Return a recent count of the number of audio frames presented to an external observer.
+    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
+
+    // FIXME: Remove after NBAIO is converted.
+    audio_stream_out_t *getStream() const { return mStream; }
+
+  private:
+    audio_stream_out_t *mStream;
+    wp<StreamOutHalInterfaceCallback> mCallback;
+
+    friend class DeviceHalLocal;
+
+    // Can not be constructed directly by clients.
+    StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device);
+
+    virtual ~StreamOutHalLocal();
+
+    static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+};
+
+class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
+  public:
+    // Return the frame size (number of bytes per sample) of a stream.
+    virtual status_t getFrameSize(size_t *size);
+
+    // Set the input gain for the audio driver.
+    virtual status_t setGain(float gain);
+
+    // Read audio buffer in from driver.
+    virtual status_t read(void *buffer, size_t bytes, size_t *read);
+
+    // Return the amount of input frames lost in the audio driver.
+    virtual status_t getInputFramesLost(uint32_t *framesLost);
+
+    // Return a recent count of the number of audio frames received and
+    // the clock time associated with that frame count.
+    virtual status_t getCapturePosition(int64_t *frames, int64_t *time);
+
+    // FIXME: Remove after NBAIO is converted.
+    audio_stream_in_t *getStream() const { return mStream; }
+
+  private:
+    audio_stream_in_t *mStream;
+
+    friend class DeviceHalLocal;
+
+    // Can not be constructed directly by clients.
+    StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device);
+
+    virtual ~StreamInHalLocal();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_STREAM_HAL_LOCAL_H
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 923fcf6..b07c914 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -73,6 +73,9 @@
 
 #include "AutoPark.h"
 
+// FIXME: Remove after NBAIO is converted
+#include "StreamHalLocal.h"
+
 // ----------------------------------------------------------------------------
 
 // Note: the following macro is used for extremely verbose logging message.  In
@@ -1847,7 +1850,8 @@
     ALOGV("  preExit()");
     // FIXME this is using hard-coded strings but in the future, this functionality will be
     //       converted to use audio HAL extensions required to support tunneling
-    mOutput->stream->common.set_parameters(&mOutput->stream->common, "exiting=1");
+    status_t result = mOutput->stream->setParameters(String8("exiting=1"));
+    ALOGE_IF(result != OK, "Error when setting parameters on exit: %d", result);
 }
 
 // PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
@@ -1969,7 +1973,12 @@
             && audio_has_proportional_frames(format) && sharedBuffer == 0) {
         // this must match AudioTrack.cpp calculateMinFrameCount().
         // TODO: Move to a common library
-        uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
+        uint32_t latencyMs = 0;
+        lStatus = mOutput->stream->getLatency(&latencyMs);
+        if (lStatus != OK) {
+            ALOGE("Error when retrieving output stream latency: %d", lStatus);
+            goto Exit;
+        }
         uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
         if (minBufCount < 2) {
             minBufCount = 2;
@@ -2100,11 +2109,11 @@
 }
 uint32_t AudioFlinger::PlaybackThread::latency_l() const
 {
-    if (initCheck() == NO_ERROR) {
-        return correctLatency_l(mOutput->stream->get_latency(mOutput->stream));
-    } else {
-        return 0;
+    uint32_t latency;
+    if (initCheck() == NO_ERROR && mOutput->stream->getLatency(&latency) == OK) {
+        return correctLatency_l(latency);
     }
+    return 0;
 }
 
 void AudioFlinger::PlaybackThread::setMasterVolume(float value)
@@ -2269,14 +2278,11 @@
 String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
 {
     Mutex::Autolock _l(mLock);
-    if (initCheck() != NO_ERROR) {
-        return String8();
+    String8 out_s8;
+    if (initCheck() == NO_ERROR && mOutput->stream->getParameters(keys, &out_s8) == OK) {
+        return out_s8;
     }
-
-    char *s = mOutput->stream->common.get_parameters(&mOutput->stream->common, keys.string());
-    const String8 out_s8(s);
-    free(s);
-    return out_s8;
+    return String8();
 }
 
 void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
@@ -2305,21 +2311,18 @@
     mAudioFlinger->ioConfigChanged(event, desc, pid);
 }
 
-void AudioFlinger::PlaybackThread::writeCallback()
+void AudioFlinger::PlaybackThread::onWriteReady()
 {
-    ALOG_ASSERT(mCallbackThread != 0);
     mCallbackThread->resetWriteBlocked();
 }
 
-void AudioFlinger::PlaybackThread::drainCallback()
+void AudioFlinger::PlaybackThread::onDrainReady()
 {
-    ALOG_ASSERT(mCallbackThread != 0);
     mCallbackThread->resetDraining();
 }
 
-void AudioFlinger::PlaybackThread::errorCallback()
+void AudioFlinger::PlaybackThread::onError()
 {
-    ALOG_ASSERT(mCallbackThread != 0);
     mCallbackThread->setAsyncError();
 }
 
@@ -2343,30 +2346,6 @@
     }
 }
 
-// static
-int AudioFlinger::PlaybackThread::asyncCallback(stream_callback_event_t event,
-                                                void *param __unused,
-                                                void *cookie)
-{
-    AudioFlinger::PlaybackThread *me = (AudioFlinger::PlaybackThread *)cookie;
-    ALOGV("asyncCallback() event %d", event);
-    switch (event) {
-    case STREAM_CBK_EVENT_WRITE_READY:
-        me->writeCallback();
-        break;
-    case STREAM_CBK_EVENT_DRAIN_READY:
-        me->drainCallback();
-        break;
-    case STREAM_CBK_EVENT_ERROR:
-        me->errorCallback();
-        break;
-    default:
-        ALOGW("asyncCallback() unknown event %d", event);
-        break;
-    }
-    return 0;
-}
-
 void AudioFlinger::PlaybackThread::readOutputParameters_l()
 {
     // unfortunately we have no way of recovering from errors here, hence the LOG_ALWAYS_FATAL
@@ -2383,7 +2362,8 @@
     mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
 
     // Get actual HAL format.
-    mHALFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
+    status_t result = mOutput->stream->getFormat(&mHALFormat);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error when retrieving output stream format: %d", result);
     // Get format from the shim, which will be different than the HAL format
     // if playing compressed audio over HDMI passthrough.
     mFormat = mOutput->getFormat();
@@ -2396,17 +2376,17 @@
                 mFormat);
     }
     mFrameSize = mOutput->getFrameSize();
-    mBufferSize = mOutput->stream->common.get_buffer_size(&mOutput->stream->common);
+    result = mOutput->stream->getBufferSize(&mBufferSize);
+    LOG_ALWAYS_FATAL_IF(result != OK,
+            "Error when retrieving output stream buffer size: %d", result);
     mFrameCount = mBufferSize / mFrameSize;
     if (mFrameCount & 15) {
         ALOGW("HAL output buffer size is %zu frames but AudioMixer requires multiples of 16 frames",
                 mFrameCount);
     }
 
-    if ((mOutput->flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) &&
-            (mOutput->stream->set_callback != NULL)) {
-        if (mOutput->stream->set_callback(mOutput->stream,
-                                      AudioFlinger::PlaybackThread::asyncCallback, this) == 0) {
+    if (mOutput->flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) {
+        if (mOutput->stream->setCallback(this) == OK) {
             mUseAsyncWrite = true;
             mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
         }
@@ -2414,14 +2394,15 @@
 
     mHwSupportsPause = false;
     if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (mOutput->stream->pause != NULL) {
-            if (mOutput->stream->resume != NULL) {
+        bool supportsPause = false, supportsResume = false;
+        if (mOutput->stream->supportsPauseAndResume(&supportsPause, &supportsResume) == OK) {
+            if (supportsPause && supportsResume) {
                 mHwSupportsPause = true;
-            } else {
+            } else if (supportsPause) {
                 ALOGW("direct output implements pause but not resume");
+            } else if (supportsResume) {
+                ALOGW("direct output implements resume but not pause");
             }
-        } else if (mOutput->stream->resume != NULL) {
-            ALOGW("direct output implements resume but not pause");
         }
     }
     if (!mHwSupportsPause && mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) {
@@ -2611,12 +2592,12 @@
 }
 
 // this method must always be called either with ThreadBase mLock held or inside the thread loop
-audio_stream_t* AudioFlinger::PlaybackThread::stream() const
+sp<StreamHalInterface> AudioFlinger::PlaybackThread::stream() const
 {
     if (mOutput == NULL) {
         return NULL;
     }
-    return &mOutput->stream->common;
+    return mOutput->stream;
 }
 
 uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs() const
@@ -2754,7 +2735,8 @@
 
 void AudioFlinger::PlaybackThread::threadLoop_drain()
 {
-    if (mOutput->stream->drain) {
+    bool supportsDrain = false;
+    if (mOutput->stream->supportsDrain(&supportsDrain) == OK && supportsDrain) {
         ALOGV("draining %s", (mMixerStatus == MIXER_DRAIN_TRACK) ? "early" : "full");
         if (mUseAsyncWrite) {
             ALOGW_IF(mDrainSequence & 1, "threadLoop_drain(): out of sequence drain request");
@@ -2762,9 +2744,10 @@
             ALOG_ASSERT(mCallbackThread != 0);
             mCallbackThread->setDraining(mDrainSequence);
         }
-        mOutput->stream->drain(mOutput->stream,
+        status_t result = mOutput->stream->drain(
             (mMixerStatus == MIXER_DRAIN_TRACK) ? AUDIO_DRAIN_EARLY_NOTIFY
                                                 : AUDIO_DRAIN_ALL);
+        ALOGE_IF(result != OK, "Error when draining stream: %d", result);
     }
 }
 
@@ -3449,11 +3432,9 @@
         }
         return status;
     }
-    if ((mType == OFFLOAD || mType == DIRECT)
-            && mOutput != NULL && mOutput->stream->get_presentation_position) {
+    if ((mType == OFFLOAD || mType == DIRECT) && mOutput != NULL) {
         uint64_t position64;
-        int ret = mOutput->getPresentationPosition(&position64, &timestamp.mTime);
-        if (ret == 0) {
+        if (mOutput->getPresentationPosition(&position64, &timestamp.mTime) == OK) {
             timestamp.mPosition = (uint32_t)position64;
             return NO_ERROR;
         }
@@ -3540,8 +3521,7 @@
         AudioParameter param = AudioParameter(String8(address));
         free(address);
         param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
-        status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                param.toString().string());
+        status = mOutput->stream->setParameters(param.toString());
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
     if (configChanged) {
@@ -3577,8 +3557,7 @@
     } else {
         AudioParameter param;
         param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
-        status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                param.toString().string());
+        status = mOutput->stream->setParameters(param.toString());
     }
     return status;
 }
@@ -3630,7 +3609,8 @@
         return;
     }
     // create an NBAIO sink for the HAL output stream, and negotiate
-    mOutputSink = new AudioStreamOutSink(output->stream);
+    mOutputSink = new AudioStreamOutSink(
+            static_cast<StreamOutHalLocal*>(output->stream.get())->getStream());
     size_t numCounterOffers = 0;
     const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)};
 #if !LOG_NDEBUG
@@ -4144,8 +4124,11 @@
                 // We have consumed all the buffers of this track.
                 // This would be incomplete if we auto-paused on underrun
                 {
-                    size_t audioHALFrames =
-                            (mOutput->stream->get_latency(mOutput->stream)*mSampleRate) / 1000;
+                    uint32_t latency = 0;
+                    status_t result = mOutput->stream->getLatency(&latency);
+                    ALOGE_IF(result != OK,
+                            "Error when retrieving output stream latency: %d", result);
+                    size_t audioHALFrames = (latency * mSampleRate) / 1000;
                     int64_t framesWritten = mBytesWritten / mFrameSize;
                     if (!(mStandby || track->presentationComplete(framesWritten, audioHALFrames))) {
                         // track stays in active list until presentation is complete
@@ -4686,14 +4669,12 @@
     }
 
     if (status == NO_ERROR) {
-        status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                keyValuePair.string());
+        status = mOutput->stream->setParameters(keyValuePair);
         if (!mStandby && status == INVALID_OPERATION) {
             mOutput->standby();
             mStandby = true;
             mBytesWritten = 0;
-            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                   keyValuePair.string());
+            status = mOutput->stream->setParameters(keyValuePair);
         }
         if (status == NO_ERROR && reconfig) {
             readOutputParameters_l();
@@ -4834,9 +4815,8 @@
                 left = (float)vl / (1 << 24);
                 right = (float)vr / (1 << 24);
             }
-            if (mOutput->stream->set_volume) {
-                mOutput->stream->set_volume(mOutput->stream, left, right);
-            }
+            status_t result = mOutput->stream->setVolume(left, right);
+            ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
         }
     }
 }
@@ -5046,13 +5026,15 @@
     // if resume is received before pause is executed.
     if (mHwSupportsPause && !mStandby &&
             (doHwPause || (mFlushPending && !mHwPaused && (count != 0)))) {
-        mOutput->stream->pause(mOutput->stream);
+        status_t result = mOutput->stream->pause();
+        ALOGE_IF(result != OK, "Error when pausing output stream: %d", result);
     }
     if (mFlushPending) {
         flushHw_l();
     }
     if (mHwSupportsPause && !mStandby && doHwResume) {
-        mOutput->stream->resume(mOutput->stream);
+        status_t result = mOutput->stream->resume();
+        ALOGE_IF(result != OK, "Error when resuming output stream: %d", result);
     }
     // remove all the tracks that need to be...
     removeTracks_l(*tracksToRemove);
@@ -5190,14 +5172,12 @@
         }
     }
     if (status == NO_ERROR) {
-        status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                keyValuePair.string());
+        status = mOutput->stream->setParameters(keyValuePair);
         if (!mStandby && status == INVALID_OPERATION) {
             mOutput->standby();
             mStandby = true;
             mBytesWritten = 0;
-            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                   keyValuePair.string());
+            status = mOutput->stream->setParameters(keyValuePair);
         }
         if (status == NO_ERROR && reconfig) {
             readOutputParameters_l();
@@ -5584,8 +5564,11 @@
                 // Drain has completed or we are in standby, signal presentation complete
                 if (!(mDrainSequence & 1) || !last || mStandby) {
                     track->mState = TrackBase::STOPPED;
-                    size_t audioHALFrames =
-                            (mOutput->stream->get_latency(mOutput->stream)*mSampleRate) / 1000;
+                    uint32_t latency = 0;
+                    status_t result = mOutput->stream->getLatency(&latency);
+                    ALOGE_IF(result != OK,
+                            "Error when retrieving output stream latency: %d", result);
+                    size_t audioHALFrames = (latency * mSampleRate) / 1000;
                     int64_t framesWritten =
                             mBytesWritten / mOutput->getFrameSize();
                     track->presentationComplete(framesWritten, audioHALFrames);
@@ -5597,16 +5580,15 @@
                 // fill a buffer, then remove it from active list.
                 if (--(track->mRetryCount) <= 0) {
                     bool running = false;
-                    if (mOutput->stream->get_presentation_position != nullptr) {
-                        uint64_t position = 0;
-                        struct timespec unused;
-                        // The running check restarts the retry counter at least once.
-                        int ret = mOutput->stream->get_presentation_position(
-                                mOutput->stream, &position, &unused);
-                        if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
-                            running = true;
-                            mOffloadUnderrunPosition = position;
-                        }
+                    uint64_t position = 0;
+                    struct timespec unused;
+                    // The running check restarts the retry counter at least once.
+                    status_t ret = mOutput->stream->getPresentationPosition(&position, &unused);
+                    if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
+                        running = true;
+                        mOffloadUnderrunPosition = position;
+                    }
+                    if (ret == NO_ERROR) {
                         ALOGVV("underrun counter, running(%d): %lld vs %lld", running,
                                 (long long)position, (long long)mOffloadUnderrunPosition);
                     }
@@ -5634,13 +5616,15 @@
     // before flush and then resume HW. This can happen in case of pause/flush/resume
     // if resume is received before pause is executed.
     if (!mStandby && (doHwPause || (mFlushPending && !mHwPaused && (count != 0)))) {
-        mOutput->stream->pause(mOutput->stream);
+        status_t result = mOutput->stream->pause();
+        ALOGE_IF(result != OK, "Error when pausing output stream: %d", result);
     }
     if (mFlushPending) {
         flushHw_l();
     }
     if (!mStandby && doHwResume) {
-        mOutput->stream->resume(mOutput->stream);
+        status_t result = mOutput->stream->resume();
+        ALOGE_IF(result != OK, "Error when resuming output stream: %d", result);
     }
 
     // remove all the tracks that need to be...
@@ -5915,7 +5899,8 @@
     readInputParameters_l();
 
     // create an NBAIO source for the HAL input stream, and negotiate
-    mInputSource = new AudioStreamInSource(input->stream);
+    mInputSource = new AudioStreamInSource(
+            static_cast<StreamInHalLocal*>(input->stream.get())->getStream());
     size_t numCounterOffers = 0;
     const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)};
 #if !LOG_NDEBUG
@@ -6304,11 +6289,12 @@
         // otherwise use the HAL / AudioStreamIn directly
         } else {
             ATRACE_BEGIN("read");
-            ssize_t bytesRead = mInput->stream->read(mInput->stream,
-                    (uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize);
+            size_t bytesRead;
+            status_t result = mInput->stream->read(
+                    (uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, &bytesRead);
             ATRACE_END();
-            if (bytesRead < 0) {
-                framesRead = bytesRead;
+            if (result < 0) {
+                framesRead = result;
             } else {
                 framesRead = bytesRead / mFrameSize;
             }
@@ -6320,10 +6306,9 @@
         mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
 
         // Update server timestamp with kernel stats
-        if (mInput->stream->get_capture_position != nullptr
-                && mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
+        if (mPipeSource.get() == nullptr /* don't obtain for FastCapture, could block */) {
             int64_t position, time;
-            int ret = mInput->stream->get_capture_position(mInput->stream, &position, &time);
+            int ret = mInput->stream->getCapturePosition(&position, &time);
             if (ret == NO_ERROR) {
                 mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
                 mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
@@ -6532,7 +6517,8 @@
             sq->end(false /*didModify*/);
         }
     }
-    mInput->stream->common.standby(&mInput->stream->common);
+    status_t result = mInput->stream->standby();
+    ALOGE_IF(result != OK, "Error when putting input stream into standby: %d", result);
 
     // If going into standby, flush the pipe source.
     if (mPipeSource.get() != nullptr) {
@@ -7386,22 +7372,22 @@
     }
 
     if (status == NO_ERROR) {
-        status = mInput->stream->common.set_parameters(&mInput->stream->common,
-                keyValuePair.string());
+        status = mInput->stream->setParameters(keyValuePair);
         if (status == INVALID_OPERATION) {
             inputStandBy();
-            status = mInput->stream->common.set_parameters(&mInput->stream->common,
-                    keyValuePair.string());
+            status = mInput->stream->setParameters(keyValuePair);
         }
         if (reconfig) {
-            if (status == BAD_VALUE &&
-                audio_is_linear_pcm(mInput->stream->common.get_format(&mInput->stream->common)) &&
-                audio_is_linear_pcm(reqFormat) &&
-                (mInput->stream->common.get_sample_rate(&mInput->stream->common)
-                        <= (AUDIO_RESAMPLER_DOWN_RATIO_MAX * samplingRate)) &&
-                audio_channel_count_from_in_mask(
-                        mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_8) {
-                status = NO_ERROR;
+            if (status == BAD_VALUE) {
+                uint32_t sRate;
+                audio_channel_mask_t channelMask;
+                audio_format_t format;
+                if (mInput->stream->getAudioProperties(&sRate, &channelMask, &format) == OK &&
+                        audio_is_linear_pcm(format) && audio_is_linear_pcm(reqFormat) &&
+                        sRate <= (AUDIO_RESAMPLER_DOWN_RATIO_MAX * samplingRate) &&
+                        audio_channel_count_from_in_mask(channelMask) <= FCC_8) {
+                    status = NO_ERROR;
+                }
             }
             if (status == NO_ERROR) {
                 readInputParameters_l();
@@ -7416,14 +7402,13 @@
 String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
 {
     Mutex::Autolock _l(mLock);
-    if (initCheck() != NO_ERROR) {
-        return String8();
+    if (initCheck() == NO_ERROR) {
+        String8 out_s8;
+        if (mInput->stream->getParameters(keys, &out_s8) == OK) {
+            return out_s8;
+        }
     }
-
-    char *s = mInput->stream->common.get_parameters(&mInput->stream->common, keys.string());
-    const String8 out_s8(s);
-    free(s);
-    return out_s8;
+    return String8();
 }
 
 void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
@@ -7452,19 +7437,16 @@
 
 void AudioFlinger::RecordThread::readInputParameters_l()
 {
-    mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
-    mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
+    status_t result = mInput->stream->getAudioProperties(&mSampleRate, &mChannelMask, &mHALFormat);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving audio properties from HAL: %d", result);
     mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
-    if (mChannelCount > FCC_8) {
-        ALOGE("HAL channel count %d > %d", mChannelCount, FCC_8);
-    }
-    mHALFormat = mInput->stream->common.get_format(&mInput->stream->common);
+    LOG_ALWAYS_FATAL_IF(mChannelCount > FCC_8, "HAL channel count %d > %d", mChannelCount, FCC_8);
     mFormat = mHALFormat;
-    if (!audio_is_linear_pcm(mFormat)) {
-        ALOGE("HAL format %#x is not linear pcm", mFormat);
-    }
-    mFrameSize = audio_stream_in_frame_size(mInput->stream);
-    mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common);
+    LOG_ALWAYS_FATAL_IF(!audio_is_linear_pcm(mFormat), "HAL format %#x is not linear pcm", mFormat);
+    result = mInput->stream->getFrameSize(&mFrameSize);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving frame size from HAL: %d", result);
+    result = mInput->stream->getBufferSize(&mBufferSize);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
     mFrameCount = mBufferSize / mFrameSize;
     // This is the formula for calculating the temporary buffer size.
     // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
@@ -7498,11 +7480,11 @@
 uint32_t AudioFlinger::RecordThread::getInputFramesLost()
 {
     Mutex::Autolock _l(mLock);
-    if (initCheck() != NO_ERROR) {
-        return 0;
+    uint32_t result;
+    if (initCheck() == NO_ERROR && mInput->stream->getInputFramesLost(&result) == OK) {
+        return result;
     }
-
-    return mInput->stream->get_input_frames_lost(mInput->stream);
+    return 0;
 }
 
 // hasAudioSession_l() must be called with ThreadBase::mLock held
@@ -7549,12 +7531,12 @@
 }
 
 // this method must always be called either with ThreadBase mLock held or inside the thread loop
-audio_stream_t* AudioFlinger::RecordThread::stream() const
+sp<StreamHalInterface> AudioFlinger::RecordThread::stream() const
 {
     if (mInput == NULL) {
         return NULL;
     }
-    return &mInput->stream->common;
+    return mInput->stream;
 }
 
 status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
@@ -7646,8 +7628,7 @@
                      (int)patch->sources[0].ext.device.type);
         param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE),
                                          (int)patch->sinks[0].ext.mix.usecase.source);
-        status = mInput->stream->common.set_parameters(&mInput->stream->common,
-                param.toString().string());
+        status = mInput->stream->setParameters(param.toString());
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
@@ -7671,8 +7652,7 @@
     } else {
         AudioParameter param;
         param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0);
-        status = mInput->stream->common.set_parameters(&mInput->stream->common,
-                param.toString().string());
+        status = mInput->stream->setParameters(param.toString());
     }
     return status;
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 15536f1..255fa8f 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -286,7 +286,7 @@
                 audio_devices_t outDevice() const { return mOutDevice; }
                 audio_devices_t inDevice() const { return mInDevice; }
 
-    virtual     audio_stream_t* stream() const = 0;
+    virtual     sp<StreamHalInterface> stream() const = 0;
 
                 sp<EffectHandle> createEffect_l(
                                     const sp<AudioFlinger::Client>& client,
@@ -484,7 +484,7 @@
 };
 
 // --- PlaybackThread ---
-class PlaybackThread : public ThreadBase {
+class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback {
 public:
 
 #include "PlaybackTracks.h"
@@ -539,13 +539,13 @@
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove) = 0;
                 void        removeTracks_l(const Vector< sp<Track> >& tracksToRemove);
 
-                void        writeCallback();
-                void        resetWriteBlocked(uint32_t sequence);
-                void        drainCallback();
-                void        resetDraining(uint32_t sequence);
-                void        errorCallback();
+    // StreamOutHalInterfaceCallback implementation
+    virtual     void        onWriteReady();
+    virtual     void        onDrainReady();
+    virtual     void        onError();
 
-    static      int         asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+                void        resetWriteBlocked(uint32_t sequence);
+                void        resetDraining(uint32_t sequence);
 
     virtual     bool        waitingAsyncCallback();
     virtual     bool        waitingAsyncCallback_l();
@@ -591,7 +591,7 @@
 
                 AudioStreamOut* getOutput() const;
                 AudioStreamOut* clearOutput();
-                virtual audio_stream_t* stream() const;
+                virtual sp<StreamHalInterface> stream() const;
 
                 // a very large number of suspend() will eventually wraparound, but unlikely
                 void        suspend() { (void) android_atomic_inc(&mSuspended); }
@@ -1297,7 +1297,7 @@
 
             void        dump(int fd, const Vector<String16>& args);
             AudioStreamIn* clearInput();
-            virtual audio_stream_t* stream() const;
+            virtual sp<StreamHalInterface> stream() const;
 
 
     virtual bool        checkForNewParameter_l(const String8& keyValuePair,