Merge "MediaCodec refactoring part 2-a: introduce callback"
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index 26135d7..3108a67 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -32,7 +32,6 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
@@ -401,8 +400,6 @@
 
     ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     sp<ALooper> looper = new ALooper;
     looper->start();
 
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index 410dd69..f219e69 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -30,7 +30,6 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/NuMediaExtractor.h>
 #include <media/stagefright/RenderScriptWrapper.h>
@@ -738,8 +737,6 @@
 
     ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     android::sp<ALooper> looper = new ALooper;
     looper->start();
 
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 0a3bdf3..4a83a4a 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -29,7 +29,6 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaMuxer.h>
@@ -319,9 +318,6 @@
     }
     ProcessState::self()->startThreadPool();
 
-    // Make sure setDataSource() works.
-    DataSource::RegisterDefaultSniffers();
-
     sp<ALooper> looper = new ALooper;
     looper->start();
 
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 9aa0156..94c2e96 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -170,8 +170,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
 #if 1
     if (argc != 3) {
         fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 31acdbc..12bbfd1 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -728,8 +728,6 @@
         return 1;
     }
 
-    DataSource::RegisterDefaultSniffers();
-
     sp<ALooper> looper = new ALooper;
     looper->setName("sf2");
 
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 2bb35cb..5e3a859 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -965,8 +965,6 @@
         }
     }
 
-    DataSource::RegisterDefaultSniffers();
-
     status_t err = OK;
 
     for (int k = 0; k < argc && err == OK; ++k) {
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 16ff39d..0cba8b9 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -301,8 +301,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     if (argc != 2) {
         fprintf(stderr, "Usage: %s filename\n", argv[0]);
         return 1;
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index 0750406..d75f71c 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -234,10 +234,6 @@
      * POSIX based Decrypt API set for container based DRM
      */
     static const int CONTAINER_BASED = 0x02;
-    /**
-     * Decrypt API for Widevine streams
-     */
-    static const int WV_BASED = 0x3;
 };
 
 /**
diff --git a/include/media/BufferingSettings.h b/include/media/BufferingSettings.h
new file mode 100644
index 0000000..7dd9d40
--- /dev/null
+++ b/include/media/BufferingSettings.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 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_BUFFERING_SETTINGS_H
+#define ANDROID_BUFFERING_SETTINGS_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+enum BufferingMode : int {
+    // Do not support buffering.
+    BUFFERING_MODE_NONE             = 0,
+    // Support only time based buffering.
+    BUFFERING_MODE_TIME_ONLY        = 1,
+    // Support only size based buffering.
+    BUFFERING_MODE_SIZE_ONLY        = 2,
+    // Support both time and size based buffering, time based calculation precedes size based.
+    // Size based calculation will be used only when time information is not available for
+    // the stream.
+    BUFFERING_MODE_TIME_THEN_SIZE   = 3,
+    // Number of modes.
+    BUFFERING_MODE_COUNT            = 4,
+};
+
+struct BufferingSettings : public Parcelable {
+    static const int kNoWatermark = -1;
+
+    static bool IsValidBufferingMode(int mode);
+
+    BufferingMode mInitialBufferingMode;  // for prepare
+    BufferingMode mRebufferingMode;  // for playback
+
+    int mInitialWatermarkMs;  // time based
+    int mInitialWatermarkKB;  // size based
+
+    // When cached data is below this mark, playback will be paused for buffering
+    // till data reach |mRebufferingWatermarkHighMs| or end of stream.
+    int mRebufferingWatermarkLowMs;
+    // When cached data is above this mark, buffering will be paused.
+    int mRebufferingWatermarkHighMs;
+
+    // When cached data is below this mark, playback will be paused for buffering
+    // till data reach |mRebufferingWatermarkHighKB| or end of stream.
+    int mRebufferingWatermarkLowKB;
+    // When cached data is above this mark, buffering will be paused.
+    int mRebufferingWatermarkHighKB;
+
+    BufferingSettings();
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BUFFERING_SETTINGS_H
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 99ef59f..f642373 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -39,6 +39,7 @@
 struct IMediaHTTPService;
 struct AudioPlaybackRate;
 struct AVSyncSettings;
+struct BufferingSettings;
 
 typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
 
@@ -59,6 +60,9 @@
     virtual status_t        setDataSource(const sp<IDataSource>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer) = 0;
+    virtual status_t        getDefaultBufferingSettings(
+                                    BufferingSettings* buffering /* nonnull */) = 0;
+    virtual status_t        setBufferingSettings(const BufferingSettings& buffering) = 0;
     virtual status_t        prepareAsync() = 0;
     virtual status_t        start() = 0;
     virtual status_t        stop() = 0;
diff --git a/include/media/MediaDefs.h b/include/media/MediaDefs.h
index 5f2a32d..0682413 100644
--- a/include/media/MediaDefs.h
+++ b/include/media/MediaDefs.h
@@ -59,8 +59,6 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
 
-extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
-
 extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
 extern const char *MEDIA_MIMETYPE_TEXT_VTT;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 4e4878a..0e815cb 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -30,6 +30,7 @@
 #include <media/AudioSystem.h>
 #include <media/AudioTimestamp.h>
 #include <media/AVSyncSettings.h>
+#include <media/BufferingSettings.h>
 #include <media/Metadata.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -174,6 +175,15 @@
     virtual status_t    setVideoSurfaceTexture(
                                 const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 
+    virtual status_t    getDefaultBufferingSettings(
+                                BufferingSettings* buffering /* nonnull */) {
+        *buffering = BufferingSettings();
+        return OK;
+    }
+    virtual status_t    setBufferingSettings(const BufferingSettings& /* buffering */) {
+        return OK;
+    }
+
     virtual status_t    prepare() = 0;
     virtual status_t    prepareAsync() = 0;
     virtual status_t    start() = 0;
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 0254545..3479f76 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -102,17 +102,6 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);
-
-    // The sniffer can optionally fill in "meta" with an AMessage containing
-    // a dictionary of values that helps the corresponding extractor initialize
-    // its state without duplicating effort already exerted by the sniffer.
-    typedef bool (*SnifferFunc)(
-            const sp<DataSource> &source, String8 *mimeType,
-            float *confidence, sp<AMessage> *meta);
-
-    static void RegisterDefaultSniffers();
-
     // for DRM
     virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
         return NULL;
@@ -131,12 +120,6 @@
     virtual ~DataSource() {}
 
 private:
-    static Mutex gSnifferMutex;
-    static List<SnifferFunc> gSniffers;
-    static bool gSniffersRegistered;
-
-    static void RegisterSniffer_l(SnifferFunc func);
-
     DataSource(const DataSource &);
     DataSource &operator=(const DataSource &);
 };
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 89def5d..b0243ec 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -151,8 +151,6 @@
     status_t getOutputFormat(sp<AMessage> *format) const;
     status_t getInputFormat(sp<AMessage> *format) const;
 
-    status_t getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
-
     status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
     status_t getOutputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const;
 
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 6bf8c9e..e5ee72e 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -80,6 +80,24 @@
 private:
     bool mIsDrm;
 
+    typedef bool (*SnifferFunc)(
+            const sp<DataSource> &source, String8 *mimeType,
+            float *confidence, sp<AMessage> *meta);
+
+    static Mutex gSnifferMutex;
+    static List<SnifferFunc> gSniffers;
+    static bool gSniffersRegistered;
+
+    // The sniffer can optionally fill in "meta" with an AMessage containing
+    // a dictionary of values that helps the corresponding extractor initialize
+    // its state without duplicating effort already exerted by the sniffer.
+    static void RegisterSniffer_l(SnifferFunc func);
+
+    static bool sniff(const sp<DataSource> &source,
+            String8 *mimeType, float *confidence, sp<AMessage> *meta);
+
+    static void RegisterDefaultSniffers();
+
     MediaExtractor(const MediaExtractor &);
     MediaExtractor &operator=(const MediaExtractor &);
 };
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 03e2185..a8aca5a 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -108,7 +108,6 @@
     sp<DataSource> mDataSource;
 
     sp<IMediaExtractor> mImpl;
-    bool mIsWidevineExtractor;
 
     Vector<TrackInfo> mSelectedTracks;
     int64_t mTotalBitrate;  // in bits/sec
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2e4cf7d..f4d8bc0 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -12,6 +12,7 @@
 LOCAL_SRC_FILES += \
     IDataSource.cpp \
     IHDCP.cpp \
+    BufferingSettings.cpp \
     mediaplayer.cpp \
     IMediaCodecList.cpp \
     IMediaCodecService.cpp \
diff --git a/media/libmedia/BufferingSettings.cpp b/media/libmedia/BufferingSettings.cpp
new file mode 100644
index 0000000..6dc4a53
--- /dev/null
+++ b/media/libmedia/BufferingSettings.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "BufferingSettings"
+//#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+
+#include <media/BufferingSettings.h>
+
+namespace android {
+
+// static
+bool BufferingSettings::IsValidBufferingMode(int mode) {
+    return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT);
+}
+
+BufferingSettings::BufferingSettings()
+        : mInitialBufferingMode(BUFFERING_MODE_NONE),
+          mRebufferingMode(BUFFERING_MODE_NONE),
+          mInitialWatermarkMs(kNoWatermark),
+          mInitialWatermarkKB(kNoWatermark),
+          mRebufferingWatermarkLowMs(kNoWatermark),
+          mRebufferingWatermarkHighMs(kNoWatermark),
+          mRebufferingWatermarkLowKB(kNoWatermark),
+          mRebufferingWatermarkHighKB(kNoWatermark) { }
+
+status_t BufferingSettings::readFromParcel(const Parcel* parcel) {
+    if (parcel == nullptr) {
+        return BAD_VALUE;
+    }
+    mInitialBufferingMode = (BufferingMode)parcel->readInt32();
+    mRebufferingMode = (BufferingMode)parcel->readInt32();
+    mInitialWatermarkMs = parcel->readInt32();
+    mInitialWatermarkKB = parcel->readInt32();
+    mRebufferingWatermarkLowMs = parcel->readInt32();
+    mRebufferingWatermarkHighMs = parcel->readInt32();
+    mRebufferingWatermarkLowKB = parcel->readInt32();
+    mRebufferingWatermarkHighKB = parcel->readInt32();
+
+    return OK;
+}
+
+status_t BufferingSettings::writeToParcel(Parcel* parcel) const {
+    if (parcel == nullptr) {
+        return BAD_VALUE;
+    }
+    parcel->writeInt32(mInitialBufferingMode);
+    parcel->writeInt32(mRebufferingMode);
+    parcel->writeInt32(mInitialWatermarkMs);
+    parcel->writeInt32(mInitialWatermarkKB);
+    parcel->writeInt32(mRebufferingWatermarkLowMs);
+    parcel->writeInt32(mRebufferingWatermarkHighMs);
+    parcel->writeInt32(mRebufferingWatermarkLowKB);
+    parcel->writeInt32(mRebufferingWatermarkHighKB);
+
+    return OK;
+}
+
+} // namespace android
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index dda2570..9ffde4e 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -23,6 +23,7 @@
 
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
+#include <media/BufferingSettings.h>
 
 #include <media/IDataSource.h>
 #include <media/IMediaHTTPService.h>
@@ -40,6 +41,8 @@
     SET_DATA_SOURCE_FD,
     SET_DATA_SOURCE_STREAM,
     SET_DATA_SOURCE_CALLBACK,
+    SET_BUFFERING_SETTINGS,
+    GET_DEFAULT_BUFFERING_SETTINGS,
     PREPARE_ASYNC,
     START,
     STOP,
@@ -148,6 +151,30 @@
         return reply.readInt32();
     }
 
+    status_t setBufferingSettings(const BufferingSettings& buffering)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        buffering.writeToParcel(&data);
+        remote()->transact(SET_BUFFERING_SETTINGS, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */)
+    {
+        if (buffering == nullptr) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(GET_DEFAULT_BUFFERING_SETTINGS, data, &reply);
+        status_t err = reply.readInt32();
+        if (err == OK) {
+            err = buffering->readFromParcel(&reply);
+        }
+        return err;
+    }
+
     status_t prepareAsync()
     {
         Parcel data, reply;
@@ -497,6 +524,23 @@
             reply->writeInt32(setVideoSurfaceTexture(bufferProducer));
             return NO_ERROR;
         } break;
+        case SET_BUFFERING_SETTINGS: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            BufferingSettings buffering;
+            buffering.readFromParcel(&data);
+            reply->writeInt32(setBufferingSettings(buffering));
+            return NO_ERROR;
+        } break;
+        case GET_DEFAULT_BUFFERING_SETTINGS: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            BufferingSettings buffering;
+            status_t err = getDefaultBufferingSettings(&buffering);
+            reply->writeInt32(err);
+            if (err == OK) {
+                buffering.writeToParcel(reply);
+            }
+            return NO_ERROR;
+        } break;
         case PREPARE_ASYNC: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             reply->writeInt32(prepareAsync());
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index c1fe87f..3d466b1 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -590,7 +590,7 @@
                     params = mmap(NULL, allocSize, PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANONYMOUS, -1 /* fd */, 0 /* offset */);
                 }
