Bug 3329759 Implement streamInformation and volume in OpenMAX AL

- Implement StreamInformation for video size notification.
- Implement the XAVolumeItf for volume control
- Fix bug in GUID -> MPH hash.
- Fixed typo in GenericPlayer::pause() log
- Do not signal a discontinuity automatically when the ABQ is
  cleared because clearing the queue doesn't imply there will
  be a discontinuity in the data (e.g. the same data that was
  cleared could be reenqueued)
- In "native-media" test app: add test code to exercise the
  XAVolumeItf functionality.

Change-Id: I9f69f8cacbdce51b6d96d60141ec1d0f645df991
diff --git a/src/itf/IAndroidBufferQueue.c b/src/itf/IAndroidBufferQueue.c
index bea4701..fa4c7e9 100644
--- a/src/itf/IAndroidBufferQueue.c
+++ b/src/itf/IAndroidBufferQueue.c
@@ -158,6 +158,7 @@
         thiz->mBufferArray[i].mDataBuffer = NULL;
         thiz->mBufferArray[i].mDataSize = 0;
         thiz->mBufferArray[i].mDataSizeConsumed = 0;
+        thiz->mBufferArray[i].mBufferContext = NULL;
         switch (thiz->mBufferType) {
           case kAndroidBufferTypeMpeg2Ts:
             thiz->mBufferArray[i].mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
@@ -191,7 +192,8 @@
 
 
 SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
-        const void *pData,
+        void *pBufferContext,
+        void *pData,
         SLuint32 dataLength,
         const SLAndroidBufferItem *pItems,
         SLuint32 itemsLength)
@@ -233,6 +235,7 @@
             oldRear->mDataBuffer = pData;
             oldRear->mDataSize = dataLength;
             oldRear->mDataSizeConsumed = 0;
+            oldRear->mBufferContext = pBufferContext;
             thiz->mRear = newRear;
             ++thiz->mState.count;
             setItems(pItems, itemsLength, thiz->mBufferType, oldRear);
diff --git a/src/itf/IEngine.c b/src/itf/IEngine.c
index 648767c..7d07c02 100644
--- a/src/itf/IEngine.c
+++ b/src/itf/IEngine.c
@@ -311,6 +311,7 @@
                                 thiz->mAndroidBufferQueue.mBufferArray[i].mDataBuffer = NULL;
                                 thiz->mAndroidBufferQueue.mBufferArray[i].mDataSize = 0;
                                 thiz->mAndroidBufferQueue.mBufferArray[i].mDataSizeConsumed = 0;
