/*
|
* 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.
|
*/
|
|
/* AndroidBufferQueue implementation */
|
|
//#define USE_LOG SLAndroidLogLevel_Verbose
|
|
#include "sles_allinclusive.h"
|
// for AAC ADTS verification on enqueue:
|
#include "android/include/AacBqToPcmCbRenderer.h"
|
|
/**
|
* Determine the state of the audio player or media player associated with a buffer queue.
|
* Note that PLAYSTATE and RECORDSTATE values are equivalent (where PLAYING == RECORDING).
|
*/
|
|
static SLuint32 getAssociatedState(IAndroidBufferQueue *thiz)
|
{
|
SLuint32 state;
|
switch (InterfaceToObjectID(thiz)) {
|
case XA_OBJECTID_MEDIAPLAYER:
|
state = ((CMediaPlayer *) thiz->mThis)->mPlay.mState;
|
break;
|
case SL_OBJECTID_AUDIOPLAYER:
|
state = ((CAudioPlayer *) thiz->mThis)->mPlay.mState;
|
break;
|
default:
|
// unreachable, but just in case we will assume it is stopped
|
assert(SL_BOOLEAN_FALSE);
|
state = SL_PLAYSTATE_STOPPED;
|
break;
|
}
|
return state;
|
}
|
|
|
/**
|
* parse and set the items associated with the given buffer, based on the buffer type,
|
* which determines the set of authorized items and format
|
*/
|
static SLresult setItems(SLuint32 dataLength,
|
const SLAndroidBufferItem *pItems, SLuint32 itemsLength,
|
SLuint16 bufferType, AdvancedBufferHeader *pBuff, bool *pEOS)
|
{
|
// reset item structure based on type
|
switch (bufferType) {
|
case kAndroidBufferTypeMpeg2Ts:
|
pBuff->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
|
pBuff->mItems.mTsCmdData.mPts = 0;
|
break;
|
case kAndroidBufferTypeAacadts:
|
pBuff->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
|
break;
|
case kAndroidBufferTypeInvalid:
|
default:
|
// shouldn't happen, but just in case clear out the item structure
|
memset(&pBuff->mItems, 0, sizeof(AdvancedBufferItems));
|
return SL_RESULT_INTERNAL_ERROR;
|
}
|
|
// process all items in the array; if no items then we break out of loop immediately
|
while (itemsLength > 0) {
|
|
// remaining length must be large enough for one full item without any associated data
|
if (itemsLength < sizeof(SLAndroidBufferItem)) {
|
SL_LOGE("Partial item at end of array");
|
return SL_RESULT_PARAMETER_INVALID;
|
}
|
itemsLength -= sizeof(SLAndroidBufferItem);
|
|
// remaining length must be large enough for data with current item and alignment padding
|
SLuint32 itemDataSizeWithAlignmentPadding = (pItems->itemSize + 3) & ~3;
|
if (itemsLength < itemDataSizeWithAlignmentPadding) {
|
SL_LOGE("Partial item data at end of array");
|
return SL_RESULT_PARAMETER_INVALID;
|
}
|
itemsLength -= itemDataSizeWithAlignmentPadding;
|
|
// parse item data based on type
|
switch (bufferType) {
|
|
case kAndroidBufferTypeMpeg2Ts: {
|
switch (pItems->itemKey) {
|
|
case SL_ANDROID_ITEMKEY_EOS:
|
pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_EOS;
|
//SL_LOGD("Found EOS event=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
|
if (pItems->itemSize != 0) {
|
SL_LOGE("Invalid item parameter size %u for EOS", pItems->itemSize);
|
return SL_RESULT_PARAMETER_INVALID;
|
}
|
break;
|
|
case SL_ANDROID_ITEMKEY_DISCONTINUITY:
|
if (pItems->itemSize == 0) {
|
pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCONTINUITY;
|
//SL_LOGD("Found DISCONTINUITYevent=%d", pBuff->mItems.mTsCmdData.mTsCmdCode);
|
} else if (pItems->itemSize == sizeof(SLAuint64)) {
|
pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_DISCON_NEWPTS;
|
pBuff->mItems.mTsCmdData.mPts = *((SLAuint64*)pItems->itemData);
|
//SL_LOGD("Found PTS=%lld", pBuff->mItems.mTsCmdData.mPts);
|
} else {
|
SL_LOGE("Invalid item parameter size %u for MPEG-2 PTS", pItems->itemSize);
|
return SL_RESULT_PARAMETER_INVALID;
|
}
|
break;
|
|
case SL_ANDROID_ITEMKEY_FORMAT_CHANGE:
|
// distinguish between a "full" format change and one where it says what changed
|
if (pItems->itemSize == 0) {
|
SL_LOGV("Received format change with no data == full format change");
|
pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL;
|
} else if (pItems->itemSize == sizeof(SLuint32)) {
|
XAuint32 formatData = *((XAuint32*)pItems->itemData);
|
// intentionally only supporting video change when reading which specific
|
// stream has changed, interpret other changes as full change
|
if (formatData == XA_ANDROID_FORMATCHANGE_ITEMDATA_VIDEO) {
|
pBuff->mItems.mTsCmdData.mTsCmdCode |=
|
ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO;
|
SL_LOGV("Received video format change");
|
} else {
|
// note that we don't support specifying
|
// ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL by having all bits of
|
// the data mask set, we default to it with unsupported masks
|
SL_LOGE("Received format change with unsupported data, ignoring data");
|
pBuff->mItems.mTsCmdData.mTsCmdCode |=
|
ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL;
|
}
|
} else {
|
SL_LOGE("Received format change with invalid data size, ignoring data");
|
pBuff->mItems.mTsCmdData.mTsCmdCode |= ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL;
|
}
|
break;
|
|
default:
|
// unknown item key
|
SL_LOGE("Unknown item key %u with size %u", pItems->itemKey, pItems->itemSize);
|
return SL_RESULT_PARAMETER_INVALID;
|
|
}// switch (pItems->itemKey)
|
} break;
|
|
case kAndroidBufferTypeAacadts: {
|
switch (pItems->itemKey) {
|
|
case SL_ANDROID_ITEMKEY_EOS:
|
pBuff->mItems.mAdtsCmdData.mAdtsCmdCode |= ANDROID_ADTSEVENT_EOS;
|
if (pItems->itemSize != 0) {
|
SL_LOGE("Invalid item parameter size %u for EOS", pItems->itemSize);
|
return SL_RESULT_PARAMETER_INVALID;
|
}
|
break;
|
|
default:
|
// unknown item key
|
SL_LOGE("Unknown item key %u with size %u", pItems->itemKey, pItems->itemSize);
|
return SL_RESULT_PARAMETER_INVALID;
|
|
}// switch (pItems->itemKey)
|
} break;
|
|
case kAndroidBufferTypeInvalid:
|
default:
|
// not reachable as we checked this earlier
|
return SL_RESULT_INTERNAL_ERROR;
|
|
}// switch (bufferType)
|
|
// skip past this item, including data with alignment padding
|
pItems = (SLAndroidBufferItem *) ((char *) pItems +
|
sizeof(SLAndroidBufferItem) + itemDataSizeWithAlignmentPadding);
|
}
|
|
// now check for invalid combinations of items
|
switch (bufferType) {
|
|
case kAndroidBufferTypeMpeg2Ts: {
|
// supported Mpeg2Ts commands are mutually exclusive
|
switch (pBuff->mItems.mTsCmdData.mTsCmdCode) {
|
// single items are allowed
|
case ANDROID_MP2TSEVENT_EOS:
|
if (dataLength > 0) {
|
SL_LOGE("Can't enqueue non-zero data with EOS");
|
return SL_RESULT_PRECONDITIONS_VIOLATED;
|
}
|
*pEOS = true;
|
break;
|
case ANDROID_MP2TSEVENT_NONE:
|
case ANDROID_MP2TSEVENT_DISCONTINUITY:
|
case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
|
case ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL:
|
case ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO:
|
break;
|
// no combinations are allowed
|
default:
|
SL_LOGE("Invalid combination of items");
|
return SL_RESULT_PARAMETER_INVALID;
|
}
|
} break;
|
|
case kAndroidBufferTypeAacadts: {
|
// only one item supported, and thus no combination check needed
|
if (pBuff->mItems.mAdtsCmdData.mAdtsCmdCode == ANDROID_ADTSEVENT_EOS) {
|
if (dataLength > 0) {
|
SL_LOGE("Can't enqueue non-zero data with EOS");
|
return SL_RESULT_PRECONDITIONS_VIOLATED;
|
}
|
*pEOS = true;
|
}
|
} break;
|
|
case kAndroidBufferTypeInvalid:
|
default:
|
// not reachable as we checked this earlier
|
return SL_RESULT_INTERNAL_ERROR;
|
}
|
|
return SL_RESULT_SUCCESS;
|
}
|
|
|
static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf self,
|
slAndroidBufferQueueCallback callback, void *pContext)
|
{
|
SL_ENTER_INTERFACE
|
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
|
interface_lock_exclusive(thiz);
|
|
// verify pre-condition that media object is in the SL_PLAYSTATE_STOPPED state
|
if (SL_PLAYSTATE_STOPPED == getAssociatedState(thiz)) {
|
thiz->mCallback = callback;
|
thiz->mContext = pContext;
|
result = SL_RESULT_SUCCESS;
|
|
} else {
|
result = SL_RESULT_PRECONDITIONS_VIOLATED;
|
}
|
|
interface_unlock_exclusive(thiz);
|
|
SL_LEAVE_INTERFACE
|
}
|
|
|
static SLresult IAndroidBufferQueue_Clear(SLAndroidBufferQueueItf self)
|
{
|
SL_ENTER_INTERFACE
|
result = SL_RESULT_SUCCESS;
|
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
|
interface_lock_exclusive(thiz);
|
|
// reset the queue pointers
|
thiz->mFront = &thiz->mBufferArray[0];
|
thiz->mRear = &thiz->mBufferArray[0];
|
// reset the queue state
|
thiz->mState.count = 0;
|
thiz->mState.index = 0;
|
|
// object-specific behavior for a clear
|
switch (InterfaceToObjectID(thiz)) {
|
case SL_OBJECTID_AUDIOPLAYER:
|
android_audioPlayer_androidBufferQueue_clear_l((CAudioPlayer*) thiz->mThis);
|
break;
|
case XA_OBJECTID_MEDIAPLAYER:
|
android_Player_androidBufferQueue_clear_l((CMediaPlayer*) thiz->mThis);
|
break;
|
default:
|
result = SL_RESULT_PARAMETER_INVALID;
|
}
|
|
interface_unlock_exclusive(thiz);
|
|
SL_LEAVE_INTERFACE
|
}
|
|
|
static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
|
void *pBufferContext,
|
void *pData,
|
SLuint32 dataLength,
|
const SLAndroidBufferItem *pItems,
|
SLuint32 itemsLength)
|
{
|
SL_ENTER_INTERFACE
|
SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength);
|
|
if ((dataLength > 0) && (NULL == pData)) {
|
SL_LOGE("Enqueue failure: non-zero data length %u but NULL data pointer", dataLength);
|
result = SL_RESULT_PARAMETER_INVALID;
|
} else if ((itemsLength > 0) && (NULL == pItems)) {
|
SL_LOGE("Enqueue failure: non-zero items length %u but NULL items pointer", itemsLength);
|
result = SL_RESULT_PARAMETER_INVALID;
|
} else if ((0 == dataLength) && (0 == itemsLength)) {
|
// no data and no msg
|
SL_LOGE("Enqueue failure: trying to enqueue buffer with no data and no items.");
|
result = SL_RESULT_PARAMETER_INVALID;
|
// Note that a non-NULL data pointer with zero data length is allowed.
|
// We track that data pointer as it moves through the queue
|
// to assist the application in accounting for data buffers.
|
// A non-NULL items pointer with zero items length is also allowed, but has no value.
|
} else {
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
|
// buffer size check, can be done outside of lock because buffer type can't change
|
switch (thiz->mBufferType) {
|
case kAndroidBufferTypeMpeg2Ts:
|
if (dataLength % MPEG2_TS_PACKET_SIZE == 0) {
|
// The downstream Stagefright MPEG-2 TS parser is sensitive to format errors,
|
// so do a quick sanity check beforehand on the first packet of the buffer.
|
// We don't check all the packets to avoid thrashing the data cache.
|
if ((dataLength > 0) && (*(SLuint8 *)pData != MPEG2_TS_PACKET_SYNC)) {
|
SL_LOGE("Error enqueueing MPEG-2 TS data: incorrect packet sync");
|
result = SL_RESULT_CONTENT_CORRUPTED;
|
SL_LEAVE_INTERFACE
|
}
|
break;
|
}
|
SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (packet size)",
|
MPEG2_TS_PACKET_SIZE);
|
result = SL_RESULT_PARAMETER_INVALID;
|
SL_LEAVE_INTERFACE
|
break;
|
case kAndroidBufferTypeAacadts:
|
// zero dataLength is permitted in case of EOS command only
|
if (dataLength > 0) {
|
result = android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(
|
pData, dataLength);
|
if (SL_RESULT_SUCCESS != result) {
|
SL_LOGE("Error enqueueing ADTS data: data must start and end on frame "
|
"boundaries");
|
SL_LEAVE_INTERFACE
|
}
|
}
|
break;
|
case kAndroidBufferTypeInvalid:
|
default:
|
result = SL_RESULT_PARAMETER_INVALID;
|
SL_LEAVE_INTERFACE
|
}
|
|
interface_lock_exclusive(thiz);
|
|
AdvancedBufferHeader *oldRear = thiz->mRear, *newRear;
|
if ((newRear = oldRear + 1) == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
|
newRear = thiz->mBufferArray;
|
}
|
if (thiz->mEOS) {
|
SL_LOGE("Can't enqueue after EOS");
|
result = SL_RESULT_PRECONDITIONS_VIOLATED;
|
} else if (newRear == thiz->mFront) {
|
result = SL_RESULT_BUFFER_INSUFFICIENT;
|
} else {
|
// set oldRear->mItems based on items
|
result = setItems(dataLength, pItems, itemsLength, thiz->mBufferType, oldRear,
|
&thiz->mEOS);
|
if (SL_RESULT_SUCCESS == result) {
|
oldRear->mDataBuffer = pData;
|
oldRear->mDataSize = dataLength;
|
oldRear->mDataSizeConsumed = 0;
|
oldRear->mBufferContext = pBufferContext;
|
//oldRear->mBufferState = TBD;
|
thiz->mRear = newRear;
|
++thiz->mState.count;
|
}
|
}
|
// set enqueue attribute if state is PLAYING and the first buffer is enqueued
|
interface_unlock_exclusive_attributes(thiz, ((SL_RESULT_SUCCESS == result) &&
|
(1 == thiz->mState.count) && (SL_PLAYSTATE_PLAYING == getAssociatedState(thiz))) ?
|
ATTR_ABQ_ENQUEUE : ATTR_NONE);
|
}
|
|
SL_LEAVE_INTERFACE
|
}
|
|
|
static SLresult IAndroidBufferQueue_GetState(SLAndroidBufferQueueItf self,
|
SLAndroidBufferQueueState *pState)
|
{
|
SL_ENTER_INTERFACE
|
|
// Note that GetState while a Clear is pending is equivalent to GetState before the Clear
|
|
if (NULL == pState) {
|
result = SL_RESULT_PARAMETER_INVALID;
|
} else {
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
|
interface_lock_shared(thiz);
|
|
pState->count = thiz->mState.count;
|
pState->index = thiz->mState.index;
|
|
interface_unlock_shared(thiz);
|
|
result = SL_RESULT_SUCCESS;
|
}
|
|
SL_LEAVE_INTERFACE
|
}
|
|
|
static SLresult IAndroidBufferQueue_SetCallbackEventsMask(SLAndroidBufferQueueItf self,
|
SLuint32 eventFlags)
|
{
|
SL_ENTER_INTERFACE
|
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
interface_lock_exclusive(thiz);
|
// FIXME only supporting SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED in this implementation
|
if (!(~(SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED /* | others TBD */ ) & eventFlags)) {
|
thiz->mCallbackEventsMask = eventFlags;
|
result = SL_RESULT_SUCCESS;
|
} else {
|
result = SL_RESULT_FEATURE_UNSUPPORTED;
|
}
|
interface_unlock_exclusive(thiz);
|
|
SL_LEAVE_INTERFACE
|
}
|
|
|
static SLresult IAndroidBufferQueue_GetCallbackEventsMask(SLAndroidBufferQueueItf self,
|
SLuint32 *pEventFlags)
|
{
|
SL_ENTER_INTERFACE
|
|
if (NULL == pEventFlags) {
|
result = SL_RESULT_PARAMETER_INVALID;
|
} else {
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
interface_lock_shared(thiz);
|
SLuint32 callbackEventsMask = thiz->mCallbackEventsMask;
|
interface_unlock_shared(thiz);
|
*pEventFlags = callbackEventsMask;
|
result = SL_RESULT_SUCCESS;
|
}
|
|
SL_LEAVE_INTERFACE
|
}
|
|
|
static const struct SLAndroidBufferQueueItf_ IAndroidBufferQueue_Itf = {
|
IAndroidBufferQueue_RegisterCallback,
|
IAndroidBufferQueue_Clear,
|
IAndroidBufferQueue_Enqueue,
|
IAndroidBufferQueue_GetState,
|
IAndroidBufferQueue_SetCallbackEventsMask,
|
IAndroidBufferQueue_GetCallbackEventsMask
|
};
|
|
|
void IAndroidBufferQueue_init(void *self)
|
{
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
thiz->mItf = &IAndroidBufferQueue_Itf;
|
|
thiz->mState.count = 0;
|
thiz->mState.index = 0;
|
|
thiz->mCallback = NULL;
|
thiz->mContext = NULL;
|
thiz->mCallbackEventsMask = SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED;
|
|
thiz->mBufferType = kAndroidBufferTypeInvalid;
|
thiz->mBufferArray = NULL;
|
thiz->mFront = NULL;
|
thiz->mRear = NULL;
|
thiz->mEOS = false;
|
}
|
|
|
void IAndroidBufferQueue_deinit(void *self)
|
{
|
IAndroidBufferQueue *thiz = (IAndroidBufferQueue *) self;
|
if (NULL != thiz->mBufferArray) {
|
free(thiz->mBufferArray);
|
thiz->mBufferArray = NULL;
|
}
|
}
|
|
|
#if 0
|
// Dump the contents of an IAndroidBufferQueue to the log. This is for debugging only,
|
// and is not a documented API. The associated object is locked throughout for atomicity,
|
// but the log entries may be interspersed with unrelated logs.
|
|
void IAndroidBufferQueue_log(IAndroidBufferQueue *thiz)
|
{
|
interface_lock_shared(thiz);
|
SL_LOGI("IAndroidBufferQueue %p:", thiz);
|
SL_LOGI(" mState.count=%u mState.index=%u mCallback=%p mContext=%p",
|
thiz->mState.count, thiz->mState.index, thiz->mCallback, thiz->mContext);
|
const char *bufferTypeString;
|
switch (thiz->mBufferType) {
|
case kAndroidBufferTypeInvalid:
|
bufferTypeString = "kAndroidBufferTypeInvalid";
|
break;
|
case kAndroidBufferTypeMpeg2Ts:
|
bufferTypeString = "kAndroidBufferTypeMpeg2Ts";
|
break;
|
case kAndroidBufferTypeAacadts:
|
bufferTypeString = "kAndroidBufferTypeAacadts";
|
break;
|
default:
|
bufferTypeString = "unknown";
|
break;
|
}
|
SL_LOGI(" mCallbackEventsMask=0x%x, mBufferType=0x%x (%s), mEOS=%s",
|
thiz->mCallbackEventsMask,
|
thiz->mBufferType, bufferTypeString,
|
thiz->mEOS ? "true" : "false");
|
SL_LOGI(" mBufferArray=%p, mFront=%p (%u), mRear=%p (%u)",
|
thiz->mBufferArray,
|
thiz->mFront, thiz->mFront - thiz->mBufferArray,
|
thiz->mRear, thiz->mRear - thiz->mBufferArray);
|
SL_LOGI(" index mDataBuffer mDataSize mDataSizeConsumed mBufferContext mItems");
|
const AdvancedBufferHeader *hdr;
|
for (hdr = thiz->mFront; hdr != thiz->mRear; ) {
|
SLuint32 i = hdr - thiz->mBufferArray;
|
char itemString[32];
|
switch (thiz->mBufferType) {
|
case kAndroidBufferTypeMpeg2Ts:
|
switch (hdr->mItems.mTsCmdData.mTsCmdCode) {
|
case ANDROID_MP2TSEVENT_NONE:
|
strcpy(itemString, "NONE");
|
break;
|
case ANDROID_MP2TSEVENT_EOS:
|
strcpy(itemString, "EOS");
|
break;
|
case ANDROID_MP2TSEVENT_DISCONTINUITY:
|
strcpy(itemString, "DISCONTINUITY");
|
break;
|
case ANDROID_MP2TSEVENT_DISCON_NEWPTS:
|
snprintf(itemString, sizeof(itemString), "NEWPTS %llu",
|
hdr->mItems.mTsCmdData.mPts);
|
break;
|
case ANDROID_MP2TSEVENT_FORMAT_CHANGE:
|
strcpy(itemString, "FORMAT_CHANGE");
|
break;
|
default:
|
snprintf(itemString, sizeof(itemString), "0x%x", hdr->mItems.mTsCmdData.mTsCmdCode);
|
break;
|
}
|
break;
|
case kAndroidBufferTypeAacadts:
|
switch (hdr->mItems.mAdtsCmdData.mAdtsCmdCode) {
|
case ANDROID_ADTSEVENT_NONE:
|
strcpy(itemString, "NONE");
|
break;
|
case ANDROID_ADTSEVENT_EOS:
|
strcpy(itemString, "EOS");
|
break;
|
default:
|
snprintf(itemString, sizeof(itemString), "0x%x",
|
hdr->mItems.mAdtsCmdData.mAdtsCmdCode);
|
break;
|
}
|
break;
|
default:
|
strcpy(itemString, "");
|
break;
|
}
|
SL_LOGI(" %5u %11p %9u %17u %14p %s",
|
i, hdr->mDataBuffer, hdr->mDataSize, hdr->mDataSizeConsumed,
|
hdr->mBufferContext, itemString);
|
// mBufferState
|
if (++hdr == &thiz->mBufferArray[thiz->mNumBuffers + 1]) {
|
hdr = thiz->mBufferArray;
|
}
|
}
|
interface_unlock_shared(thiz);
|
}
|
|
#endif
|