-                if (params != MAP_FAILED) {
+                if (params != MAP_FAILED && params != NULL) {
                     err = data.read(params, size);
                     if (err != OK) {
                         android_errorWriteLog(0x534e4554, "26914474");
diff --git a/media/libmedia/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index a2110c9..2ae71f7 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -57,8 +57,6 @@
 const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
 
-const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
-
 const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
 const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 605c710..0a9f791 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -26,7 +26,6 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <utils/Errors.h>
 #include <utils/misc.h>
-#include <../libstagefright/include/WVMExtractor.h>
 
 #include "MediaPlayerFactory.h"
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 6e163d9..3ad461c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -972,6 +972,42 @@
     return OK;
 }
 
+status_t MediaPlayerService::Client::setBufferingSettings(
+        const BufferingSettings& buffering)
+{
+    ALOGV("[%d] setBufferingSettings(%d, %d, %d, %d, %d, %d, %d, %d)",
+            mConnId, buffering.mInitialBufferingMode, buffering.mRebufferingMode,
+            buffering.mInitialWatermarkMs, buffering.mInitialWatermarkKB,
+            buffering.mRebufferingWatermarkLowMs,
+            buffering.mRebufferingWatermarkHighMs,
+            buffering.mRebufferingWatermarkLowKB,
+            buffering.mRebufferingWatermarkHighKB);
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+    return p->setBufferingSettings(buffering);
+}
+
+status_t MediaPlayerService::Client::getDefaultBufferingSettings(
+        BufferingSettings* buffering /* nonnull */)
+{
+    sp<MediaPlayerBase> p = getPlayer();
+    // TODO: create mPlayer on demand.
+    if (p == 0) return UNKNOWN_ERROR;
+    status_t ret = p->getDefaultBufferingSettings(buffering);
+    if (ret == NO_ERROR) {
+        ALOGV("[%d] getDefaultBufferingSettings(%d, %d, %d, %d, %d, %d, %d, %d)",
+                mConnId, buffering->mInitialBufferingMode, buffering->mRebufferingMode,
+                buffering->mInitialWatermarkMs, buffering->mInitialWatermarkKB,
+                buffering->mRebufferingWatermarkLowMs,
+                buffering->mRebufferingWatermarkHighMs,
+                buffering->mRebufferingWatermarkLowKB,
+                buffering->mRebufferingWatermarkHighKB);
+    } else {
+        ALOGV("[%d] getDefaultBufferingSettings returned %d", mConnId, ret);
+    }
+    return ret;
+}
+
 status_t MediaPlayerService::Client::prepareAsync()
 {
     ALOGV("[%d] prepareAsync", mConnId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index a4ea37f..8a6ada0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -288,6 +288,9 @@
         virtual void            disconnect();
         virtual status_t        setVideoSurfaceTexture(
                                         const sp<IGraphicBufferProducer>& bufferProducer);
+        virtual status_t        setBufferingSettings(const BufferingSettings& buffering) override;
+        virtual status_t        getDefaultBufferingSettings(
+                                        BufferingSettings* buffering /* nonnull */) override;
         virtual status_t        prepareAsync();
         virtual status_t        start();
         virtual status_t        stop();
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index fce9ab5..4956fa0 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -35,7 +35,6 @@
 #include <media/stagefright/Utils.h>
 #include "../../libstagefright/include/DRMExtractor.h"
 #include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/WVMExtractor.h"
 #include "../../libstagefright/include/HTTPBase.h"
 
 namespace android {
@@ -59,7 +58,6 @@
       mFetchTimedTextDataGeneration(0),
       mDurationUs(-1ll),
       mAudioIsVorbis(false),
-      mIsWidevine(false),
       mIsSecure(false),
       mIsStreaming(false),
       mUIDValid(uidValid),
@@ -70,7 +68,6 @@
       mPendingReadBufferTypes(0) {
     mBufferingMonitor = new BufferingMonitor(notify);
     resetDataSource();
-    DataSource::RegisterDefaultSniffers();
 }
 
 void NuPlayer::GenericSource::resetDataSource() {
@@ -141,44 +138,9 @@
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<IMediaExtractor> extractor;
-    String8 mimeType;
-    float confidence;
-    sp<AMessage> dummy;
-    bool isWidevineStreaming = false;
-
     CHECK(mDataSource != NULL);
 
-    if (mIsWidevine) {
-        isWidevineStreaming = SniffWVM(
-                mDataSource, &mimeType, &confidence, &dummy);
-        if (!isWidevineStreaming ||
-                strcasecmp(
-                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            ALOGE("unsupported widevine mime: %s", mimeType.string());
-            return UNKNOWN_ERROR;
-        }
-    } else if (mIsStreaming) {
-        if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
-            return UNKNOWN_ERROR;
-        }
-        isWidevineStreaming = !strcasecmp(
-                mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
-    }
-
-    if (isWidevineStreaming) {
-        // we don't want cached source for widevine streaming.
-        mCachedSource.clear();
-        mDataSource = mHttpSource;
-        mWVMExtractor = new WVMExtractor(mDataSource);
-        mWVMExtractor->setAdaptiveStreamingMode(true);
-        if (mUIDValid) {
-            mWVMExtractor->setUID(mUID);
-        }
-        extractor = mWVMExtractor;
-    } else {
-        extractor = MediaExtractor::Create(mDataSource,
-                mimeType.isEmpty() ? NULL : mimeType.string());
-    }
+    extractor = MediaExtractor::Create(mDataSource, NULL);
 
     if (extractor == NULL) {
         return UNKNOWN_ERROR;
@@ -194,17 +156,6 @@
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
             mDurationUs = duration;
         }
-
-        if (!mIsWidevine) {
-            // Check mime to see if we actually have a widevine source.
-            // If the data source is not URL-type (eg. file source), we
-            // won't be able to tell until now.
-            const char *fileMime;
-            if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
-                    && !strncasecmp(fileMime, "video/wvm", 9)) {
-                mIsWidevine = true;
-            }
-        }
     }
 
     int32_t totalBitrate = 0;
@@ -296,6 +247,9 @@
     // Widevine sources might re-initialize crypto when starting, if we delay
     // this to start(), all data buffered during prepare would be wasted.
     // (We don't actually start reading until start().)
+    //
+    // TODO: this logic may no longer be relevant after the removal of widevine
+    // support
     if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
         ALOGE("failed to start audio track!");
         return UNKNOWN_ERROR;
@@ -378,11 +332,8 @@
         if (!mUri.empty()) {
             const char* uri = mUri.c_str();
             String8 contentType;
-            mIsWidevine = !strncasecmp(uri, "widevine://", 11);
 
-            if (!strncasecmp("http://", uri, 7)
-                    || !strncasecmp("https://", uri, 8)
-                    || mIsWidevine) {
+            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
                 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
                 if (mHttpSource == NULL) {
                     ALOGE("Failed to create http source!");
@@ -395,8 +346,6 @@
                    mHTTPService, uri, &mUriHeaders, &contentType,
                    static_cast<HTTPBase *>(mHttpSource.get()));
         } else {
-            mIsWidevine = false;
-
             mDataSource = new FileSource(mFd, mOffset, mLength);
             mFd = -1;
         }
@@ -412,13 +361,9 @@
         mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
     }
 
-    // For widevine or other cached streaming cases, we need to wait for
-    // enough buffering before reporting prepared.
-    // Note that even when URL doesn't start with widevine://, mIsWidevine
-    // could still be set to true later, if the streaming or file source
-    // is sniffed to be widevine. We don't want to buffer for file source
-    // in that case, so must check the flag now.
-    mIsStreaming = (mIsWidevine || mCachedSource != NULL);
+    // For cached streaming cases, we need to wait for enough
+    // buffering before reporting prepared.
+    mIsStreaming = (mCachedSource != NULL);
 
     // init extractor from data source
     status_t err = initFromDataSource();
@@ -450,6 +395,9 @@
 
     if (mIsSecure) {
         // secure decoders must be instantiated before starting widevine source
+        //
+        // TODO: mIsSecure and FLAG_SECURE may be obsolete, revisit after
+        // removing widevine
         sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
         notifyInstantiateSecureDecoders(reply);
     } else {
@@ -476,7 +424,7 @@
 
     if (mIsStreaming) {
         if (mBufferingMonitorLooper == NULL) {
-            mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate,
+            mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
                     mIsStreaming);
 
             mBufferingMonitorLooper = new ALooper;
@@ -536,12 +484,6 @@
     // nothing to do, just account for DRM playback status
     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
     mStarted = false;
-    if (mIsWidevine || mIsSecure) {
-        // For widevine or secure sources we need to prevent any further reads.
-        sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
-        sp<AMessage> response;
-        (void) msg->postAndAwaitResponse(&response);
-    }
 }
 
 void NuPlayer::GenericSource::pause() {
@@ -719,20 +661,6 @@
           break;
       }
 
-      case kWhatStopWidevine:
-      {
-          // mStopRead is only used for Widevine to prevent the video source
-          // from being read while the associated video decoder is shutting down.
-          mStopRead = true;
-          if (mVideoTrack.mSource != NULL) {
-              mVideoTrack.mPackets->clear();
-          }
-          sp<AMessage> response = new AMessage;
-          sp<AReplyToken> replyID;
-          CHECK(msg->senderAwaitsResponse(&replyID));
-          response->postReply(replyID);
-          break;
-      }
       default:
           Source::onMessageReceived(msg);
           break;
@@ -888,11 +816,6 @@
         return -EWOULDBLOCK;
     }
 
-    if (mIsWidevine && !audio) {
-        // try to read a buffer as we may not have been able to the last time
-        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
-    }
-
     status_t finalResult;
     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
         if (finalResult == OK) {
@@ -1222,6 +1145,9 @@
 
     // If the Widevine source is stopped, do not attempt to read any
     // more buffers.
+    //
+    // TODO: revisit after widevine is removed.  May be able to
+    // combine mStopRead with mStarted.
     if (mStopRead) {
         return INVALID_OPERATION;
     }
@@ -1366,6 +1292,9 @@
         media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
         int64_t *actualTimeUs, bool formatChange) {
     // Do not read data if Widevine source is stopped
+    //
+    // TODO: revisit after widevine is removed.  May be able to
+    // combine mStopRead with mStarted.
     if (mStopRead) {
         return;
     }
@@ -1374,19 +1303,11 @@
     switch (trackType) {
         case MEDIA_TRACK_TYPE_VIDEO:
             track = &mVideoTrack;
-            if (mIsWidevine) {
-                maxBuffers = 2;
-            } else {
-                maxBuffers = 8;  // too large of a number may influence seeks
-            }
+            maxBuffers = 8;  // too large of a number may influence seeks
             break;
         case MEDIA_TRACK_TYPE_AUDIO:
             track = &mAudioTrack;
-            if (mIsWidevine) {
-                maxBuffers = 8;
-            } else {
-                maxBuffers = 64;
-            }
+            maxBuffers = 64;
             break;
         case MEDIA_TRACK_TYPE_SUBTITLE:
             track = &mSubtitleTrack;
@@ -1414,9 +1335,9 @@
         seeking = true;
     }
 
-    const bool couldReadMultiple = (!mIsWidevine && track->mSource->supportReadMultiple());
+    const bool couldReadMultiple = (track->mSource->supportReadMultiple());
 
-    if (mIsWidevine || couldReadMultiple) {
+    if (couldReadMultiple) {
         options.setNonBlocking();
     }
 
@@ -1538,17 +1459,16 @@
 
 void NuPlayer::GenericSource::BufferingMonitor::prepare(
         const sp<NuCachedSource2> &cachedSource,
-        const sp<WVMExtractor> &wvmExtractor,
         int64_t durationUs,
         int64_t bitrate,
         bool isStreaming) {
     Mutex::Autolock _l(mLock);
-    prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming);
+    prepare_l(cachedSource, durationUs, bitrate, isStreaming);
 }
 
 void NuPlayer::GenericSource::BufferingMonitor::stop() {
     Mutex::Autolock _l(mLock);
-    prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */,
+    prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
             -1 /* bitrate */, false /* isStreaming */);
 }
 
@@ -1603,22 +1523,17 @@
 
 void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
         const sp<NuCachedSource2> &cachedSource,
-        const sp<WVMExtractor> &wvmExtractor,
         int64_t durationUs,
         int64_t bitrate,
         bool isStreaming) {
-    ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL,
-            "WVMExtractor and NuCachedSource are both present when "
-            "BufferingMonitor::prepare_l is called, ignore NuCachedSource");
 
     mCachedSource = cachedSource;
-    mWVMExtractor = wvmExtractor;
     mDurationUs = durationUs;
     mBitrate = bitrate;
     mIsStreaming = isStreaming;
     mAudioTimeUs = 0;
     mVideoTimeUs = 0;
-    mPrepareBuffering = (cachedSource != NULL || wvmExtractor != NULL);
+    mPrepareBuffering = (cachedSource != NULL);
     cancelPollBuffering_l();
     mOffloadAudio = false;
     mFirstDequeuedBufferRealUs = -1ll;
@@ -1702,9 +1617,7 @@
     int32_t kbps = 0;
     status_t err = UNKNOWN_ERROR;
 
-    if (mWVMExtractor != NULL) {
-        err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
-    } else if (mCachedSource != NULL) {
+    if (mCachedSource != NULL) {
         err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
     }
 
@@ -1744,10 +1657,7 @@
     int64_t cachedDurationUs = -1ll;
     ssize_t cachedDataRemaining = -1;
 
-    if (mWVMExtractor != NULL) {
-        cachedDurationUs =
-                mWVMExtractor->getCachedDurationUs(&finalStatus);
-    } else if (mCachedSource != NULL) {
+    if (mCachedSource != NULL) {
         cachedDataRemaining =
                 mCachedSource->approxDataRemaining(&finalStatus);
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index d317c42..38d8616 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -37,7 +37,6 @@
 struct MediaSource;
 class MediaBuffer;
 struct NuCachedSource2;
-class WVMExtractor;
 
 struct NuPlayer::GenericSource : public NuPlayer::Source {
     GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
@@ -103,7 +102,6 @@
         kWhatSelectTrack,
         kWhatSeek,
         kWhatReadBuffer,
-        kWhatStopWidevine,
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
@@ -123,7 +121,6 @@
 
         // Set up state.
         void prepare(const sp<NuCachedSource2> &cachedSource,
-                const sp<WVMExtractor> &wvmExtractor,
                 int64_t durationUs,
                 int64_t bitrate,
                 bool isStreaming);
@@ -157,7 +154,6 @@
         sp<AMessage> mNotify;
 
         sp<NuCachedSource2> mCachedSource;
-        sp<WVMExtractor> mWVMExtractor;
         int64_t mDurationUs;
         int64_t mBitrate;
         bool mIsStreaming;
@@ -177,7 +173,6 @@
         int64_t mlastDequeuedBufferMediaUs;
 
         void prepare_l(const sp<NuCachedSource2> &cachedSource,
-                const sp<WVMExtractor> &wvmExtractor,
                 int64_t durationUs,
                 int64_t bitrate,
                 bool isStreaming);
@@ -206,7 +201,6 @@
     int32_t mFetchTimedTextDataGeneration;
     int64_t mDurationUs;
     bool mAudioIsVorbis;
-    bool mIsWidevine;
     bool mIsSecure;
     bool mIsStreaming;
     bool mUIDValid;
@@ -221,7 +215,6 @@
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
-    sp<WVMExtractor> mWVMExtractor;
     sp<MetaData> mFileMeta;
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d240521..1476206 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -263,9 +263,6 @@
     } else {
         sp<GenericSource> genericSource =
                 new GenericSource(notify, mUIDValid, mUID);
-        // Don't set FLAG_SECURE on mSourceFlags here for widevine.
-        // The correct flags will be updated in Source::kWhatFlagsChanged
-        // handler when  GenericSource is prepared.
 
         status_t err = genericSource->setDataSource(httpService, url, headers);
 
@@ -1671,29 +1668,6 @@
     (*decoder)->init();
     (*decoder)->configure(format);
 
-    // allocate buffers to decrypt widevine source buffers
-    if (!audio && (mSourceFlags & Source::FLAG_SECURE)) {
-        Vector<sp<MediaCodecBuffer> > inputBufs;
-        CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK);
-
-        Vector<MediaBuffer *> mediaBufs;
-        for (size_t i = 0; i < inputBufs.size(); i++) {
-            const sp<MediaCodecBuffer> &buffer = inputBufs[i];
-            MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size());
-            mediaBufs.push(mbuf);
-        }
-
-        status_t err = mSource->setBuffers(audio, mediaBufs);
-        if (err != OK) {
-            for (size_t i = 0; i < mediaBufs.size(); ++i) {
-                mediaBufs[i]->release();
-            }
-            mediaBufs.clear();
-            ALOGE("Secure source didn't support secure mediaBufs.");
-            return err;
-        }
-    }
-
     if (!audio) {
         sp<AMessage> params = new AMessage();
         float rate = getFrameRate();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index d2452af..e1d426a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -411,17 +411,7 @@
 }
 
 void NuPlayer::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
-    bool hadNoRenderer = (mRenderer == NULL);
     mRenderer = renderer;
-    if (hadNoRenderer && mRenderer != NULL) {
-        // this means that the widevine legacy source is ready
-        onRequestInputBuffers();
-    }
-}
-
-void NuPlayer::Decoder::onGetInputBuffers(
-        Vector<sp<MediaCodecBuffer> > *dstBuffers) {
-    CHECK_EQ((status_t)OK, mCodec->getWidevineLegacyBuffers(dstBuffers));
 }
 
 void NuPlayer::Decoder::onResume(bool notifyComplete) {
@@ -518,9 +508,7 @@
  * returns true if we should request more data
  */
 bool NuPlayer::Decoder::doRequestBuffers() {
-    // mRenderer is only NULL if we have a legacy widevine source that
-    // is not yet ready. In this case we must not fetch input.
-    if (isDiscontinuityPending() || mRenderer == NULL) {
+    if (isDiscontinuityPending()) {
         return false;
     }
     status_t err = OK;
@@ -878,40 +866,6 @@
     bool hasBuffer = msg->findBuffer("buffer", &buffer);
     bool needsCopy = true;
 
-    // handle widevine classic source - that fills an arbitrary input buffer
-    MediaBuffer *mediaBuffer = NULL;
-    if (hasBuffer) {
-        mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
-        if (mediaBuffer != NULL) {
-            // likely filled another buffer than we requested: adjust buffer index
-            size_t ix;
-            for (ix = 0; ix < mInputBuffers.size(); ix++) {
-                const sp<MediaCodecBuffer> &buf = mInputBuffers[ix];
-                if (buf->data() == mediaBuffer->data()) {
-                    // all input buffers are dequeued on start, hence the check
-                    if (!mInputBufferIsDequeued[ix]) {
-                        ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
-                                mComponentName.c_str(), ix, bufferIx);
-                        mediaBuffer->release();
-                        return false;
-                    }
-
-                    // TRICKY: need buffer for the metadata, so instead, set
-                    // codecBuffer to the same (though incorrect) buffer to
-                    // avoid a memcpy into the codecBuffer
-                    codecBuffer = new MediaCodecBuffer(codecBuffer->format(), buffer);
-                    codecBuffer->setRange(
-                            mediaBuffer->range_offset(),
-                            mediaBuffer->range_length());
-                    bufferIx = ix;
-                    needsCopy = false;
-                    break;
-                }
-            }
-            CHECK(ix < mInputBuffers.size());
-        }
-    }
-
     if (buffer == NULL /* includes !hasBuffer */) {
         int32_t streamErr = ERROR_END_OF_STREAM;
         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
@@ -981,18 +935,11 @@
                         timeUs,
                         flags);
         if (err != OK) {
-            if (mediaBuffer != NULL) {
-                mediaBuffer->release();
-            }
             ALOGE("Failed to queue input buffer for %s (err=%d)",
                     mComponentName.c_str(), err);
             handleError(err);
         } else {
             mInputBufferIsDequeued.editItemAt(bufferIx) = false;
-            if (mediaBuffer != NULL) {
-                CHECK(mMediaBuffers[bufferIx] == NULL);
-                mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
-            }
         }
     }
     return true;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index a576ae5..fcf601b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -47,7 +47,6 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 9c007ae..1210dc9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -92,14 +92,6 @@
     PostAndAwaitResponse(msg, &response);
 }
 
-status_t NuPlayer::DecoderBase::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
-    sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, this);
-    msg->setPointer("buffers", buffers);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
 void NuPlayer::DecoderBase::signalFlush() {
     (new AMessage(kWhatFlush, this))->post();
 }
@@ -166,20 +158,6 @@
             break;
         }
 
-        case kWhatGetInputBuffers:
-        {
-            sp<AReplyToken> replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            Vector<sp<MediaCodecBuffer> > *dstBuffers;
-            CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
-
-            onGetInputBuffers(dstBuffers);
-
-            (new AMessage)->postReply(replyID);
-            break;
-        }
-
         case kWhatRequestInputBuffers:
         {
             mRequestInputBuffersPending = false;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 6f4ead6..6811903 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -43,7 +43,6 @@
     void setRenderer(const sp<Renderer> &renderer);
     virtual status_t setVideoSurface(const sp<Surface> &) { return INVALID_OPERATION; }
 
-    status_t getInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) const;
     void signalFlush();
     void signalResume(bool notifyComplete);
     void initiateShutdown();
@@ -71,7 +70,6 @@
     virtual void onConfigure(const sp<AMessage> &format) = 0;
     virtual void onSetParameters(const sp<AMessage> &params) = 0;
     virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers) = 0;
     virtual void onResume(bool notifyComplete) = 0;
     virtual void onFlush() = 0;
     virtual void onShutdown(bool notifyComplete) = 0;
@@ -91,7 +89,6 @@
         kWhatSetParameters       = 'setP',
         kWhatSetRenderer         = 'setR',
         kWhatPause               = 'paus',
-        kWhatGetInputBuffers     = 'gInB',
         kWhatRequestInputBuffers = 'reqB',
         kWhatFlush               = 'flus',
         kWhatShutdown            = 'shuD',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index e4767ff..cb668e4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -93,11 +93,6 @@
             "ignoring request to change renderer");
 }
 