+                                thiz->mAndroidBufferQueue.mBufferArray[i].mBufferContext = NULL;
                                 switch (thiz->mAndroidBufferQueue.mBufferType) {
                                   case kAndroidBufferTypeMpeg2Ts:
                                     thiz->mAndroidBufferQueue.mBufferArray[i].mItems.mTsCmdData.
@@ -1156,6 +1157,17 @@
                         if (XA_CONTAINERTYPE_MPEG_TS ==
                                 thiz->mDataSource.mFormat.mMIME.containerType) {
                             thiz->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeMpeg2Ts;
+
+                            // Set the container type for the StreamInformation interface
+                            XAMediaContainerInformation *containerInfo =
+                                    (XAMediaContainerInformation*)
+                                        // always storing container info at index 0, as per spec
+                                        &(thiz->mStreamInfo.mStreamInfoTable.itemAt(0).
+                                                containerInfo);
+                            containerInfo->containerType = XA_CONTAINERTYPE_MPEG_TS;
+                            // there are no streams at this stage
+                            containerInfo->numStreams = 0;
+
                         } else {
                             thiz->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeInvalid;
                             SL_LOGE("Invalid buffer type in Android Buffer Queue");
@@ -1173,6 +1185,7 @@
                                 thiz->mAndroidBufferQueue.mBufferArray[i].mDataBuffer = NULL;
                                 thiz->mAndroidBufferQueue.mBufferArray[i].mDataSize = 0;
                                 thiz->mAndroidBufferQueue.mBufferArray[i].mDataSizeConsumed = 0;
+                                thiz->mAndroidBufferQueue.mBufferArray[i].mBufferContext = NULL;
                                 switch (thiz->mAndroidBufferQueue.mBufferType) {
                                   case kAndroidBufferTypeMpeg2Ts:
                                     thiz->mAndroidBufferQueue.mBufferArray[i].mItems.mTsCmdData.
diff --git a/src/itf/IStreamInformation.c b/src/itf/IStreamInformation.c
index a983caa..0769784 100644
--- a/src/itf/IStreamInformation.c
+++ b/src/itf/IStreamInformation.c
@@ -26,6 +26,7 @@
 #ifdef ANDROID
     IStreamInformation *thiz = (IStreamInformation *) self;
     interface_lock_exclusive(thiz);
+    // always storing container info at index 0, as per spec
     info = (XAMediaContainerInformation*)&(thiz->mStreamInfoTable.itemAt(0).containerInfo);
     interface_unlock_exclusive(thiz);
     // even though the pointer to the media container info is returned, the values aren't set
@@ -63,6 +64,7 @@
         IStreamInformation *thiz = (IStreamInformation *) self;
 
         interface_lock_exclusive(thiz);
+
         XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
         // streams in the container are numbered 1..nbStreams
         if (streamIndex <= nbStreams) {
@@ -73,6 +75,7 @@
                     streamIndex, nbStreams);
             result = XA_RESULT_PARAMETER_INVALID;
         }
+
         interface_unlock_exclusive(thiz);
     }
 #endif
@@ -87,8 +90,62 @@
 {
     XA_ENTER_INTERFACE
 
-    SL_LOGE("unsupported XAStreamInformationItf function");
-    result = XA_RESULT_CONTENT_UNSUPPORTED;
+    if (NULL == info) {
+        result = XA_RESULT_PARAMETER_INVALID;
+    } else {
+
+#ifndef ANDROID
+        result = XA_RESULT_FEATURE_UNSUPPORTED;
+#else
+
+        IStreamInformation *thiz = (IStreamInformation *) self;
+
+        interface_lock_exclusive(thiz);
+
+        XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
+        // streams in the container are numbered 1..nbStreams
+        if (streamIndex <= nbStreams) {
+            result = XA_RESULT_SUCCESS;
+            const StreamInfo& streamInfo = thiz->mStreamInfoTable.itemAt((size_t)streamIndex);
+
+            switch (streamInfo.domain) {
+            case XA_DOMAINTYPE_CONTAINER:
+                *(XAMediaContainerInformation *)info = streamInfo.containerInfo;
+                break;
+            case XA_DOMAINTYPE_AUDIO:
+                *(XAAudioStreamInformation *)info = streamInfo.audioInfo;
+                break;
+            case XA_DOMAINTYPE_VIDEO:
+                *(XAVideoStreamInformation *)info = streamInfo.videoInfo;
+                break;
+            case XA_DOMAINTYPE_IMAGE:
+                *(XAImageStreamInformation *)info = streamInfo.imageInfo;
+                break;
+            case XA_DOMAINTYPE_TIMEDTEXT:
+                *(XATimedTextStreamInformation *)info = streamInfo.textInfo;
+                break;
+            case XA_DOMAINTYPE_MIDI:
+                *(XAMIDIStreamInformation *)info = streamInfo.midiInfo;
+                break;
+            case XA_DOMAINTYPE_VENDOR:
+                *(XAVendorStreamInformation *)info = streamInfo.vendorInfo;
+                break;
+            default:
+                SL_LOGE("StreamInformation::QueryStreamInformation index %lu has unknown domain %lu", streamIndex, streamInfo.domain);
+                result = XA_RESULT_INTERNAL_ERROR;
+                break;
+            }
+
+        } else {
+            SL_LOGE("Querying stream type for stream %ld, only %ld streams available",
+                    streamIndex, nbStreams);
+            result = XA_RESULT_PARAMETER_INVALID;
+        }
+
+        interface_unlock_exclusive(thiz);
+#endif
+
+    }
 
     XA_LEAVE_INTERFACE
 }
@@ -149,10 +206,15 @@
         XA_LEAVE_INTERFACE;
     }
 
-    SL_LOGE("unsupported XAStreamInformationItf function");
-    result = XA_RESULT_CONTENT_UNSUPPORTED;
-    *numStreams = 0;
-    activeStreams = NULL;
+    IStreamInformation *thiz = (IStreamInformation *) self;
+
+    interface_lock_exclusive(thiz);
+
+    result = XA_RESULT_SUCCESS;
+    *numStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
+    activeStreams = thiz->mActiveStreams;
+
+    interface_unlock_exclusive(thiz);
 
     XA_LEAVE_INTERFACE
 }
@@ -182,21 +244,40 @@
     IStreamInformation_SetActiveStream
 };
 
+
 void IStreamInformation_init(void *self)
 {
+    SL_LOGV("IStreamInformation_init\n");
     IStreamInformation *thiz = (IStreamInformation *) self;
     thiz->mItf = &IStreamInformation_Itf;
 
     thiz->mCallback = NULL;
     thiz->mContext = NULL;
 
+    for (int i=0 ; i < NB_SUPPORTED_STREAMS ; i++) {
+        thiz->mActiveStreams[i] = XA_BOOLEAN_FALSE;
+    }
+
 #ifdef ANDROID
+    // placement new constructor for C++ field within C struct
+    (void) new (&thiz->mStreamInfoTable) android::Vector<StreamInfo>();
     // initialize container info
     StreamInfo contInf;
-    contInf.domain = XA_DOMAINTYPE_UNKNOWN; // there should really be a domain for the container!
+    contInf.domain = XA_DOMAINTYPE_CONTAINER;
     contInf.containerInfo.containerType = XA_CONTAINERTYPE_UNSPECIFIED;
     contInf.containerInfo.mediaDuration = XA_TIME_UNKNOWN;
+    // FIXME shouldn't this be 1 ?
     contInf.containerInfo.numStreams = 0;
+    // always storing container info at index 0, as per spec: here, the table was still empty
     thiz->mStreamInfoTable.add(contInf);
 #endif
 }
+
+
+void IStreamInformation_deinit(void *self) {
+#ifdef ANDROID
+    IStreamInformation *thiz = (IStreamInformation *) self;
+    // explicit destructor
+    thiz->mStreamInfoTable.~Vector<StreamInfo>();
+#endif
+}