Merge "Add template class StateQueue"
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 8ba0203..746f506 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -34,21 +34,7 @@
 static Vector<uid_t> trustedUids;
 
 static bool isProtectedCallAllowed() {
-    // TODO
-    // Following implementation is just for reference.
-    // Each OEM manufacturer should implement/replace with their own solutions.
-    bool result = false;
-
-    IPCThreadState* ipcState = IPCThreadState::self();
-    uid_t uid = ipcState->getCallingUid();
-
-    for (unsigned int i = 0; i < trustedUids.size(); ++i) {
-        if (trustedUids[i] == uid) {
-            result = true;
-            break;
-        }
-    }
-    return result;
+    return true;
 }
 
 void DrmManagerService::instantiate() {
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
index e3ca536..1c5fd36 100644
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ b/include/media/stagefright/timedtext/TimedTextDriver.h
@@ -40,18 +40,24 @@
 
     status_t start();
     status_t pause();
-    status_t selectTrack(int32_t index);
-    status_t unselectTrack(int32_t index);
+    status_t selectTrack(size_t index);
+    status_t unselectTrack(size_t index);
 
     status_t seekToAsync(int64_t timeUs);
 
-    status_t addInBandTextSource(const sp<MediaSource>& source);
-    status_t addOutOfBandTextSource(const char *uri, const char *mimeType);
+    status_t addInBandTextSource(
+            size_t trackIndex, const sp<MediaSource>& source);
+
+    status_t addOutOfBandTextSource(
+            size_t trackIndex, const char *uri, const char *mimeType);
+
     // Caller owns the file desriptor and caller is responsible for closing it.
     status_t addOutOfBandTextSource(
-            int fd, off64_t offset, off64_t length, const char *mimeType);
+            size_t trackIndex, int fd, off64_t offset,
+            off64_t length, const char *mimeType);
 
-    void getTrackInfo(Parcel *parcel);
+    void getExternalTrackInfo(Parcel *parcel);
+    size_t countExternalTracks() const;
 
 private:
     Mutex mLock;
@@ -68,13 +74,17 @@
 
     // Variables to be guarded by mLock.
     State mState;
-    int32_t mCurrentTrackIndex;
-    Vector<sp<TimedTextSource> > mTextSourceVector;
+    size_t mCurrentTrackIndex;
+    KeyedVector<size_t, sp<TimedTextSource> > mTextSourceVector;
+    Vector<bool> mTextSourceTypeVector;
+
     // -- End of variables to be guarded by mLock
 
-    status_t selectTrack_l(int32_t index);
+    status_t selectTrack_l(size_t index);
+
     status_t createOutOfBandTextSource(
-            const char *mimeType, const sp<DataSource>& dataSource);
+            size_t trackIndex, const char* mimeType,
+            const sp<DataSource>& dataSource);
 
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
 };
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 4491f2b..574ae71 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -32,6 +32,7 @@
 Crypto::Crypto()
     : mInitCheck(NO_INIT),
       mLibHandle(NULL),
+      mFactory(NULL),
       mPlugin(NULL) {
     mInitCheck = init();
 }
@@ -57,6 +58,8 @@
     mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
 
     if (mLibHandle == NULL) {
+        ALOGE("Unable to locate libdrmdecrypt.so");
+
         return ERROR_UNSUPPORTED;
     }
 
@@ -66,6 +69,12 @@
 
     if (createCryptoFactory == NULL
             || ((mFactory = createCryptoFactory()) == NULL)) {
+        if (createCryptoFactory == NULL) {
+            ALOGE("Unable to find symbol 'createCryptoFactory'.");
+        } else {
+            ALOGE("createCryptoFactory() failed.");
+        }
+
         dlclose(mLibHandle);
         mLibHandle = NULL;
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 120a410..b67476b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -356,6 +356,7 @@
 
     int64_t totalBitRate = 0;
 
+    mExtractor = extractor;
     for (size_t i = 0; i < extractor->countTracks(); ++i) {
         sp<MetaData> meta = extractor->getTrackMetaData(i);
 
@@ -443,7 +444,7 @@
                 }
             }
         } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
-            addTextSource(extractor->getTrack(i));
+            addTextSource(i, extractor->getTrack(i));
         }
     }
 
@@ -507,6 +508,7 @@
     mCachedSource.clear();
     mAudioTrack.clear();
     mVideoTrack.clear();