-void NuPlayer::DecoderPassThrough::onGetInputBuffers(
-        Vector<sp<MediaCodecBuffer> > * /* dstBuffers */) {
-    ALOGE("onGetInputBuffers() called unexpectedly");
-}
-
 bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
     int32_t generation;
     CHECK(msg->findInt32("generation", &generation));
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 9af25ff..173387a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -38,7 +38,6 @@
     virtual void onConfigure(const sp<AMessage> &format);
     virtual void onSetParameters(const sp<AMessage> &params);
     virtual void onSetRenderer(const sp<Renderer> &renderer);
-    virtual void onGetInputBuffers(Vector<sp<MediaCodecBuffer> > *dstBuffers);
     virtual void onResume(bool notifyComplete);
     virtual void onFlush();
     virtual void onShutdown(bool notifyComplete);
diff --git a/media/liboboe/README.md b/media/liboboe/README.md
new file mode 100644
index 0000000..80894c6
--- /dev/null
+++ b/media/liboboe/README.md
@@ -0,0 +1 @@
+Oboe Audio input/output API
diff --git a/media/liboboe/include/oboe/OboeAudio.h b/media/liboboe/include/oboe/OboeAudio.h
new file mode 100644
index 0000000..35013a7
--- /dev/null
+++ b/media/liboboe/include/oboe/OboeAudio.h
@@ -0,0 +1,482 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is the 'C' ABI for Oboe.
+ */
+#ifndef OBOE_OBOEAUDIO_H
+#define OBOE_OBOEAUDIO_H
+
+#include "OboeDefinitions.h"
+
+typedef int32_t OboeDeviceId;
+typedef oboe_handle_t OboeStream;
+typedef oboe_handle_t OboeStreamBuilder;
+typedef oboe_handle_t OboeThread;
+
+#define OBOE_STREAM_NONE         ((OboeStream)OBOE_HANDLE_INVALID)
+#define OBOE_STREAM_BUILDER_NONE ((OboeStreamBuilder)OBOE_HANDLE_INVALID)
+
+
+// ============================================================
+// Audio System
+// ============================================================
+
+/**
+ * @return time in the same clock domain as the timestamps
+ */
+oboe_nanoseconds_t Oboe_getNanoseconds(oboe_clockid_t clockid);
+
+/**
+ * The text is the ASCII symbol corresponding to the returnCode,
+ * or an English message saying the returnCode is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an Oboe result code.
+ */
+const char * Oboe_convertResultToText(oboe_result_t returnCode);
+
+/**
+ * The text is the ASCII symbol corresponding to the state,
+ * or an English message saying the state is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an Oboe state.
+ */
+const char * Oboe_convertStateToText(oboe_state_t state);
+
+// ============================================================
+// StreamBuilder
+// ============================================================
+/**
+ * Create a StreamBuilder that can be used to open a Stream.
+ *
+ * OboeStreamBuilder_delete() must be called when you are done using the builder.
+ */
+oboe_result_t Oboe_createStreamBuilder(OboeStreamBuilder *builder);
+
+/**
+ * Request an audio device identified device using an ID.
+ * The ID is platform specific.
+ * On Android, for example, the ID could be obtained from the Java AudioManager.
+ *
+ * By default, the primary output device will be used.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setDeviceId(OboeStreamBuilder builder, OboeDeviceId deviceId);
+
+/**
+ * Request a sample rate in Hz.
+ * The stream may be opened with a different sample rate.
+ * So the application should query for the actual rate after the stream is opened.
+ *
+ * Technically, this should be called the "frame rate" or "frames per second",
+ * because it refers to the number of complete frames transferred per second.
+ * But it is traditionally called "sample rate". Se we use that term.
+ *
+ * Default is OBOE_UNSPECIFIED.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setSampleRate(OboeStreamBuilder builder,
+                                              oboe_sample_rate_t sampleRate);
+
+/**
+ * Returns sample rate in Hertz (samples per second).
+ * @return positive sampleRate or a negative error, zero for unspecified
+ */
+oboe_result_t OboeStreamBuilder_getSampleRate(OboeStreamBuilder builder,
+                                              oboe_sample_rate_t *sampleRate);
+
+
+/**
+ * Request a number of samples per frame.
+ * The stream may be opened with a different value.
+ * So the application should query for the actual value after the stream is opened.
+ *
+ * Default is OBOE_UNSPECIFIED.
+ *
+ * Note, this quantity is sometimes referred to as "channel count".
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setSamplesPerFrame(OboeStreamBuilder builder,
+                                                   int32_t samplesPerFrame);
+
+/**
+ * Note, this quantity is sometimes referred to as "channel count".
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param samplesPerFrame pointer to a variable to be set to samplesPerFrame.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_getSamplesPerFrame(OboeStreamBuilder builder,
+                                                   int32_t *samplesPerFrame);
+
+
+/**
+ * Request a sample data format, for example OBOE_AUDIO_FORMAT_PCM16.
+ * The application should query for the actual format after the stream is opened.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setFormat(OboeStreamBuilder builder, oboe_audio_format_t format);
+
+/**
+ * @return positive data format or a negative error, zero for unspecified
+ */
+oboe_result_t OboeStreamBuilder_getFormat(OboeStreamBuilder builder, oboe_audio_format_t *format);
+
+/**
+ * Request a mode for sharing the device.
+ * The requested sharing mode may not be available.
+ * So the application should query for the actual mode after the stream is opened.
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param sharingMode OBOE_SHARING_MODE_LEGACY or OBOE_SHARING_MODE_EXCLUSIVE
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setSharingMode(OboeStreamBuilder builder,
+                                               oboe_sharing_mode_t sharingMode);
+
+/**
+ * Return requested sharing mode.
+ * @return OBOE_OK or a negative error
+ */
+oboe_result_t OboeStreamBuilder_getSharingMode(OboeStreamBuilder builder,
+                                               oboe_sharing_mode_t *sharingMode);
+
+/**
+ * Request the direction for a stream. The default is OBOE_DIRECTION_OUTPUT.
+ *
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param direction OBOE_DIRECTION_OUTPUT or OBOE_DIRECTION_INPUT
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_setDirection(OboeStreamBuilder builder,
+                                             oboe_direction_t direction);
+
+/**
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @param direction pointer to a variable to be set to the currently requested direction.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStreamBuilder_getDirection(OboeStreamBuilder builder,
+                                             oboe_direction_t *direction);
+
+/**
+ * Open a stream based on the options in the StreamBuilder.
+ *
+ * OboeStream_close must be called when finished with the stream to recover
+ * the memory and to free the associated resources.
+ *
+ * @return OBOE_OK or a negative error. Also pass back a stream handle.
+ */
+oboe_result_t  OboeStreamBuilder_openStream(OboeStreamBuilder builder, OboeStream *stream);
+
+/**
+ * Delete the resources associated with the StreamBuilder.
+ * @param builder handle provided by Oboe_createStreamBuilder()
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t  OboeStreamBuilder_delete(OboeStreamBuilder builder);
+
+// ============================================================
+// Stream Control
+// ============================================================
+
+/**
+ * Free the resources associated with a stream created by OboeStreamBuilder_openStream()
+ */
+oboe_result_t  OboeStream_close(OboeStream stream);
+
+/**
+ * Asynchronously request to start playing the stream. For output streams, one should
+ * write to the stream to fill the buffer before starting.
+ * Otherwise it will underflow.
+ * After this call the state will be in OBOE_STATE_STARTING or OBOE_STATE_STARTED.
+ */
+oboe_result_t  OboeStream_requestStart(OboeStream stream);
+
+/**
+ * Asynchronous request for the stream to pause.
+ * Pausing a stream will freeze the data flow but not flush any buffers.
+ * Use OboeStream_Start() to resume playback after a pause.
+ * After this call the state will be in OBOE_STATE_PAUSING or OBOE_STATE_PAUSED.
+ */
+oboe_result_t  OboeStream_requestPause(OboeStream stream);
+
+/**
+ * Asynchronous request for the stream to flush.
+ * Flushing will discard any pending data.
+ * This call only works if the stream is pausing or paused. TODO review
+ * Frame counters are not reset by a flush. They may be advanced.
+ * After this call the state will be in OBOE_STATE_FLUSHING or OBOE_STATE_FLUSHED.
+ */
+oboe_result_t  OboeStream_requestFlush(OboeStream stream);
+
+/**
+ * Asynchronous request for the stream to stop.
+ * The stream will stop after all of the data currently buffered has been played.
+ * After this call the state will be in OBOE_STATE_STOPPING or OBOE_STATE_STOPPED.
+ */
+oboe_result_t  OboeStream_requestStop(OboeStream stream);
+
+/**
+ * Query the current state, eg. OBOE_STATE_PAUSING
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getState(OboeStream stream, oboe_state_t *state);
+
+/**
+ * Wait until the current state no longer matches the input state.
+ *
+ * <pre><code>
+ * oboe_state_t currentState = OboeStream_getState(stream);
+ * while (currentState >= 0 && currentState != OBOE_STATE_PAUSING) {
+ *     currentState = OboeStream_waitForStateChange(
+ *                                   stream, currentState, MY_TIMEOUT_MSEC);
+ * }
+ * </code></pre>
+ *
+ * @param stream A handle provided by OboeStreamBuilder_openStream()
+ * @param inputState The state we want to avoid.
+ * @param nextState Pointer to a variable that will be set to the new state.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return oboe_state_t or a negative error.
+ */
+oboe_result_t OboeStream_waitForStateChange(OboeStream stream,
+                                            oboe_state_t inputState,
+                                            oboe_state_t *nextState,
+                                            oboe_nanoseconds_t timeoutNanoseconds);
+
+// ============================================================
+// Stream I/O
+// ============================================================
+
+/**
+ * Read data from the stream.
+ *
+ * The call will wait until the read is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for data.
+ *
+ * @param stream A stream created using OboeStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to read. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+oboe_result_t OboeStream_read(OboeStream stream,
+                               void *buffer,
+                               int32_t numFrames,
+                               oboe_nanoseconds_t timeoutNanoseconds);
+
+/**
+ * Write data to the stream.
+ *
+ * The call will wait until the write is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for room in the buffer.
+ *
+ * @param stream A stream created using OboeStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to write. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+oboe_result_t OboeStream_write(OboeStream stream,
+                               const void *buffer,
+                               int32_t numFrames,
+                               oboe_nanoseconds_t timeoutNanoseconds);
+
+
+// ============================================================
+// High priority audio threads
+// ============================================================
+
+/**
+ * Create a thread with special properties for low latency audio performance.
+ * This thread can be used to implement a callback API.
+ *
+ * Note that this API is in flux.
+ *
+ * @param threadHandlePtr a pointer to receive a thread handle
+ * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
+ * @param start_routine your thread entry point
+ * @param arg an argument that will be passed to your thread entry point
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t Oboe_createAudioThread(OboeThread *threadHandlePtr,
+                                     oboe_nanoseconds_t periodNanoseconds,
+                                     void *(*start_routine)(void *), void *arg);
+
+/**
+ * Wait until the thread exits or an error occurs.
+ * The thread handle will be deleted.
+ *
+ * @param thread the thread handle passed back from Oboe_createAudioThread()
+ * @param returnArg a pointer to a variable to receive the return value
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t Oboe_joinAudioThread(OboeThread thread,
+                                   void **returnArg,
+                                   oboe_nanoseconds_t timeoutNanoseconds);
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+
+/**
+ * This can be used to adjust the latency of the buffer by changing
+ * the threshold where blocking will occur.
+ * By combining this with OboeStream_getUnderrunCount(), the latency can be tuned
+ * at run-time for each device.
+ *
+ * This cannot be set higher than OboeStream_getBufferCapacity().
+ *
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param frames requested number of frames that can be filled without blocking
+ * @return actual number of frames or a negative error
+ */
+oboe_result_t OboeStream_setBufferSize(OboeStream stream, oboe_size_frames_t frames);
+
+/**
+ * Query the maximum number of frames that can be filled without blocking.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getBufferSize(OboeStream stream, oboe_size_frames_t *frames);
+
+/**
+ * Query the number of frames that are read or written by the endpoint at one time.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFramesPerBurst(OboeStream stream, oboe_size_frames_t *frames);
+
+/**
+ * Query maximum buffer capacity in frames.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getBufferCapacity(OboeStream stream, oboe_size_frames_t *frames);
+
+/**
+ * An XRun is an Underrun or an Overrun.
+ * During playing, an underrun will occur if the stream is not written in time
+ * and the system runs out of valid data.
+ * During recording, an overrun will occur if the stream is not read in time
+ * and there is no place to put the incoming data so it is discarded.
+ *
+ * An underrun or overrun can cause an audible "pop" or "glitch".
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getXRunCount(OboeStream stream, int32_t *xRunCount);
+
+/**
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getSampleRate(OboeStream stream, int32_t *sampleRate);
+
+/**
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getSamplesPerFrame(OboeStream stream, int32_t *samplesPerFrame);
+
+/**
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFormat(OboeStream stream, oboe_audio_format_t *format);
+
+/**
+ * Provide actual sharing mode.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getSharingMode(OboeStream stream,
+                                        oboe_sharing_mode_t *sharingMode);
+
+/**
+ * @param stream handle provided by OboeStreamBuilder_openStream()
+ * @param direction pointer to a variable to be set to the current direction.
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getDirection(OboeStream stream, uint32_t *direction);
+
+/**
+ * Passes back the number of frames that have been written since the stream was created.
+ * For an output stream, this will be advanced by the application calling write().
+ * For an input stream, this will be advanced by the device or service.
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFramesWritten(OboeStream stream, oboe_position_frames_t *frames);
+
+/**
+ * Passes back the number of frames that have been read since the stream was created.
+ * For an output stream, this will be advanced by the device or service.
+ * For an input stream, this will be advanced by the application calling read().
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @return OBOE_OK or a negative error.
+ */
+oboe_result_t OboeStream_getFramesRead(OboeStream stream, oboe_position_frames_t *frames);
+
+/**
+ * Passes back the time at which a particular frame was presented.
+ * This can be used to synchronize audio with video or MIDI.
+ * It can also be used to align a recorded stream with a playback stream.
+ *
+ * Timestamps are only valid when the stream is in OBOE_STATE_STARTED.
+ * OBOE_ERROR_INVALID_STATE will be returned if the stream is not started.
+ * Note that because requestStart() is asynchronous, timestamps will not be valid until
+ * a short time after calling requestStart().
+ * So OBOE_ERROR_INVALID_STATE should not be considered a fatal error.
+ * Just try calling again later.
+ *
+ * If an error occurs, then the position and time will not be modified.
+ *
+ * The position and time passed back are monotonically increasing.
+ *
+ * @param stream A handle provided by OboeStreamBuilder_openStream()
+ * @param clockId OBOE_CLOCK_MONOTONIC or OBOE_CLOCK_BOOTTIME
+ * @param framePosition pointer to a variable to receive the position
+ * @param timeNanoseconds pointer to a variable to receive the time
+ * @return OBOE_OK or a negative error
+ */
+oboe_result_t OboeStream_getTimestamp(OboeStream stream,
+                                      oboe_clockid_t clockid,
+                                      oboe_position_frames_t *framePosition,
+                                      oboe_nanoseconds_t *timeNanoseconds);
+
+#endif //NATIVEOBOE_OBOEAUDIO_H
diff --git a/media/liboboe/include/oboe/OboeDefinitions.h b/media/liboboe/include/oboe/OboeDefinitions.h
new file mode 100644
index 0000000..ff9bd92
--- /dev/null
+++ b/media/liboboe/include/oboe/OboeDefinitions.h
@@ -0,0 +1,177 @@
+/*
+ * 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 OBOE_OBOEDEFINITIONS_H
+#define OBOE_OBOEDEFINITIONS_H
+
+#include <stdint.h>
+
+typedef int32_t  oboe_handle_t;
+typedef int32_t  oboe_result_t;
+typedef int32_t  oboe_sample_rate_t;
+/** This is used for small quantities such as the number of frames in a buffer. */
+typedef int32_t  oboe_size_frames_t;
+/** This is used for large quantities, such as the number of frames that have
+ * been played since a stream was started.
+ * At 48000 Hz, a 32-bit integer would wrap around in just over 12 hours.
+ */
+typedef int64_t  oboe_position_frames_t;
+
+typedef int64_t  oboe_nanoseconds_t;
+typedef uint32_t oboe_audio_format_t;
+
+/**
+ * This is used to represent a value that has not been specified.
+ * For example, an application could use OBOE_UNSPECIFIED to indicate
+ * that is did not not care what the specific value of a parameter was
+ * and would accept whatever it was given.
+ */
+#define OBOE_UNSPECIFIED           0
+#define OBOE_NANOS_PER_MICROSECOND ((int64_t)1000)
+#define OBOE_NANOS_PER_MILLISECOND (OBOE_NANOS_PER_MICROSECOND * 1000)
+#define OBOE_MILLIS_PER_SECOND     1000
+#define OBOE_NANOS_PER_SECOND      (OBOE_NANOS_PER_MILLISECOND * OBOE_MILLIS_PER_SECOND)
+
+#define OBOE_HANDLE_INVALID     ((oboe_handle_t)-1)
+
+enum oboe_direction_t {
+    OBOE_DIRECTION_OUTPUT,
+    OBOE_DIRECTION_INPUT,
+    OBOE_DIRECTION_COUNT // This should always be last.
+};
+
+enum {
+    OBOE_AUDIO_DATATYPE_INT16,
+    OBOE_AUDIO_DATATYPE_INT32,
+    OBOE_AUDIO_DATATYPE_INT824,
+    OBOE_AUDIO_DATATYPE_UINT8,
+    OBOE_AUDIO_DATATYPE_FLOAT32, // Add new values below.
+    OBOE_AUDIO_DATATYPE_COUNT // This should always be last.
+};
+
+enum {
+    OBOE_AUDIO_CONTENT_PCM,
+    OBOE_AUDIO_CONTENT_MP3,
+    OBOE_AUDIO_CONTENT_AAC,
+    OBOE_AUDIO_CONTENT_AC3,
+    OBOE_AUDIO_CONTENT_EAC3,
+    OBOE_AUDIO_CONTENT_DTS,
+    OBOE_AUDIO_CONTENT_DTSHD, // Add new values below.
+    OBOE_AUDIO_CONTENT_COUNT // This should always be last.
+};
+
+enum {
+    OBOE_AUDIO_WRAPPER_NONE,
+    OBOE_AUDIO_WRAPPER_IEC61937, // Add new values below.
+    OBOE_AUDIO_WRAPPER_COUNT // This should always be last.
+};
+
+/**
+ * Fields packed into oboe_audio_format_t, from most to least significant bits.
+ *   Reserved:8
+ *   Wrapper:8
+ *   Content:8
+ *   Data Type:8
+ */
+#define OBOE_AUDIO_FORMAT(dataType, content, wrapper) \
+    ((oboe_audio_format_t)((wrapper << 16) | (content << 8) | dataType))
+
+#define OBOE_AUDIO_FORMAT_RAW(dataType, content) \
+                OBOE_AUDIO_FORMAT(dataType, content, OBOE_AUDIO_WRAPPER_NONE)
+
+#define OBOE_AUDIO_FORMAT_DATA_TYPE(format) \
+    (format & 0x0FF)
+
+// Define some common formats.
+#define OBOE_AUDIO_FORMAT_PCM16  \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT16, OBOE_AUDIO_CONTENT_PCM)
+#define OBOE_AUDIO_FORMAT_PCM_FLOAT \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_FLOAT32, OBOE_AUDIO_CONTENT_PCM)
+#define OBOE_AUDIO_FORMAT_PCM824 \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT824, OBOE_AUDIO_CONTENT_PCM)
+
+enum {
+    OBOE_OK,
+    OBOE_ERROR_BASE = -900, // TODO review
+    OBOE_ERROR_DISCONNECTED,
+    OBOE_ERROR_ILLEGAL_ARGUMENT,
+    OBOE_ERROR_INCOMPATIBLE,
+    OBOE_ERROR_INTERNAL, // an underlying API returned an error code
+    OBOE_ERROR_INVALID_STATE,
+    OBOE_ERROR_UNEXPECTED_STATE,
+    OBOE_ERROR_UNEXPECTED_VALUE,
+    OBOE_ERROR_INVALID_HANDLE,
+    OBOE_ERROR_INVALID_QUERY,
+    OBOE_ERROR_UNIMPLEMENTED,
+    OBOE_ERROR_UNAVAILABLE,
+    OBOE_ERROR_NO_FREE_HANDLES,
+    OBOE_ERROR_NO_MEMORY,
+    OBOE_ERROR_NULL,
+    OBOE_ERROR_TIMEOUT,
+    OBOE_ERROR_WOULD_BLOCK,
+    OBOE_ERROR_INVALID_ORDER
+};
+
+typedef enum {
+    OBOE_CLOCK_MONOTONIC, // Clock since booted, pauses when CPU is sleeping.
+    OBOE_CLOCK_BOOTTIME,  // Clock since booted, runs all the time.
+    OBOE_CLOCK_COUNT // This should always be last.
+} oboe_clockid_t;
+
+typedef enum
+{
+    OBOE_STATE_UNINITIALIZED = 0,
+    OBOE_STATE_OPEN,
+    OBOE_STATE_STARTING,
+    OBOE_STATE_STARTED,
+    OBOE_STATE_PAUSING,
+    OBOE_STATE_PAUSED,
+    OBOE_STATE_FLUSHING,
+    OBOE_STATE_FLUSHED,
+    OBOE_STATE_STOPPING,
+    OBOE_STATE_STOPPED,
+    OBOE_STATE_CLOSING,
+    OBOE_STATE_CLOSED,
+} oboe_state_t;
+
+// TODO review API
+typedef enum {
+    /**
+     * This will use an AudioTrack object for playing audio
+     * and an AudioRecord for recording data.
+     */
+    OBOE_SHARING_MODE_LEGACY,
+    /**
+     * This will be the only stream using a particular source or sink.
+     * This mode will provide the lowest possible latency.
+     * You should close EXCLUSIVE streams immediately when you are not using them.
+     */
+    OBOE_SHARING_MODE_EXCLUSIVE,
+    /**
+     * Multiple applications will be mixed by the Oboe Server.
+     * This will have higher latency than the EXCLUSIVE mode.
+     */
+    OBOE_SHARING_MODE_SHARED,
+    /**
+     * Multiple applications will do their own mixing into a memory mapped buffer.
+     * It may be possible for malicious applications to read the data produced by
+     * other apps. So do not use this for private data such as telephony or messaging.
+     */
+    OBOE_SHARING_MODE_PUBLIC_MIX,
+    OBOE_SHARING_MODE_COUNT // This should always be last.
+} oboe_sharing_mode_t;
+
+#endif // OBOE_OBOEDEFINITIONS_H
diff --git a/media/liboboe/include/oboe/README.md b/media/liboboe/include/oboe/README.md
new file mode 100644
index 0000000..de60d03
--- /dev/null
+++ b/media/liboboe/include/oboe/README.md
@@ -0,0 +1,4 @@
+Oboe Audio headers
+
+This folder contains the public header files.
+
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 47c3f82..a0c8ace 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5484,9 +5484,8 @@
     int32_t err = OK;
     bool eos = false;
     PortMode mode = getPortMode(kPortIndexInput);
