/*
* Copyright (C) 2011 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.
*/
/* StreamInformation implementation */
#include "sles_allinclusive.h"
static XAresult IStreamInformation_QueryMediaContainerInformation( XAStreamInformationItf self,
XAMediaContainerInformation * info /* [out] */)
{
XA_ENTER_INTERFACE
if (NULL == info) {
result = XA_RESULT_PARAMETER_INVALID;
XA_LEAVE_INTERFACE
}
#ifdef ANDROID
IStreamInformation *thiz = (IStreamInformation *) self;
interface_lock_shared(thiz);
// always storing container info at index 0, as per spec
*info = thiz->mStreamInfoTable.itemAt(0).containerInfo;
interface_unlock_shared(thiz);
// even though the pointer to the media container info is returned, the values aren't set
// for the actual container in this version, they are simply initialized to defaults
// (see IStreamInformation_init)
result = XA_RESULT_SUCCESS;
#else
SL_LOGE("QueryMediaContainerInformation is unsupported");
memset(info, 0, sizeof(XAMediaContainerInformation));
result = XA_RESULT_FEATURE_UNSUPPORTED;
#endif
XA_LEAVE_INTERFACE
}
static XAresult IStreamInformation_QueryStreamType( XAStreamInformationItf self,
XAuint32 streamIndex, /* [in] */
XAuint32 *domain) /* [out] */
{
XA_ENTER_INTERFACE
if (NULL == domain) {
result = XA_RESULT_PARAMETER_INVALID;
XA_LEAVE_INTERFACE;
}
#ifndef ANDROID
*domain = XA_DOMAINTYPE_UNKNOWN;
#else
if (0 == streamIndex) {
// stream 0 is reserved for the container
result = XA_RESULT_PARAMETER_INVALID;
*domain = XA_DOMAINTYPE_UNKNOWN;
} else {
IStreamInformation *thiz = (IStreamInformation *) self;
interface_lock_shared(thiz);
XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
// streams in the container are numbered 1..nbStreams
if (streamIndex <= nbStreams) {
result = XA_RESULT_SUCCESS;
*domain = thiz->mStreamInfoTable.itemAt(streamIndex).domain;
} else {
SL_LOGE("Querying stream type for stream %d, only %d streams available",
streamIndex, nbStreams);
result = XA_RESULT_PARAMETER_INVALID;
}
interface_unlock_shared(thiz);
}
#endif
XA_LEAVE_INTERFACE
}
static XAresult IStreamInformation_QueryStreamInformation( XAStreamInformationItf self,
XAuint32 streamIndex, /* [in] */
void * info) /* [out] */
{
XA_ENTER_INTERFACE
if (NULL == info) {
result = XA_RESULT_PARAMETER_INVALID;
} else {
#ifndef ANDROID
result = XA_RESULT_FEATURE_UNSUPPORTED;
#else
IStreamInformation *thiz = (IStreamInformation *) self;
interface_lock_shared(thiz);
XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
// stream 0 is the container, and other 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 %u has "
"unknown domain %u", streamIndex, streamInfo.domain);
result = XA_RESULT_INTERNAL_ERROR;
break;
}
} else {
SL_LOGE("Querying stream type for stream %d, only %d streams available",
streamIndex, nbStreams);
result = XA_RESULT_PARAMETER_INVALID;
}
interface_unlock_shared(thiz);
#endif
}
XA_LEAVE_INTERFACE
}
static XAresult IStreamInformation_QueryStreamName( XAStreamInformationItf self,
XAuint32 streamIndex, /* [in] */
XAuint16 * pNameSize, /* [in/out] */
XAchar * pName) /* [out] */
{
XA_ENTER_INTERFACE
if (NULL == pNameSize || streamIndex == 0) {
result = XA_RESULT_PARAMETER_INVALID;
} else {
#ifdef ANDROID
IStreamInformation *thiz = (IStreamInformation *) self;
interface_lock_shared(thiz);
XAuint32 nbStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
// streams in the container are numbered 1..nbStreams
if (streamIndex <= nbStreams) {
char streamName[16]; // large enough for the fixed format in next line
snprintf(streamName, sizeof(streamName), "stream%u", streamIndex);
size_t actualNameLength = strlen(streamName);
if (NULL == pName) {
// application is querying the name length in order to allocate a buffer
result = XA_RESULT_SUCCESS;
} else {
SLuint16 availableNameLength = *pNameSize;
if (actualNameLength > availableNameLength) {
memcpy(pName, streamName, availableNameLength);
result = XA_RESULT_BUFFER_INSUFFICIENT;
} else if (actualNameLength == availableNameLength) {
memcpy(pName, streamName, availableNameLength);
result = XA_RESULT_SUCCESS;
} else { // actualNameLength < availableNameLength
memcpy(pName, streamName, actualNameLength + 1);
result = XA_RESULT_SUCCESS;
}
}
*pNameSize = actualNameLength;
} else {
result = XA_RESULT_PARAMETER_INVALID;
}
interface_unlock_shared(thiz);
#else
SL_LOGE("unsupported XAStreamInformationItf function");
result = XA_RESULT_FEATURE_UNSUPPORTED;
#endif
}
XA_LEAVE_INTERFACE
}
static XAresult IStreamInformation_RegisterStreamChangeCallback( XAStreamInformationItf self,
xaStreamEventChangeCallback callback, /* [in] */
void * pContext) /* [in] */
{
XA_ENTER_INTERFACE
IStreamInformation *thiz = (IStreamInformation *) self;
interface_lock_exclusive(thiz);
thiz->mCallback = callback;
thiz->mContext = pContext;
result = SL_RESULT_SUCCESS;
interface_unlock_exclusive(thiz);
XA_LEAVE_INTERFACE
}
static XAresult IStreamInformation_QueryActiveStreams( XAStreamInformationItf self,
XAuint32 *numStreams, /* [in/out] */
XAboolean *activeStreams) /* [out] */
{
XA_ENTER_INTERFACE
if (NULL == numStreams) {
result = XA_RESULT_PARAMETER_INVALID;
XA_LEAVE_INTERFACE;
}
#ifdef ANDROID
IStreamInformation *thiz = (IStreamInformation *) self;
interface_lock_shared(thiz);
result = XA_RESULT_SUCCESS;
*numStreams = thiz->mStreamInfoTable.itemAt(0).containerInfo.numStreams;
activeStreams = thiz->mActiveStreams;
interface_unlock_shared(thiz);
#else
result = SL_RESULT_FEATURE_UNSUPPORTED;
#endif
XA_LEAVE_INTERFACE
}
static XAresult IStreamInformation_SetActiveStream( XAStreamInformationItf self,
XAuint32 streamNum, /* [in] */
XAboolean active, /* [in] */
XAboolean commitNow) /* [in] */
{
XA_ENTER_INTERFACE
SL_LOGE("unsupported XAStreamInformationItf function");
result = XA_RESULT_FEATURE_UNSUPPORTED;
XA_LEAVE_INTERFACE
}
static const struct XAStreamInformationItf_ IStreamInformation_Itf = {
IStreamInformation_QueryMediaContainerInformation,
IStreamInformation_QueryStreamType,
IStreamInformation_QueryStreamInformation,
IStreamInformation_QueryStreamName,
IStreamInformation_RegisterStreamChangeCallback,
IStreamInformation_QueryActiveStreams,
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_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
}