+    mExtractor.clear();
 
     // Shutdown audio first, so that the respone to the reset request
     // appears to happen instantaneously as far as the user is concerned
@@ -1331,7 +1333,7 @@
     mAudioTrack = source;
 }
 
-void AwesomePlayer::addTextSource(const sp<MediaSource>& source) {
+void AwesomePlayer::addTextSource(size_t trackIndex, const sp<MediaSource>& source) {
     Mutex::Autolock autoLock(mTimedTextLock);
     CHECK(source != NULL);
 
@@ -1339,7 +1341,7 @@
         mTextDriver = new TimedTextDriver(mListener);
     }
 
-    mTextDriver->addInBandTextSource(source);
+    mTextDriver->addInBandTextSource(trackIndex, source);
 }
 
 status_t AwesomePlayer::initAudioDecoder() {
@@ -2254,6 +2256,94 @@
     }
 }
 
+status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
+    Mutex::Autolock autoLock(mTimedTextLock);
+    if (mTextDriver == NULL) {
+        return INVALID_OPERATION;
+    }
+
+    reply->writeInt32(mTextDriver->countExternalTracks() +
+                mExtractor->countTracks());
+    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+
+        const char *_mime;
+        CHECK(meta->findCString(kKeyMIMEType, &_mime));
+
+        String8 mime = String8(_mime);
+
+        reply->writeInt32(2); // 2 fields
+
+        if (!strncasecmp(mime.string(), "video/", 6)) {
+            reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
+        } else if (!strncasecmp(mime.string(), "audio/", 6)) {
+            reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
+        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
+            reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
+        } else {
+            reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
+        }
+
+        const char *lang;
+        if (meta->findCString(kKeyMediaLanguage, &lang)) {
+            reply->writeString16(String16(lang));
+        } else {
+            reply->writeString16(String16(""));
+        }
+    }
+
+    mTextDriver->getExternalTrackInfo(reply);
+    return OK;
+}
+
+// FIXME:
+// At present, only timed text track is able to be selected or unselected.
+status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
+    Mutex::Autolock autoLock(mTimedTextLock);
+    if (mTextDriver == NULL) {
+        return INVALID_OPERATION;
+    }
+
+    if (trackIndex >= mExtractor->countTracks()
+                + mTextDriver->countExternalTracks()) {
+        return BAD_VALUE;
+    }
+
+    if (trackIndex < mExtractor->countTracks()) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
+        const char *_mime;
+        CHECK(meta->findCString(kKeyMIMEType, &_mime));
+        String8 mime = String8(_mime);
+
+        if (strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
+            return ERROR_UNSUPPORTED;
+        }
+    }
+
+    status_t err = OK;
+    if (select) {
+        err = mTextDriver->selectTrack(trackIndex);
+        if (err == OK) {
+            modifyFlags(TEXTPLAYER_INITIALIZED, SET);
+            if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
+                mTextDriver->start();
+                modifyFlags(TEXT_RUNNING, SET);
+            }
+        }
+    } else {
+        err = mTextDriver->unselectTrack(trackIndex);
+        if (err == OK) {
+            modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
+            modifyFlags(TEXT_RUNNING, CLEAR);
+        }
+    }
+    return err;
+}
+
+size_t AwesomePlayer::countTracks() const {
+    return mExtractor->countTracks() + mTextDriver->countExternalTracks();
+}
+
 status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
     if (NULL == reply) {
         return android::BAD_VALUE;
@@ -2266,12 +2356,7 @@
     switch(methodId) {
         case INVOKE_ID_GET_TRACK_INFO:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextDriver == NULL) {
-                return INVALID_OPERATION;
-            }
-            mTextDriver->getTrackInfo(reply);
-            return OK;
+            return getTrackInfo(reply);
         }
         case INVOKE_ID_ADD_EXTERNAL_SOURCE:
         {
@@ -2282,7 +2367,8 @@
             // String values written in Parcel are UTF-16 values.
             String8 uri(request.readString16());
             String8 mimeType(request.readString16());
-            return mTextDriver->addOutOfBandTextSource(uri, mimeType);
+            size_t nTracks = countTracks();
+            return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
         }
         case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
         {
@@ -2294,40 +2380,19 @@
             off64_t offset = request.readInt64();
             off64_t length  = request.readInt64();
             String8 mimeType(request.readString16());
+            size_t nTracks = countTracks();
             return mTextDriver->addOutOfBandTextSource(
-                    fd, offset, length, mimeType);
+                    nTracks, fd, offset, length, mimeType);
         }
         case INVOKE_ID_SELECT_TRACK:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextDriver == NULL) {
-                return INVALID_OPERATION;
-            }
-
-            status_t err = mTextDriver->selectTrack(
-                    request.readInt32());
-            if (err == OK) {
-                modifyFlags(TEXTPLAYER_INITIALIZED, SET);
-                if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
-                    mTextDriver->start();
-                    modifyFlags(TEXT_RUNNING, SET);
-                }
-            }
-            return err;
+            int trackIndex = request.readInt32();
+            return selectTrack(trackIndex, true);
         }
         case INVOKE_ID_UNSELECT_TRACK:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextDriver == NULL) {
-                return INVALID_OPERATION;
-            }
-            status_t err = mTextDriver->unselectTrack(
-                    request.readInt32());
-            if (err == OK) {
-                modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
-                modifyFlags(TEXT_RUNNING, CLEAR);
-            }
-            return err;
+            int trackIndex = request.readInt32();
+            return selectTrack(trackIndex, false);
         }
         default:
         {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index aba95bc..3400724 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -133,27 +133,45 @@
 // static
 sp<DataSource> DataSource::CreateFromURI(
         const char *uri, const KeyedVector<String8, String8> *headers) {
+    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)) {
+            || !strncasecmp("https://", uri, 8)
+            || isWidevine) {
         sp<HTTPBase> httpSource = HTTPBase::Create();
+
+        String8 tmp;
+        if (isWidevine) {
+            tmp = String8("http://");
+            tmp.append(uri + 11);
+
+            uri = tmp.string();
+        }
+
         if (httpSource->connect(uri, headers) != OK) {
             return NULL;
         }
 
-        String8 cacheConfig;
-        bool disconnectAtHighwatermark;
-        if (headers != NULL) {
-            KeyedVector<String8, String8> copy = *headers;
-            NuCachedSource2::RemoveCacheSpecificHeaders(
-                    &copy, &cacheConfig, &disconnectAtHighwatermark);
-        }
+        if (!isWidevine) {
+            String8 cacheConfig;
+            bool disconnectAtHighwatermark;
+            if (headers != NULL) {
+                KeyedVector<String8, String8> copy = *headers;
+                NuCachedSource2::RemoveCacheSpecificHeaders(
+                        &copy, &cacheConfig, &disconnectAtHighwatermark);
+            }
 
-        source = new NuCachedSource2(
-                httpSource,
-                cacheConfig.isEmpty() ? NULL : cacheConfig.string());
+            source = new NuCachedSource2(
+                    httpSource,
+                    cacheConfig.isEmpty() ? NULL : cacheConfig.string());
+        } else {
+            // We do not want that prefetching, caching, datasource wrapper
+            // in the widevine:// case.
+            source = httpSource;
+        }
 
 # if CHROMIUM_AVAILABLE
     } else if (!strncasecmp("data:", uri, 5)) {
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 8758c93..166a99f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -21,6 +21,7 @@
 #include <media/stagefright/NuMediaExtractor.h>
 
 #include "include/ESDS.h"
+#include "include/WVMExtractor.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -58,13 +59,32 @@
         return -EINVAL;
     }
 