-
-    sp<RefBase> obj;
-    if (!msg->findObject("buffer", &obj)) {
+    int32_t discarded = 0;
+    if (msg->findInt32("discarded", &discarded) && discarded) {
         /* these are unfilled buffers returned by client */
         CHECK(msg->findInt32("err", &err));
 
@@ -5498,9 +5497,10 @@
                  mCodec->mComponentName.c_str(), err);
             eos = true;
         }
-    } else {
-        buffer = static_cast<MediaCodecBuffer *>(obj.get());
     }
+    sp<RefBase> obj;
+    CHECK(msg->findObject("buffer", &obj));
+    buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
     int32_t tmp;
     if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
@@ -5916,10 +5916,11 @@
     IOMX::buffer_id bufferID;
     CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
     sp<RefBase> obj;
-    sp<MediaCodecBuffer> buffer = nullptr;
-    if (msg->findObject("buffer", &obj)) {
-        buffer = static_cast<MediaCodecBuffer *>(obj.get());
-    }
+    CHECK(msg->findObject("buffer", &obj));
+    sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
+    int32_t discarded = 0;
+    msg->findInt32("discarded", &discarded);
+
     ssize_t index;
     BufferInfo *info = mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
     BufferInfo::Status status = BufferInfo::getSafeStatus(info);