-    sp<DataSource> dataSource = DataSource::CreateFromURI(path, headers);
+    sp<DataSource> dataSource =
+        DataSource::CreateFromURI(path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
     }
 
-    mImpl = MediaExtractor::Create(dataSource);
+    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;
+    } else {
+        mImpl = MediaExtractor::Create(dataSource);
+    }
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -409,7 +429,13 @@
 }
 
 status_t NuMediaExtractor::seekTo(int64_t timeUs) {
-    return fetchTrackSamples(timeUs);
+    ssize_t minIndex = fetchTrackSamples(timeUs);
+
+    if (minIndex < 0) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    return OK;
 }
 
 status_t NuMediaExtractor::advance() {
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index dac8106..effe336 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -59,10 +59,14 @@
                 "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
 
     if (getInstanceFunc) {
-        CHECK(source->DrmInitialization(MEDIA_MIMETYPE_CONTAINER_WVM) != NULL);
-        mImpl = (*getInstanceFunc)(source);
-        CHECK(mImpl != NULL);
-        setDrmFlag(true);
+        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");
     }
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 06e9468..9115f91 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -235,6 +235,7 @@
     mutable Mutex mTimedTextLock;
 
     sp<WVMExtractor> mWVMExtractor;
+    sp<MediaExtractor> mExtractor;
 
     status_t setDataSource_l(
             const char *uri,
@@ -257,7 +258,7 @@
     void setVideoSource(sp<MediaSource> source);
     status_t initVideoDecoder(uint32_t flags = 0);
 
-    void addTextSource(const sp<MediaSource>& source);
+    void addTextSource(size_t trackIndex, const sp<MediaSource>& source);
 
     void onStreamDone();
 
@@ -318,6 +319,14 @@
         Vector<TrackStat> mTracks;
     } mStats;
 
+    status_t getTrackInfo(Parcel* reply) const;
+
+    // when select is true, the given track is selected.
+    // otherwise, the given track is unselected.
+    status_t selectTrack(size_t trackIndex, bool select);
+
+    size_t countTracks() const;
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index a99d882..e26f517 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -52,16 +52,13 @@
 
 TimedTextDriver::~TimedTextDriver() {
     mTextSourceVector.clear();
+    mTextSourceTypeVector.clear();
     mLooper->stop();
 }
 
-status_t TimedTextDriver::selectTrack_l(int32_t index) {
-    if (index >= (int)(mTextSourceVector.size())) {
-        return BAD_VALUE;
-    }
-
+status_t TimedTextDriver::selectTrack_l(size_t index) {
     sp<TimedTextSource> source;
-    source = mTextSourceVector.itemAt(index);
+    source = mTextSourceVector.valueFor(index);
     mPlayer->setDataSource(source);
     if (mState == UNINITIALIZED) {
         mState = PAUSED;
@@ -108,7 +105,7 @@
     return OK;
 }
 
-status_t TimedTextDriver::selectTrack(int32_t index) {
+status_t TimedTextDriver::selectTrack(size_t index) {
     status_t ret = OK;
     Mutex::Autolock autoLock(mLock);
     switch (mState) {
@@ -130,7 +127,7 @@
     return ret;
 }
 
-status_t TimedTextDriver::unselectTrack(int32_t index) {
+status_t TimedTextDriver::unselectTrack(size_t index) {
     if (mCurrentTrackIndex != index) {
         return INVALID_OPERATION;
     }
@@ -149,19 +146,21 @@
 }
 
 status_t TimedTextDriver::addInBandTextSource(
-        const sp<MediaSource>& mediaSource) {
+        size_t trackIndex, const sp<MediaSource>& mediaSource) {
     sp<TimedTextSource> source =
             TimedTextSource::CreateTimedTextSource(mediaSource);
     if (source == NULL) {
         return ERROR_UNSUPPORTED;
     }
     Mutex::Autolock autoLock(mLock);
-    mTextSourceVector.add(source);
+    mTextSourceVector.add(trackIndex, source);
+    mTextSourceTypeVector.add(true);
     return OK;
 }
 
 status_t TimedTextDriver::addOutOfBandTextSource(
-        const char *uri, const char *mimeType) {
+        size_t trackIndex, const char *uri, const char *mimeType) {
+
     // To support local subtitle file only for now
     if (strncasecmp("file://", uri, 7)) {
         ALOGE("uri('%s') is not a file", uri);
@@ -170,11 +169,11 @@
 
     sp<DataSource> dataSource =
             DataSource::CreateFromURI(uri);
-    return createOutOfBandTextSource(mimeType, dataSource);
+    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
 }
 
 status_t TimedTextDriver::addOutOfBandTextSource(
-        int fd, off64_t offset, off64_t length, const char *mimeType) {
+        size_t trackIndex, int fd, off64_t offset, off64_t length, const char *mimeType) {
 
     if (fd < 0) {
         ALOGE("Invalid file descriptor: %d", fd);
@@ -182,11 +181,13 @@
     }
 
     sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
-    return createOutOfBandTextSource(mimeType, dataSource);
+    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
 }
 
 status_t TimedTextDriver::createOutOfBandTextSource(
-        const char *mimeType, const sp<DataSource>& dataSource) {
+        size_t trackIndex,
+        const char *mimeType,
+        const sp<DataSource>& dataSource) {
 
     if (dataSource == NULL) {
         return ERROR_UNSUPPORTED;
@@ -199,28 +200,40 @@
     }
 
     if (source == NULL) {
+        ALOGE("Failed to create timed text source");
         return ERROR_UNSUPPORTED;
     }
 
     Mutex::Autolock autoLock(mLock);
-    mTextSourceVector.add(source);
+    mTextSourceVector.add(trackIndex, source);
+    mTextSourceTypeVector.add(false);
     return OK;
 }
 
-void TimedTextDriver::getTrackInfo(Parcel *parcel) {
+size_t TimedTextDriver::countExternalTracks() const {
+    size_t nTracks = 0;
+    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
+        if (!mTextSourceTypeVector[i]) {
+            ++nTracks;
+        }
+    }
+    return nTracks;
+}
+
+void TimedTextDriver::getExternalTrackInfo(Parcel *parcel) {
     Mutex::Autolock autoLock(mLock);
-    Vector<sp<TimedTextSource> >::const_iterator iter;
-    parcel->writeInt32(mTextSourceVector.size());
-    for (iter = mTextSourceVector.begin();
-         iter != mTextSourceVector.end(); ++iter) {
-        sp<MetaData> meta = (*iter)->getFormat();
+    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
+        if (mTextSourceTypeVector[i]) {
+            continue;
+        }
+
+        sp<MetaData> meta = mTextSourceVector.valueAt(i)->getFormat();
 
         // There are two fields.
         parcel->writeInt32(2);
 
         // track type.
         parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
-
         const char *lang = "und";
         if (meta != NULL) {
             meta->findCString(kKeyMediaLanguage, &lang);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d0611b0..d42ac8c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -138,25 +138,31 @@
 }
 #endif
 
-static int load_audio_interface(const char *if_name, const hw_module_t **mod,
-                                audio_hw_device_t **dev)
+static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
 {
+    const hw_module_t *mod;
     int rc;
 
-    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, mod);
-    if (rc)
+    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
+    ALOGE_IF(rc, "%s couldn't load audio hw module %s.%s (%s)", __func__,
+                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+    if (rc) {
         goto out;
-
-    rc = audio_hw_device_open(*mod, dev);
-    ALOGE_IF(rc, "couldn't open audio hw device in %s.%s (%s)",
-            AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
-    if (rc)
+    }
+    rc = audio_hw_device_open(mod, dev);
+    ALOGE_IF(rc, "%s couldn't open audio hw device in %s.%s (%s)", __func__,
+                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+    if (rc) {
         goto out;
-
+    }
+    if ((*dev)->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) {
+        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
+        rc = BAD_VALUE;
+        goto out;
+    }
     return 0;
 
 out:
-    *mod = NULL;
     *dev = NULL;
     return rc;
 }
@@ -914,7 +920,12 @@
 
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
-    size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+    struct audio_config config = {
+        sample_rate: sampleRate,
+        channel_mask: audio_channel_in_mask_from_count(channelCount),
+        format: format,
+    };
+    size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, &config);
     mHardwareStatus = AUDIO_HW_IDLE;
     return size;
 }
@@ -5743,10 +5754,9 @@
         }
     }
 
-    const hw_module_t *mod;
     audio_hw_device_t *dev;
 
-    int rc = load_audio_interface(name, &mod, &dev);
+    int rc = load_audio_interface(name, &dev);
     if (rc) {
         ALOGI("loadHwModule() error %d loading module %s ", rc, name);
         return 0;
@@ -5772,7 +5782,7 @@
     mAudioHwDevs.add(handle, new AudioHwDevice(name, dev));
 
     ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
-          name, mod->name, mod->id, handle);
+          name, dev->common.module->name, dev->common.module->id, handle);
 
     return handle;
 
@@ -5788,19 +5798,20 @@
 {
     status_t status;
     PlaybackThread *thread = NULL;
-    uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
-    audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
-    uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
-    audio_stream_out_t *outStream;
+    struct audio_config config = {
+        sample_rate: pSamplingRate ? *pSamplingRate : 0,
+        channel_mask: pChannelMask ? *pChannelMask : 0,
+        format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT,
+    };
+    audio_stream_out_t *outStream = NULL;
     audio_hw_device_t *outHwDev;
 
     ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
               module,
               (pDevices != NULL) ? (int)*pDevices : 0,
-              samplingRate,
-              format,
-              channelMask,
+              config.sample_rate,
+              config.format,
+              config.channel_mask,
               flags);
 
     if (pDevices == NULL || *pDevices == 0) {
@@ -5813,24 +5824,31 @@
     if (outHwDev == NULL)
         return 0;
 
+    audio_io_handle_t id = nextUniqueId();
+
     mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
-    status = outHwDev->open_output_stream(outHwDev, *pDevices, &format,
-                                          &channelMask, &samplingRate, &outStream);
+
+    status = outHwDev->open_output_stream(outHwDev,
+                                          id,
+                                          *pDevices,
+                                          (audio_output_flags_t)flags,
+                                          &config,
+                                          &outStream);
+
     mHardwareStatus = AUDIO_HW_IDLE;
     ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
             outStream,
-            samplingRate,
-            format,
-            channelMask,
+            config.sample_rate,
+            config.format,
+            config.channel_mask,
             status);
 
-    if (outStream != NULL) {
+    if (status == NO_ERROR && outStream != NULL) {
         AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
-        audio_io_handle_t id = nextUniqueId();
 
         if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
-            (format != AUDIO_FORMAT_PCM_16_BIT) ||
-            (channelMask != AUDIO_CHANNEL_OUT_STEREO)) {
+            (config.format != AUDIO_FORMAT_PCM_16_BIT) ||
+            (config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
             thread = new DirectOutputThread(this, output, id, *pDevices);
             ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
         } else {
@@ -5839,9 +5857,9 @@
         }
         mPlaybackThreads.add(id, thread);
 
-        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
-        if (pFormat != NULL) *pFormat = format;
-        if (pChannelMask != NULL) *pChannelMask = channelMask;
+        if (pSamplingRate != NULL) *pSamplingRate = config.sample_rate;
+        if (pFormat != NULL) *pFormat = config.format;
+        if (pChannelMask != NULL) *pChannelMask = config.channel_mask;
         if (pLatencyMs != NULL) *pLatencyMs = thread->latency();
 
         // notify client processes of the new output creation
@@ -5995,13 +6013,15 @@
 {
     status_t status;
     RecordThread *thread = NULL;
-    uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
-    audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
-    uint32_t reqSamplingRate = samplingRate;
-    audio_format_t reqFormat = format;
-    audio_channel_mask_t reqChannels = channelMask;
-    audio_stream_in_t *inStream;
+    struct audio_config config = {
+        sample_rate: pSamplingRate ? *pSamplingRate : 0,
+        channel_mask: pChannelMask ? *pChannelMask : 0,
+        format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT,
+    };
+    uint32_t reqSamplingRate = config.sample_rate;
+    audio_format_t reqFormat = config.format;
+    audio_channel_mask_t reqChannels = config.channel_mask;
+    audio_stream_in_t *inStream = NULL;
     audio_hw_device_t *inHwDev;
 
     if (pDevices == NULL || *pDevices == 0) {
@@ -6014,35 +6034,32 @@
     if (inHwDev == NULL)
         return 0;
 
-    status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                        &channelMask, &samplingRate,
-                                        (audio_in_acoustics_t)0,
+    audio_io_handle_t id = nextUniqueId();
+
+    status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config,
                                         &inStream);
     ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d",
             inStream,
-            samplingRate,
-            format,
-            channelMask,
+            config.sample_rate,
+            config.format,
+            config.channel_mask,
             status);
 
     // If the input could not be opened with the requested parameters and we can handle the conversion internally,
     // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
     // or stereo to mono conversions on 16 bit PCM inputs.
-    if (inStream == NULL && status == BAD_VALUE &&
-        reqFormat == format && format == AUDIO_FORMAT_PCM_16_BIT &&
-        (samplingRate <= 2 * reqSamplingRate) &&
-        (popcount(channelMask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+    if (status == BAD_VALUE &&
+        reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
+        (config.sample_rate <= 2 * reqSamplingRate) &&
+        (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
         ALOGV("openInput() reopening with proposed sampling rate and channels");
-        status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                            &channelMask, &samplingRate,
-                                            (audio_in_acoustics_t)0,
-                                            &inStream);
+        inStream = NULL;
+        status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, &inStream);
     }
 
-    if (inStream != NULL) {
+    if (status == NO_ERROR && inStream != NULL) {
         AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
 
-        audio_io_handle_t id = nextUniqueId();
         // Start record thread
         // RecorThread require both input and output device indication to forward to audio
         // pre processing modules
@@ -6056,7 +6073,7 @@
         mRecordThreads.add(id, thread);
         ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate != NULL) *pSamplingRate = reqSamplingRate;
-        if (pFormat != NULL) *pFormat = format;
+        if (pFormat != NULL) *pFormat = config.format;
         if (pChannelMask != NULL) *pChannelMask = reqChannels;
 
         input->stream->common.standby(&input->stream->common);