@@ -5951,7 +5952,7 @@
     int32_t render;
     if (mCodec->mNativeWindow != NULL
             && msg->findInt32("render", &render) && render != 0
-            && buffer != NULL && buffer->size() != 0) {
+            && !discarded && buffer->size() != 0) {
         ATRACE_NAME("render");
         // The client wants this buffer to be rendered.
 
@@ -5990,8 +5991,7 @@
             info->mIsReadFence = false;
         }
     } else {
-        if (mCodec->mNativeWindow != NULL &&
-            (buffer == NULL || buffer->size() != 0)) {
+        if (mCodec->mNativeWindow != NULL && (discarded || buffer->size() != 0)) {
             // move read fence into write fence to avoid clobbering
             info->mIsReadFence = false;
             ATRACE_NAME("frame-drop");
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5e921e3..9e3b35a 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -59,7 +59,6 @@
         VBRISeeker.cpp                    \
         VideoFrameScheduler.cpp           \
         WAVExtractor.cpp                  \
-        WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 163a527..a9536b9 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -31,7 +31,6 @@
 #include "include/NuCachedSource2.h"
 #include "include/OggExtractor.h"
 #include "include/WAVExtractor.h"
-#include "include/WVMExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -112,83 +111,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-Mutex DataSource::gSnifferMutex;
-List<DataSource::SnifferFunc> DataSource::gSniffers;
-bool DataSource::gSniffersRegistered = false;
-
-bool DataSource::sniff(
-        String8 *mimeType, float *confidence, sp<AMessage> *meta) {
-    *mimeType = "";
-    *confidence = 0.0f;
-    meta->clear();
-
-    {
-        Mutex::Autolock autoLock(gSnifferMutex);
-        if (!gSniffersRegistered) {
-            return false;
-        }
-    }
-
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        String8 newMimeType;
-        float newConfidence;
-        sp<AMessage> newMeta;
-        if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
-            if (newConfidence > *confidence) {
-                *mimeType = newMimeType;
-                *confidence = newConfidence;
-                *meta = newMeta;
-            }
-        }
-    }
-
-    return *confidence > 0.0;
-}
-
-// static
-void DataSource::RegisterSniffer_l(SnifferFunc func) {
-    for (List<SnifferFunc>::iterator it = gSniffers.begin();
-         it != gSniffers.end(); ++it) {
-        if (*it == func) {
-            return;
-        }
-    }
-
-    gSniffers.push_back(func);
-}
-
-// static
-void DataSource::RegisterDefaultSniffers() {
-    Mutex::Autolock autoLock(gSnifferMutex);
-    if (gSniffersRegistered) {
-        return;
-    }
-
-    RegisterSniffer_l(SniffMPEG4);
-    RegisterSniffer_l(SniffMatroska);
-    RegisterSniffer_l(SniffOgg);
-    RegisterSniffer_l(SniffWAV);
-    RegisterSniffer_l(SniffFLAC);
-    RegisterSniffer_l(SniffAMR);
-    RegisterSniffer_l(SniffMPEG2TS);
-    RegisterSniffer_l(SniffMP3);
-    RegisterSniffer_l(SniffAAC);
-    RegisterSniffer_l(SniffMPEG2PS);
-    if (getuid() == AID_MEDIA) {
-        // WVM only in the media server process
-        RegisterSniffer_l(SniffWVM);
-    }
-    RegisterSniffer_l(SniffMidi);
-
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("drm.service.enabled", value, NULL)
-            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
-        RegisterSniffer_l(SniffDRM);
-    }
-    gSniffersRegistered = true;
-}
-
 // static
 sp<DataSource> DataSource::CreateFromURI(
         const sp<IMediaHTTPService> &httpService,
@@ -200,14 +122,10 @@
         *contentType = "";
     }
 
-    bool isWidevine = !strncasecmp("widevine://", uri, 11);
-
     sp<DataSource> source;
     if (!strncasecmp("file://", uri, 7)) {
         source = new FileSource(uri + 7);
-    } else if (!strncasecmp("http://", uri, 7)
-            || !strncasecmp("https://", uri, 8)
-            || isWidevine) {
+    } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
         if (httpService == NULL) {
             ALOGE("Invalid http service!");
             return NULL;
@@ -222,14 +140,6 @@
             httpSource = new MediaHTTP(conn);
         }
 
-        String8 tmp;
-        if (isWidevine) {
-            tmp = String8("http://");
-            tmp.append(uri + 11);
-
-            uri = tmp.string();
-        }
-
         String8 cacheConfig;
         bool disconnectAtHighwatermark;
         KeyedVector<String8, String8> nonCacheSpecificHeaders;
@@ -246,20 +156,14 @@
             return NULL;
         }
 
-        if (!isWidevine) {
-            if (contentType != NULL) {
-                *contentType = httpSource->getMIMEType();
-            }
-
-            source = NuCachedSource2::Create(
-                    httpSource,
-                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
-                    disconnectAtHighwatermark);
-        } else {
-            // We do not want that prefetching, caching, datasource wrapper
-            // in the widevine:// case.
-            source = httpSource;
+        if (contentType != NULL) {
+            *contentType = httpSource->getMIMEType();
         }
+
+        source = NuCachedSource2::Create(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                disconnectAtHighwatermark);
     } else if (!strncasecmp("data:", uri, 5)) {
         source = DataURISource::Create(uri);
     } else {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 230a22b..f29f786 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1046,16 +1046,6 @@
     return OK;
 }
 
-status_t MediaCodec::getWidevineLegacyBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
-    sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
-    msg->setInt32("portIndex", kPortIndexInput);
-    msg->setPointer("buffers", buffers);
-    msg->setInt32("widevine", true);
-
-    sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
-}
-
 status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
@@ -2342,12 +2332,7 @@
         {
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
-            // Unfortunately widevine legacy source requires knowing all of the
-            // codec input buffers, so we have to provide them even in async mode.
-            int32_t widevine = 0;
-            msg->findInt32("widevine", &widevine);
-
-            if (!isExecuting() || ((mFlags & kFlagIsAsync) && !widevine)) {
+            if (!isExecuting() || (mFlags & kFlagIsAsync)) {
                 PostReplyWithError(replyID, INVALID_OPERATION);
                 break;
             } else if (mFlags & kFlagStickyError) {
@@ -2579,9 +2564,10 @@
 
         if (info->mNotify != NULL) {
             sp<AMessage> msg = info->mNotify;
-            info->mNotify = NULL;
-            msg->setObject("buffer", (portIndex == kPortIndexInput && mCrypto != NULL)
+            msg->setObject("buffer", (info->mSecureData != nullptr)
                     ? info->mSecureData : info->mData);
+            msg->setInt32("discarded", true);
+            info->mNotify = NULL;
             if (isReclaim && info->mOwnedByClient) {
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index f2fdbc9..9362a07 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -28,7 +28,6 @@
 #include "include/MPEG2PSExtractor.h"
 #include "include/MPEG2TSExtractor.h"
 #include "include/DRMExtractor.h"
-#include "include/WVMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
 #include "include/MidiExtractor.h"
@@ -151,15 +150,9 @@
         ALOGW("creating media extractor in calling process");
         return CreateFromService(source, mime);
     } else {
-        // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
-        // not the extractor process.
         String8 mime8;
         float confidence;
         sp<AMessage> meta;
-        if (SniffWVM(source, &mime8, &confidence, &meta) &&
-                !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            return new WVMExtractor(source);
-        }
 
         // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
         // process, not the extractor process.
@@ -192,14 +185,14 @@
         const sp<DataSource> &source, const char *mime) {
 
     ALOGV("MediaExtractor::CreateFromService %s", mime);
-    DataSource::RegisterDefaultSniffers();
+    RegisterDefaultSniffers();
 
     sp<AMessage> meta;
 
     String8 tmp;
     if (mime == NULL) {
         float confidence;
-        if (!source->sniff(&tmp, &confidence, &meta)) {
+        if (!sniff(source, &tmp, &confidence, &meta)) {
             ALOGV("FAILED to autodetect media content.");
 
             return NULL;
@@ -251,9 +244,6 @@
         ret = new MatroskaExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
         ret = new MPEG2TSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
-        // Return now.  WVExtractor should not have the DrmFlag set in the block below.
-        return new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
         ret = new AACExtractor(source, meta);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
@@ -273,4 +263,79 @@
     return ret;
 }
 
+Mutex MediaExtractor::gSnifferMutex;
+List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers;
+bool MediaExtractor::gSniffersRegistered = false;
+
+// static
+bool MediaExtractor::sniff(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
+    *mimeType = "";
+    *confidence = 0.0f;
+    meta->clear();
+
+    {
+        Mutex::Autolock autoLock(gSnifferMutex);
+        if (!gSniffersRegistered) {
+            return false;
+        }
+    }
+
+    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        String8 newMimeType;
+        float newConfidence;
+        sp<AMessage> newMeta;
+        if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
+            if (newConfidence > *confidence) {
+                *mimeType = newMimeType;
+                *confidence = newConfidence;
+                *meta = newMeta;
+            }
+        }
+    }
+
+    return *confidence > 0.0;
+}
+
+// static
+void MediaExtractor::RegisterSniffer_l(SnifferFunc func) {
+    for (List<SnifferFunc>::iterator it = gSniffers.begin();
+         it != gSniffers.end(); ++it) {
+        if (*it == func) {
+            return;
+        }
+    }
+
+    gSniffers.push_back(func);
+}
+
+// static
+void MediaExtractor::RegisterDefaultSniffers() {
+    Mutex::Autolock autoLock(gSnifferMutex);
+    if (gSniffersRegistered) {
+        return;
+    }
+
+    RegisterSniffer_l(SniffMPEG4);
+    RegisterSniffer_l(SniffMatroska);
+    RegisterSniffer_l(SniffOgg);
+    RegisterSniffer_l(SniffWAV);
+    RegisterSniffer_l(SniffFLAC);
+    RegisterSniffer_l(SniffAMR);
+    RegisterSniffer_l(SniffMPEG2TS);
+    RegisterSniffer_l(SniffMP3);
+    RegisterSniffer_l(SniffAAC);
+    RegisterSniffer_l(SniffMPEG2PS);
+    RegisterSniffer_l(SniffMidi);
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("drm.service.enabled", value, NULL)
+            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        RegisterSniffer_l(SniffDRM);
+    }
+    gSniffersRegistered = true;
+}
+
+
 }  // namespace android
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index e3270ed..6f8220f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -22,7 +22,6 @@
 
 #include "include/ESDS.h"
 #include "include/NuCachedSource2.h"
-#include "include/WVMExtractor.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -40,8 +39,7 @@
 namespace android {
 
 NuMediaExtractor::NuMediaExtractor()
-    : mIsWidevineExtractor(false),
-      mTotalBitrate(-1ll),
+    : mTotalBitrate(-1ll),
       mDurationUs(-1ll) {
 }
 
@@ -78,48 +76,15 @@
         return -ENOENT;
     }
 
-    mIsWidevineExtractor = false;
-    if (!strncasecmp("widevine://", path, 11)) {
-        String8 mimeType;
-        float confidence;
-        sp<AMessage> dummy;
-        bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
-
-        if (!success
-                || strcasecmp(
-                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
-            return ERROR_UNSUPPORTED;
-        }
-
-        sp<WVMExtractor> extractor = new WVMExtractor(dataSource);
-        extractor->setAdaptiveStreamingMode(true);
-
-        mImpl = extractor;
-        mIsWidevineExtractor = true;
-    } else {
-        mImpl = MediaExtractor::Create(dataSource);
-    }
+    mImpl = MediaExtractor::Create(dataSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
     }
 
     sp<MetaData> fileMeta = mImpl->getMetaData();
-    const char *containerMime;
-    if (fileMeta != NULL
-            && fileMeta->findCString(kKeyMIMEType, &containerMime)
-            && !strcasecmp(containerMime, "video/wvm")) {
-        // We always want to use "cryptoPluginMode" when using the wvm
-        // extractor. We can tell that it is this extractor by looking
-        // at the container mime type.
-        // The cryptoPluginMode ensures that the extractor will actually
-        // give us data in a call to MediaSource::read(), unlike its
-        // default mode that we used in AwesomePlayer.
-        // TODO: change default mode
-        static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
-    } else if (mImpl->getDrmFlag()) {
-        // For all other drm content, we don't want to expose decrypted
-        // content to Java application.
+    if (mImpl->getDrmFlag()) {
+        // Don't expose decrypted content to Java application
         mImpl.clear();
         mImpl = NULL;
         return ERROR_UNSUPPORTED;
@@ -633,15 +598,7 @@
     Mutex::Autolock autoLock(mLock);
 
     int64_t bitrate;
-    if (mIsWidevineExtractor) {
-        sp<WVMExtractor> wvmExtractor =
-            static_cast<WVMExtractor *>(mImpl.get());
-
-        status_t finalStatus;
-        *durationUs = wvmExtractor->getCachedDurationUs(&finalStatus);
-        *eos = (finalStatus != OK);
-        return true;
-    } else if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
+    if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
             && getTotalBitrate(&bitrate)) {
         sp<NuCachedSource2> cachedSource =
             static_cast<NuCachedSource2 *>(mDataSource.get());
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index d8fec5c..5e00c44 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -55,8 +55,6 @@
     : mParsedMetaData(false),
       mAlbumArt(NULL) {
     ALOGV("StagefrightMetadataRetriever()");
-
-    DataSource::RegisterDefaultSniffers();
 }
 
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
deleted file mode 100644
index d1b2f54..0000000
--- a/media/libstagefright/WVMExtractor.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2010 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 "WVMExtractor"
-#include <utils/Log.h>
-
-#include "include/WVMExtractor.h"
-
-#include <arpa/inet.h>
-#include <utils/String8.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <dlfcn.h>
-
-#include <utils/Errors.h>
-
-/* The extractor lifetime is short - just long enough to get
- * the media sources constructed - so the shared lib needs to remain open
- * beyond the lifetime of the extractor.  So keep the handle as a global
- * rather than a member of the extractor
- */
-void *gVendorLibHandle = NULL;
-
-namespace android {
-
-static Mutex gWVMutex;
-
-WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source)
-{
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!getVendorLibHandle()) {
-        return;
-    }
-
-    typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
-    GetInstanceFunc getInstanceFunc =
-        (GetInstanceFunc) dlsym(gVendorLibHandle,
-                "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
-
-    if (getInstanceFunc) {
-        if (source->DrmInitialization(
-                MEDIA_MIMETYPE_CONTAINER_WVM) != NULL) {
-            mImpl = (*getInstanceFunc)(source);
-            CHECK(mImpl != NULL);
-            setDrmFlag(true);
-        } else {
-            ALOGE("Drm manager failed to initialize.");
-        }
-    } else {
-        ALOGE("Failed to locate GetInstance in libwvm.so");
-    }
-}
-
-static void init_routine()
-{
-    gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
-    if (gVendorLibHandle == NULL) {
-        ALOGE("Failed to open libwvm.so: %s", dlerror());
-    }
-}
-
-bool WVMExtractor::getVendorLibHandle()
-{
-    static pthread_once_t sOnceControl = PTHREAD_ONCE_INIT;
-    pthread_once(&sOnceControl, init_routine);
-
-    return gVendorLibHandle != NULL;
-}
-
-WVMExtractor::~WVMExtractor() {
-}
-
-size_t WVMExtractor::countTracks() {
-    return (mImpl != NULL) ? mImpl->countTracks() : 0;
-}
-
-sp<IMediaSource> WVMExtractor::getTrack(size_t index) {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getTrack(index);
-}
-
-sp<MetaData> WVMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getTrackMetaData(index, flags);
-}
-
-sp<MetaData> WVMExtractor::getMetaData() {
-    if (mImpl == NULL) {
-        return NULL;
-    }
-    return mImpl->getMetaData();
-}
-
-int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
-    if (mImpl == NULL) {
-        return 0;
-    }
-
-    return mImpl->getCachedDurationUs(finalStatus);
-}
-
-status_t WVMExtractor::getEstimatedBandwidthKbps(int32_t *kbps) {
-    if (mImpl == NULL) {
-        return UNKNOWN_ERROR;
-    }
-
-    return mImpl->getEstimatedBandwidthKbps(kbps);
-}
-
-
-void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
-    if (mImpl != NULL) {
-        mImpl->setAdaptiveStreamingMode(adaptive);
-    }
-}
-
-void WVMExtractor::setCryptoPluginMode(bool cryptoPluginMode) {
-    if (mImpl != NULL) {
-        mImpl->setCryptoPluginMode(cryptoPluginMode);
-    }
-}
-
-void WVMExtractor::setUID(uid_t uid) {
-    if (mImpl != NULL) {
-        mImpl->setUID(uid);
-    }
-}
-
-status_t WVMExtractor::getError() {
-    if (mImpl == NULL) {
-       return UNKNOWN_ERROR;
-    }
-
-    return mImpl->getError();
-}
-
-void WVMExtractor::setError(status_t err) {
-    if (mImpl != NULL) {
-        mImpl->setError(err);
-    }
-}
-
-bool SniffWVM(
-    const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!WVMExtractor::getVendorLibHandle()) {
-        return false;
-    }
-
-    typedef WVMLoadableExtractor *(*SnifferFunc)(const sp<DataSource>&);
-    SnifferFunc snifferFunc =
-        (SnifferFunc) dlsym(gVendorLibHandle,
-                            "_ZN7android15IsWidevineMediaERKNS_2spINS_10DataSourceEEE");
-
-    if (snifferFunc) {
-        if ((*snifferFunc)(source)) {
-            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
-            *confidence = 10.0f;
-            return true;
-        }
-    } else {
-        ALOGE("IsWidevineMedia not found in libwvm.so");
-    }
-
-    return false;
-}
-
-} //namespace android
-
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index b2f4188..442a3ff 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -154,8 +154,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     for (int i = 1; i < argc; ++i) {
         scan(argv[i]);
     }
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
deleted file mode 100644
index 65cb99a..0000000
--- a/media/libstagefright/include/WVMExtractor.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 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 WVM_EXTRACTOR_H_
-
-#define WVM_EXTRACTOR_H_
-
-#include <media/stagefright/MediaExtractor.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-struct AMessage;
-class String8;
-class DataSource;
-
-class WVMLoadableExtractor : public MediaExtractor {
-public:
-    WVMLoadableExtractor() {}
-    virtual ~WVMLoadableExtractor() {}
-
-    virtual int64_t getCachedDurationUs(status_t *finalStatus) = 0;
-    virtual status_t getError() = 0;
-    virtual status_t getEstimatedBandwidthKbps(int32_t *kbps) = 0;
-    virtual void setAdaptiveStreamingMode(bool adaptive) = 0;
-    virtual void setCryptoPluginMode(bool cryptoPluginMode) = 0;
-    virtual void setError(status_t err) = 0;
-    virtual void setUID(uid_t uid) = 0;
-};
-
-class WVMExtractor : public MediaExtractor {
-public:
-    explicit WVMExtractor(const sp<DataSource> &source);
-
-    virtual size_t countTracks();
-    virtual sp<IMediaSource> getTrack(size_t index);
-    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
-    virtual sp<MetaData> getMetaData();
-    virtual void setUID(uid_t uid);
-
-    // Return the amount of data cached from the current
-    // playback positiion (in us).
-    // While more data is still being fetched *finalStatus == OK,
-    // Once fetching is completed (no more data available), *finalStatus != OK
-    // If fetching completed normally (i.e. reached EOS instead of IO error)
-    // *finalStatus == ERROR_END_OF_STREAM
-    int64_t getCachedDurationUs(status_t *finalStatus);
-
-    // Return the current estimated bandwidth
-    status_t getEstimatedBandwidthKbps(int32_t *kbps);
-
-    // Set to use adaptive streaming mode by the WV component.
-    // If adaptive == true, adaptive streaming mode will be used.
-    // Default mode is non-adaptive streaming mode.
-    // Should set to use adaptive streaming mode only if widevine:// protocol
-    // is used.
-    void setAdaptiveStreamingMode(bool adaptive);
-
-    // setCryptoPluginMode(true) to select crypto plugin mode.
-    // In this mode, the extractor returns encrypted data for use
-    // with the MediaCodec model, which handles the decryption in the
-    // codec.
-    void setCryptoPluginMode(bool cryptoPluginMode);
-
-    static bool getVendorLibHandle();
-
-    status_t getError();
-
-    void setError(status_t err);
-
-protected:
-    virtual ~WVMExtractor();
-
-private:
-    sp<DataSource> mDataSource;
-    sp<WVMLoadableExtractor> mImpl;
-
-    WVMExtractor(const WVMExtractor &);
-    WVMExtractor &operator=(const WVMExtractor &);
-};
-
-bool SniffWVM(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
-}  // namespace android
-
-#endif  // DRM_EXTRACTOR_H_
-
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 935d7bf..1ce5d1a 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -800,7 +800,6 @@
     using namespace android;
 
     android::ProcessState::self()->startThreadPool();
-    DataSource::RegisterDefaultSniffers();
 
     const char *me = argv[0];
 
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index 24f529b..e612a8d 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -37,8 +37,6 @@
 int main(int argc, char **argv) {
     android::ProcessState::self()->startThreadPool();
 
-    DataSource::RegisterDefaultSniffers();
-
     const char *rtpFilename = NULL;
     const char *rtcpFilename = NULL;
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 3587cb9..f1ecca0 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -36,7 +36,6 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/AudioSource.h>
-#include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
@@ -748,8 +747,6 @@
 
 status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer(
         bool enableAudio, bool enableVideo) {
-    DataSource::RegisterDefaultSniffers();
-
     mExtractor = new NuMediaExtractor;
 
     status_t err = mExtractor->setDataSource(
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 582a5e8..945f4b3 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1611,8 +1611,13 @@
         // in == NULL can happen if the track was flushed just after having
         // been enabled for mixing.
         if (in == NULL || (((uintptr_t)in) & 3)) {
-            memset(out, 0, numFrames
-                    * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat));
+            if ( AUDIO_FORMAT_PCM_FLOAT == t.mMixerFormat ) {
+                 memset((char*)fout, 0, numFrames
+                         * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat));
+            } else {
+                 memset((char*)out, 0, numFrames
+                         * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat));
+            }
             ALOGE_IF((((uintptr_t)in) & 3),
                     "process__OneTrack16BitsStereoNoResampling: misaligned buffer"
                     " %p track %d, channels %d, needs %08x, volume %08x vfl %f vfr %f",
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3a04651..ec9ced2 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1287,36 +1287,54 @@
         // particular client process:  no risk to block the whole media server process or mixer
         // threads if we are stuck here
         Mutex::Autolock _l(mCblk->lock);
-        if (mCblk->clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
-            mCblk->serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
+
+        // keep local copy of index in case of client corruption b/32220769
+        const uint32_t clientIndex = mCblk->clientIndex;
+        const uint32_t serverIndex = mCblk->serverIndex;
+        if (clientIndex > EFFECT_PARAM_BUFFER_SIZE ||
+            serverIndex > EFFECT_PARAM_BUFFER_SIZE) {
             mCblk->serverIndex = 0;
             mCblk->clientIndex = 0;
             return BAD_VALUE;
         }
         status_t status = NO_ERROR;
-        while (mCblk->serverIndex < mCblk->clientIndex) {
-            int reply;
-            uint32_t rsize = sizeof(int);
-            int *p = (int *)(mBuffer + mCblk->serverIndex);
-            int size = *p++;
-            if (((uint8_t *)p + size) > mBuffer + mCblk->clientIndex) {
+        effect_param_t *param = NULL;
+        for (uint32_t index = serverIndex; index < clientIndex;) {
+            int *p = (int *)(mBuffer + index);
+            const int size = *p++;
+            if (size < 0
+                    || size > EFFECT_PARAM_BUFFER_SIZE
+                    || ((uint8_t *)p + size) > mBuffer + clientIndex) {
                 ALOGW("command(): invalid parameter block size");
+                status = BAD_VALUE;
                 break;
             }
-            effect_param_t *param = (effect_param_t *)p;
-            if (param->psize == 0 || param->vsize == 0) {
-                ALOGW("command(): null parameter or value size");
-                mCblk->serverIndex += size;
-                continue;
+
+            // copy to local memory in case of client corruption b/32220769
+            param = (effect_param_t *)realloc(param, size);
+            if (param == NULL) {
+                ALOGW("command(): out of memory");
+                status = NO_MEMORY;
+                break;
             }
-            uint32_t psize = sizeof(effect_param_t) +
-                             ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
-                             param->vsize;
+            memcpy(param, p, size);
+
+            int reply = 0;
+            uint32_t rsize = sizeof(reply);
             status_t ret = mEffect->command(EFFECT_CMD_SET_PARAM,
-                                            psize,
-                                            p,
+                                            size,
+                                            param,
                                             &rsize,
                                             &reply);
+
+            // verify shared memory: server index shouldn't change; client index can't go back.
+            if (serverIndex != mCblk->serverIndex
+                    || clientIndex > mCblk->clientIndex) {
+                android_errorWriteLog(0x534e4554, "32220769");
+                status = BAD_VALUE;
+                break;
+            }
+
             // stop at first error encountered
             if (ret != NO_ERROR) {
                 status = ret;
@@ -1326,8 +1344,9 @@
                 *(int *)pReplyData = reply;
                 break;
             }
-            mCblk->serverIndex += size;
+            index += size;
         }
+        free(param);
         mCblk->serverIndex = 0;
         mCblk->clientIndex = 0;
         return status;
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 818da72..a224004 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -384,6 +384,7 @@
             sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
             if (source == NULL) {
                 ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
+                free(sourcesLiteral);
                 return BAD_VALUE;
             }
             sources.add(source);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5ef0216..a714041 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4477,9 +4477,7 @@
 
 bool AudioPolicyManager::streamsMatchForvolume(audio_stream_type_t stream1,
                                                audio_stream_type_t stream2) {
-    return ((stream1 == stream2) ||
-            ((stream1 == AUDIO_STREAM_ACCESSIBILITY) && (stream2 == AUDIO_STREAM_MUSIC)) ||
-            ((stream1 == AUDIO_STREAM_MUSIC) && (stream2 == AUDIO_STREAM_ACCESSIBILITY)));
+    return (stream1 == stream2);
 }
 
 uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index bcd62d6..bfbf640 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -993,7 +993,7 @@
 }
 
 status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
-    status_t res;
+    status_t res = OK;
 
     ALOGV("%s: state == %d, restart = %d", __FUNCTION__, params.state, restart);
 
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
index b4cda19..4344506 100644
--- a/services/radio/Android.mk
+++ b/services/radio/Android.mk
@@ -17,9 +17,8 @@
 include $(CLEAR_VARS)
 
 
-LOCAL_SRC_FILES:=               \
-    RadioService.cpp \
-    RadioHalLegacy.cpp
+LOCAL_SRC_FILES:= \
+    RadioService.cpp
 
 LOCAL_SHARED_LIBRARIES:= \
     liblog \
@@ -31,6 +30,26 @@
     libradio \
     libradio_metadata
 
+ifeq ($(ENABLE_TREBLE),true)
+# Treble configuration
+LOCAL_CFLAGS += -DENABLE_TREBLE
+LOCAL_SRC_FILES += \
+    HidlUtils.cpp \
+    RadioHalHidl.cpp
+
+LOCAL_SHARED_LIBRARIES += \
+    libhwbinder \
+    libhidlbase \
+    libhidltransport \
+    libbase \
+    android.hardware.broadcastradio@1.0
+else
+# libhardware configuration
+LOCAL_SRC_FILES +=               \
+    RadioHalLegacy.cpp
+endif
+
+
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/radio/HidlUtils.cpp b/services/radio/HidlUtils.cpp
new file mode 100644
index 0000000..bfced7a
--- /dev/null
+++ b/services/radio/HidlUtils.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "HidlUtils"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <system/radio_metadata.h>
+
+#include "HidlUtils.h"
+
+namespace android {
+
+using android::hardware::broadcastradio::V1_0::MetadataType;
+using android::hardware::broadcastradio::V1_0::Band;
+using android::hardware::broadcastradio::V1_0::Deemphasis;
+using android::hardware::broadcastradio::V1_0::Rds;
+
+//static
+int HidlUtils::convertHalResult(Result result)
+{
+    switch (result) {
+        case Result::OK:
+            return 0;
+        case Result::INVALID_ARGUMENTS:
+            return -EINVAL;
+        case Result::INVALID_STATE:
+            return -ENOSYS;
+        case Result::TIMEOUT:
+            return -ETIMEDOUT;
+        case Result::NOT_INITIALIZED:
+        default:
+            return -ENODEV;
+    }
+}
+
+
+//static
+void HidlUtils::convertBandConfigToHal(BandConfig *halConfig,
+                                       const radio_hal_band_config_t *config)
+{
+    halConfig->type = static_cast<Band>(config->type);
+    halConfig->antennaConnected = config->antenna_connected;
+    halConfig->lowerLimit = config->lower_limit;
+    halConfig->upperLimit = config->upper_limit;
+    halConfig->spacings.setToExternal(const_cast<unsigned int *>(&config->spacings[0]),
+                                       config->num_spacings * sizeof(uint32_t));
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    halConfig->spacings.resize(config->num_spacings);
+
+    if (halConfig->type == Band::FM) {
+        halConfig->ext.fm.deemphasis = static_cast<Deemphasis>(config->fm.deemphasis);
+        halConfig->ext.fm.stereo = config->fm.stereo;
+        halConfig->ext.fm.rds = static_cast<Rds>(config->fm.rds);
+        halConfig->ext.fm.ta = config->fm.ta;
+        halConfig->ext.fm.af = config->fm.af;
+        halConfig->ext.fm.ea = config->fm.ea;
+    } else {
+        halConfig->ext.am.stereo = config->am.stereo;
+    }
+}
+
+//static
+void HidlUtils::convertPropertiesFromHal(radio_hal_properties_t *properties,
+                                         const Properties *halProperties)
+{
+    properties->class_id = static_cast<radio_class_t>(halProperties->classId);
+    strlcpy(properties->implementor, halProperties->implementor.c_str(), RADIO_STRING_LEN_MAX);
+    strlcpy(properties->product, halProperties->product.c_str(), RADIO_STRING_LEN_MAX);
+    strlcpy(properties->version, halProperties->version.c_str(), RADIO_STRING_LEN_MAX);
+    strlcpy(properties->serial, halProperties->serial.c_str(), RADIO_STRING_LEN_MAX);
+    properties->num_tuners = halProperties->numTuners;
+    properties->num_audio_sources = halProperties->numAudioSources;
+    properties->supports_capture = halProperties->supportsCapture;
+    properties->num_bands = halProperties->bands.size();
+
+    for (size_t i = 0; i < halProperties->bands.size(); i++) {
+        convertBandConfigFromHal(&properties->bands[i], &halProperties->bands[i]);
+    }
+}
+
+//static
+void HidlUtils::convertBandConfigFromHal(radio_hal_band_config_t *config,
+                                         const BandConfig *halConfig)
+{
+    config->type = static_cast<radio_band_t>(halConfig->type);
+    config->antenna_connected = halConfig->antennaConnected;
+    config->lower_limit = halConfig->lowerLimit;
+    config->upper_limit = halConfig->upperLimit;
+    config->num_spacings = halConfig->spacings.size();
+    if (config->num_spacings > RADIO_NUM_SPACINGS_MAX) {
+        config->num_spacings = RADIO_NUM_SPACINGS_MAX;
+    }
+    memcpy(config->spacings, halConfig->spacings.data(),
+           sizeof(uint32_t) * config->num_spacings);
+
+    if (halConfig->type == Band::FM) {
+        config->fm.deemphasis = static_cast<radio_deemphasis_t>(halConfig->ext.fm.deemphasis);
+        config->fm.stereo = halConfig->ext.fm.stereo;
+        config->fm.rds = static_cast<radio_rds_t>(halConfig->ext.fm.rds);
+        config->fm.ta = halConfig->ext.fm.ta;
+        config->fm.af = halConfig->ext.fm.af;
+        config->fm.ea = halConfig->ext.fm.ea;
+    } else {
+        config->am.stereo = halConfig->ext.am.stereo;
+    }
+}
+
+
+//static
+void HidlUtils::convertProgramInfoFromHal(radio_program_info_t *info,
+                                          const ProgramInfo *halInfo,
+                                          bool withMetadata)
+{
+    info->channel = halInfo->channel;
+    info->sub_channel = halInfo->subChannel;
+    info->tuned = halInfo->tuned;
+    info->stereo = halInfo->stereo;
+    info->digital = halInfo->digital;
+    info->signal_strength = halInfo->signalStrength;
+    if (withMetadata && halInfo->metadata.size() != 0) {
+        convertMetaDataFromHal(&info->metadata, halInfo->metadata,
+                               halInfo->channel, halInfo->subChannel);
+    }
+}
+
+//static
+void HidlUtils::convertMetaDataFromHal(radio_metadata_t **metadata,
+                                       const hidl_vec<MetaData>& halMetadata,
+                                       uint32_t channel,
+                                       uint32_t subChannel)
+{
+
+    radio_metadata_allocate(metadata, channel, subChannel);
+    for (size_t i = 0; i < halMetadata.size(); i++) {
+        radio_metadata_key_t key = static_cast<radio_metadata_key_t>(halMetadata[i].key);
+        radio_metadata_type_t type = static_cast<radio_metadata_key_t>(halMetadata[i].type);
+        radio_metadata_clock_t clock;
+
+        switch (type) {
+        case RADIO_METADATA_TYPE_INT:
+            radio_metadata_add_int(metadata, key, halMetadata[i].intValue);
+            break;
+        case RADIO_METADATA_TYPE_TEXT:
+            radio_metadata_add_text(metadata, key, halMetadata[i].stringValue.c_str());
+            break;
+        case RADIO_METADATA_TYPE_RAW:
+            radio_metadata_add_raw(metadata, key,
+                                   halMetadata[i].rawValue.data(),
+                                   halMetadata[i].rawValue.size());
+            break;
+        case RADIO_METADATA_TYPE_CLOCK:
+            clock.utc_seconds_since_epoch =
+                    halMetadata[i].clockValue.utcSecondsSinceEpoch;
+            clock.timezone_offset_in_minutes =
+                    halMetadata[i].clockValue.timezoneOffsetInMinutes;
+            radio_metadata_add_clock(metadata, key, &clock);
+            break;
+        default:
+            ALOGW("%s invalid metadata type %u",__FUNCTION__, halMetadata[i].type);
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/services/radio/HidlUtils.h b/services/radio/HidlUtils.h
new file mode 100644
index 0000000..091abb7
--- /dev/null
+++ b/services/radio/HidlUtils.h
@@ -0,0 +1,51 @@
+/*
+ * 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_RADIO_HAL_HIDL_UTILS_H
+#define ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
+
+#include <android/hardware/broadcastradio/1.0/types.h>
+#include <hardware/radio.h>
+
+namespace android {
+
+using android::hardware::hidl_vec;
+using android::hardware::broadcastradio::V1_0::Result;
+using android::hardware::broadcastradio::V1_0::Properties;
+using android::hardware::broadcastradio::V1_0::BandConfig;
+using android::hardware::broadcastradio::V1_0::ProgramInfo;
+using android::hardware::broadcastradio::V1_0::MetaData;
+
+class HidlUtils {
+public:
+    static int convertHalResult(Result result);
+    static void convertBandConfigFromHal(radio_hal_band_config_t *config,
+                                         const BandConfig *halConfig);
+    static void convertPropertiesFromHal(radio_hal_properties_t *properties,
+                                         const Properties *halProperties);
+    static void convertBandConfigToHal(BandConfig *halConfig,
+                                       const radio_hal_band_config_t *config);
+    static void convertProgramInfoFromHal(radio_program_info_t *info,
+                                          const ProgramInfo *halInfo,
+                                          bool withMetadata);
+    static void convertMetaDataFromHal(radio_metadata_t **metadata,
+                                       const hidl_vec<MetaData>& halMetadata,
+                                       uint32_t channel,
+                                       uint32_t subChannel);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
new file mode 100644
index 0000000..07cb4d5
--- /dev/null
+++ b/services/radio/RadioHalHidl.cpp
@@ -0,0 +1,388 @@
+/*
+ * 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 "RadioHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <system/radio_metadata.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
+
+#include "RadioHalHidl.h"
+#include "HidlUtils.h"
+
+namespace android {
+
+using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
+using android::hardware::broadcastradio::V1_0::Class;
+using android::hardware::broadcastradio::V1_0::Direction;
+using android::hardware::broadcastradio::V1_0::Properties;
+
+
+/* static */
+sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
+{
+    return new RadioHalHidl(classId);
+}
+
+int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    sp<IBroadcastRadio> module = getService();
+    if (module == 0) {
+        return -ENODEV;
+    }
+    Properties halProperties;
+    Result halResult;
+    Return<void> hidlReturn =
+            module->getProperties([&](Result result, const Properties& properties) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        halProperties = properties;
+                    }
+                });
+
+    if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
+        clearService();
+        return -EPIPE;
+    }
+    if (halResult == Result::OK) {
+        HidlUtils::convertPropertiesFromHal(properties, &halProperties);
+    }
+    return HidlUtils::convertHalResult(halResult);
+}
+
+int RadioHalHidl::openTuner(const radio_hal_band_config_t *config,
+                            bool audio,
+                            sp<TunerCallbackInterface> callback,
+                            sp<TunerInterface>& tuner)
+{
+    sp<IBroadcastRadio> module = getService();
+    if (module == 0) {
+        return -ENODEV;
+    }
+    sp<Tuner> tunerImpl = new Tuner(callback, this);
+
+    BandConfig halConfig;
+    Result halResult;
+    sp<ITuner> halTuner;
+
+    HidlUtils::convertBandConfigToHal(&halConfig, config);
+    Return<void> hidlReturn =
+            module->openTuner(halConfig, audio, tunerImpl,
+                              [&](Result result, const sp<ITuner>& tuner) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        halTuner = tuner;
+                    }
+                });
+
+    if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
+        clearService();
+        return -EPIPE;
+    }
+    if (halResult == Result::OK) {
+        tunerImpl->setHalTuner(halTuner);
+        tuner = tunerImpl;
+    }
+
+    return HidlUtils::convertHalResult(halResult);
+}
+
+int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner)
+{
+    sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get());
+    sp<ITuner> clearTuner;
+    tunerImpl->setHalTuner(clearTuner);
+    return 0;
+}
+
+RadioHalHidl::RadioHalHidl(radio_class_t classId)
+    : mClassId(classId)
+{
+}
+
+RadioHalHidl::~RadioHalHidl()
+{
+}
+
+sp<IBroadcastRadio> RadioHalHidl::getService()
+{
+    if (mHalModule == 0) {
+        sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
+        if (factory != 0) {
+            factory->connectModule(static_cast<Class>(mClassId),
+                               [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
+                if (retval == Result::OK) {
+                    mHalModule = result;
+                }
+            });
+        }
+    }
+    ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get());
+    return mHalModule;
+}
+
+void RadioHalHidl::clearService()
+{
+    ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get());
+    mHalModule.clear();
+}
+
+
+int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    BandConfig halConfig;
+    HidlUtils::convertBandConfigToHal(&halConfig, config);
+
+    Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    BandConfig halConfig;
+    Result halResult;
+    Return<void> hidlReturn =
+            mHalTuner->getConfiguration([&](Result result, const BandConfig& config) {
+                    halResult = result;
+                    if (result == Result::OK) {
+                        halConfig = config;
+                    }
+                });
+    status_t status = checkHidlStatus(hidlReturn.getStatus());
+    if (status == NO_ERROR && halResult == Result::OK) {
+        HidlUtils::convertBandConfigFromHal(config, &halConfig);
+    }
+    return HidlUtils::convertHalResult(halResult);
+}
+
+int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult =
+            mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult =
+            mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult =
+            mHalTuner->tune(channel, sub_channel);
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::cancel()
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    Return<Result> hidlResult = mHalTuner->cancel();
+    checkHidlStatus(hidlResult.getStatus());
+    return HidlUtils::convertHalResult(hidlResult);
+}
+
+int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info)
+{
+    ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
+    if (mHalTuner == 0) {
+        return -ENODEV;
+    }
+    ProgramInfo halInfo;
+    Result halResult;
+    bool withMetaData = (info->metadata != NULL);
+    Return<void> hidlReturn = mHalTuner->getProgramInformation(
+                    withMetaData, [&](Result result, const ProgramInfo& info) {
+                        halResult = result;
+                        if (result == Result::OK) {
+                            halInfo = info;
+                        }
+    });
+    status_t status = checkHidlStatus(hidlReturn.getStatus());
+    if (status == NO_ERROR && halResult == Result::OK) {
+        HidlUtils::convertProgramInfoFromHal(info, &halInfo, withMetaData);
+    }
+    return HidlUtils::convertHalResult(halResult);
+}
+
+Return<void> RadioHalHidl::Tuner::hardwareFailure()
+{
+    ALOGV("%s IN", __FUNCTION__);
+    handleHwFailure();
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_CONFIG;
+    event.status = HidlUtils::convertHalResult(result);
+    HidlUtils::convertBandConfigFromHal(&event.config, &config);
+    onCallback(&event);
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_TUNED;
+    event.status = HidlUtils::convertHalResult(result);
+    HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
+    onCallback(&event);
+    if (event.info.metadata != NULL) {
+        radio_metadata_deallocate(event.info.metadata);
+    }
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_AF_SWITCH;
+    HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
+    onCallback(&event);
+    if (event.info.metadata != NULL) {
+        radio_metadata_deallocate(event.info.metadata);
+    }
+    return Return<void>();
+}
+
+Return<void> RadioHalHidl::Tuner::antennaStateChange(bool connected)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_ANTENNA;
+    event.on = connected;
+    onCallback(&event);
+    return Return<void>();
+}
+Return<void> RadioHalHidl::Tuner::trafficAnnouncement(bool active)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_TA;
+    event.on = active;
+    onCallback(&event);
+    return Return<void>();
+}
+Return<void> RadioHalHidl::Tuner::emergencyAnnouncement(bool active)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_EA;
+    event.on = active;
+    onCallback(&event);
+    return Return<void>();
+}
+Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
+                                          const ::android::hardware::hidl_vec<MetaData>& metadata)
+{
+    ALOGV("%s IN", __FUNCTION__);
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_METADATA;
+    HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
+    onCallback(&event);
+    if (event.metadata != NULL) {
+        radio_metadata_deallocate(event.info.metadata);
+    }
+    return Return<void>();
+}
+
+
+RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
+    : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
+{
+}
+
+
+RadioHalHidl::Tuner::~Tuner()
+{
+}
+
+void RadioHalHidl::Tuner::handleHwFailure()
+{
+    ALOGV("%s IN", __FUNCTION__);
+    sp<RadioHalHidl> parentModule = mParentModule.promote();
+    if (parentModule != 0) {
+        parentModule->clearService();
+    }
+    radio_hal_event_t event;
+    memset(&event, 0, sizeof(radio_hal_event_t));
+    event.type = RADIO_EVENT_HW_FAILURE;
+    onCallback(&event);
+    mHalTuner.clear();
+}
+
+status_t RadioHalHidl::Tuner::checkHidlStatus(Status hidlStatus)
+{
+    status_t status = hidlStatus.transactionError();
+    if (status == DEAD_OBJECT) {
+        handleHwFailure();
+    }
+    return status;
+}
+
+void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent)
+{
+    if (mCallback != 0) {
+        mCallback->onEvent(halEvent);
+    }
+}
+
+} // namespace android
diff --git a/services/radio/RadioHalHidl.h b/services/radio/RadioHalHidl.h
new file mode 100644
index 0000000..5211ee2
--- /dev/null
+++ b/services/radio/RadioHalHidl.h
@@ -0,0 +1,108 @@
+/*
+ * 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_RADIO_HAL_HIDL_H
+#define ANDROID_HARDWARE_RADIO_HAL_HIDL_H
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include "RadioInterface.h"
+#include "TunerInterface.h"
+#include "TunerCallbackInterface.h"
+#include <android/hardware/broadcastradio/1.0/types.h>
+#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.0/ITuner.h>
+#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
+
+namespace android {
+
+using android::hardware::Status;
+using android::hardware::Return;
+using android::hardware::broadcastradio::V1_0::Result;
+using android::hardware::broadcastradio::V1_0::IBroadcastRadio;
+using android::hardware::broadcastradio::V1_0::ITuner;
+using android::hardware::broadcastradio::V1_0::ITunerCallback;
+
+using android::hardware::broadcastradio::V1_0::BandConfig;
+using android::hardware::broadcastradio::V1_0::ProgramInfo;
+using android::hardware::broadcastradio::V1_0::MetaData;
+
+class RadioHalHidl : public RadioInterface
+{
+public:
+                    RadioHalHidl(radio_class_t classId);
+
+                    // RadioInterface
+        virtual int getProperties(radio_hal_properties_t *properties);
+        virtual int openTuner(const radio_hal_band_config_t *config,
+                              bool audio,
+                              sp<TunerCallbackInterface> callback,
+                              sp<TunerInterface>& tuner);
+        virtual int closeTuner(sp<TunerInterface>& tuner);
+
+        class Tuner  : public TunerInterface, public virtual ITunerCallback
+        {
+        public:
+                        Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module);
+
+                        // TunerInterface
+            virtual int setConfiguration(const radio_hal_band_config_t *config);
+            virtual int getConfiguration(radio_hal_band_config_t *config);
+            virtual int scan(radio_direction_t direction, bool skip_sub_channel);
+            virtual int step(radio_direction_t direction, bool skip_sub_channel);
+            virtual int tune(unsigned int channel, unsigned int sub_channel);
+            virtual int cancel();
+            virtual int getProgramInformation(radio_program_info_t *info);
+
+                        // ITunerCallback
+            virtual Return<void> hardwareFailure();
+            virtual Return<void> configChange(Result result, const BandConfig& config);
+            virtual Return<void> tuneComplete(Result result, const ProgramInfo& info);
+            virtual Return<void> afSwitch(const ProgramInfo& info);
+            virtual Return<void> antennaStateChange(bool connected);
+            virtual Return<void> trafficAnnouncement(bool active);
+            virtual Return<void> emergencyAnnouncement(bool active);
+            virtual Return<void> newMetadata(uint32_t channel, uint32_t subChannel,
+                                         const ::android::hardware::hidl_vec<MetaData>& metadata);
+
+            void setHalTuner(sp<ITuner>& halTuner) { mHalTuner = halTuner; }
+            sp<ITuner> getHalTuner() { return mHalTuner; }
+
+        private:
+            virtual          ~Tuner();
+
+                    void     onCallback(radio_hal_event_t *halEvent);
+                    void     handleHwFailure();
+                    status_t checkHidlStatus(Status hidlStatus);
+
+            sp<ITuner> mHalTuner;
+            sp<TunerCallbackInterface>  mCallback;
+            wp<RadioHalHidl> mParentModule;
+        };
+
+        sp<IBroadcastRadio> getService();
+        void clearService();
+
+private:
+        virtual         ~RadioHalHidl();
+
+                radio_class_t mClassId;
+                sp<IBroadcastRadio> mHalModule;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_RADIO_HAL_HIDL_H