Esempio n. 1
0
void IThreadSync_deinit(void *self)
{
    IThreadSync *this = (IThreadSync *) self;
    if (this->mInCriticalSection) {
        SL_LOGW("ThreadSync::EnterCriticalSection was active at Engine::Destroy");
    }
}
Esempio n. 2
0
void object_lock_exclusive_(IObject *thiz, const char *file, int line)
{
    int ok;
    ok = pthread_mutex_trylock(&thiz->mMutex);
    if (0 != ok) {
        // not android_atomic_acquire_load because we don't care about relative load/load ordering
        int32_t oldGeneration = thiz->mGeneration;
        // wait up to a total of 250 ms
        static const long nanoBackoffs[] = {
            10 * 1000000, 20 * 1000000, 30 * 1000000, 40 * 1000000, 50 * 1000000, 100 * 1000000};
        unsigned i = 0;
        timespec ts;
        memset(&ts, 0, sizeof(timespec));
        for (;;) {
            init_time_spec(&ts, nanoBackoffs[i]);
            ok = pthread_mutex_timedlock(&thiz->mMutex, &ts);
            if (0 == ok) {
                break;
            }
            if (EBUSY == ok) {
                // this is the expected return value for timeout, and will be handled below
            } else if (EDEADLK == ok) {
                // we don't use the kind of mutex that can return this error, but just in case
                SL_LOGE("%s:%d: recursive lock detected", file, line);
            } else {
                // some other return value
                SL_LOGE("%s:%d: pthread_mutex_lock_timeout_np returned %d", file, line, ok);
            }
            // is anyone else making forward progress?
            int32_t newGeneration = thiz->mGeneration;
            if (newGeneration != oldGeneration) {
                // if we ever see forward progress then lock without timeout (more efficient)
                goto forward_progress;
            }
            // no, then continue trying to lock but with increasing timeouts
            if (++i >= (sizeof(nanoBackoffs) / sizeof(nanoBackoffs[0]))) {
                // the extra block avoids a C++ compiler error about goto past initialization
                {
                    pthread_t me = pthread_self();
                    pthread_t owner = thiz->mOwner;
                    // unlikely, but this could result in a memory fault if owner is corrupt
                    pid_t ownerTid = LIKELY_VALID(owner) ? __pthread_gettid(owner) : -1;
                    SL_LOGW("%s:%d: pthread %p (tid %d) sees object %p was locked by pthread %p"
                            " (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
                            *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
                }
forward_progress:
                // attempt one more time without timeout; maybe this time we will be successful
                ok = pthread_mutex_lock(&thiz->mMutex);
                assert(0 == ok);
                break;
            }
        }
    }
    // here if mutex was successfully locked
    pthread_t zero;
    memset(&zero, 0, sizeof(pthread_t));
    if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
        pthread_t me = pthread_self();
        pthread_t owner = thiz->mOwner;
        pid_t ownerTid = LIKELY_VALID(owner) ? __pthread_gettid(owner) : -1;
        if (pthread_equal(pthread_self(), owner)) {
            SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was recursively locked by pthread"
                    " %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
                    *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
        } else {
            SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was left unlocked in unexpected"
                    " state by pthread %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(),
                    thiz, *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
        }
        assert(false);
    }
    thiz->mOwner = pthread_self();
    thiz->mFile = file;
    thiz->mLine = line;
    // not android_atomic_inc because we are already holding a mutex
    ++thiz->mGeneration;
}
//--------------------------------------------------
// consumption from ABQ: pull from the ABQ, and push to shared memory (media server)
void StreamSourceAppProxy::pullFromBuffQueue() {

    if (android::CallbackProtector::enterCbIfOk(mCallbackProtector)) {

        size_t bufferId;
        void* bufferLoc;
        size_t buffSize;

        slAndroidBufferQueueCallback callback = NULL;
        void* pBufferContext, *pBufferData, *callbackPContext = NULL;
        AdvancedBufferHeader *oldFront = NULL;
        uint32_t dataSize /* , dataUsed */;

        // retrieve data from the buffer queue
        interface_lock_exclusive(mAndroidBufferQueue);

        // can this read operation cause us to call the buffer queue callback
        // (either because there was a command with no data, or all the data has been consumed)
        bool queueCallbackCandidate = false;

        if (mAndroidBufferQueue->mState.count != 0) {
            // SL_LOGD("nbBuffers in ABQ = %u, buffSize=%u",abq->mState.count, buffSize);
            assert(mAndroidBufferQueue->mFront != mAndroidBufferQueue->mRear);

            oldFront = mAndroidBufferQueue->mFront;
            AdvancedBufferHeader *newFront = &oldFront[1];

            // consume events when starting to read data from a buffer for the first time
            if (oldFront->mDataSizeConsumed == 0) {
                // note this code assumes at most one event per buffer; see IAndroidBufferQueue_Enqueue
                if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_EOS) {
                    receivedCmd_l(IStreamListener::EOS);
                    // EOS has no associated data
                    queueCallbackCandidate = true;
                } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCONTINUITY) {
                    receivedCmd_l(IStreamListener::DISCONTINUITY);
                } else if (oldFront->mItems.mTsCmdData.mTsCmdCode & ANDROID_MP2TSEVENT_DISCON_NEWPTS) {
                    sp<AMessage> msg = new AMessage();
                    msg->setInt64(IStreamListener::kKeyResumeAtPTS,
                                  (int64_t)oldFront->mItems.mTsCmdData.mPts);
                    receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
                } else if (oldFront->mItems.mTsCmdData.mTsCmdCode
                           & ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL) {
                    sp<AMessage> msg = new AMessage();
                    msg->setInt32(
                        IStreamListener::kKeyDiscontinuityMask,
                        ATSParser::DISCONTINUITY_FORMATCHANGE);
                    receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
                } else if (oldFront->mItems.mTsCmdData.mTsCmdCode
                           & ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO) {
                    sp<AMessage> msg = new AMessage();
                    msg->setInt32(
                        IStreamListener::kKeyDiscontinuityMask,
                        ATSParser::DISCONTINUITY_VIDEO_FORMAT);
                    receivedCmd_l(IStreamListener::DISCONTINUITY, msg /*msg*/);
                }
                // note that here we are intentionally only supporting
                //   ANDROID_MP2TSEVENT_FORMAT_CHANGE_VIDEO, see IAndroidBufferQueue.c

                // some commands may introduce a time discontinuity, reevaluate position if needed
                if (oldFront->mItems.mTsCmdData.mTsCmdCode & (ANDROID_MP2TSEVENT_DISCONTINUITY |
                        ANDROID_MP2TSEVENT_DISCON_NEWPTS | ANDROID_MP2TSEVENT_FORMAT_CHANGE_FULL)) {
                    const sp<StreamPlayer> player(mPlayer.promote());
                    if (player != NULL) {
                        // FIXME see note at onSeek
                        player->seek(ANDROID_UNKNOWN_TIME);
                    }
                }
                oldFront->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
            }

            {
                // we're going to change the shared mem buffer queue, so lock it
                Mutex::Autolock _l(mLock);
                if (!mAvailableBuffers.empty()) {
                    bufferId = *mAvailableBuffers.begin();
                    CHECK_LT(bufferId, mBuffers.size());
                    sp<IMemory> mem = mBuffers.itemAt(bufferId);
                    bufferLoc = mem->pointer();
                    buffSize = mem->size();

                    char *pSrc = ((char*)oldFront->mDataBuffer) + oldFront->mDataSizeConsumed;
                    if (oldFront->mDataSizeConsumed + buffSize < oldFront->mDataSize) {
                        // more available than requested, copy as much as requested
                        // consume data: 1/ copy to given destination
                        memcpy(bufferLoc, pSrc, buffSize);
                        //               2/ keep track of how much has been consumed
                        oldFront->mDataSizeConsumed += buffSize;
                        //               3/ notify shared mem listener that new data is available
                        receivedBuffer_l(bufferId, buffSize);
                        mAvailableBuffers.erase(mAvailableBuffers.begin());
                    } else {
                        // requested as much available or more: consume the whole of the current
                        //   buffer and move to the next
                        size_t consumed = oldFront->mDataSize - oldFront->mDataSizeConsumed;
                        //SL_LOGD("consuming rest of buffer: enqueueing=%u", consumed);
                        oldFront->mDataSizeConsumed = oldFront->mDataSize;

                        // move queue to next
                        if (newFront == &mAndroidBufferQueue->
                                mBufferArray[mAndroidBufferQueue->mNumBuffers + 1]) {
                            // reached the end, circle back
                            newFront = mAndroidBufferQueue->mBufferArray;
                        }
                        mAndroidBufferQueue->mFront = newFront;
                        mAndroidBufferQueue->mState.count--;
                        mAndroidBufferQueue->mState.index++;

                        if (consumed > 0) {
                            // consume data: 1/ copy to given destination
                            memcpy(bufferLoc, pSrc, consumed);
                            //               2/ keep track of how much has been consumed
                            // here nothing to do because we are done with this buffer
                            //               3/ notify StreamPlayer that new data is available
                            receivedBuffer_l(bufferId, consumed);
                            mAvailableBuffers.erase(mAvailableBuffers.begin());
                        }

                        // data has been consumed, and the buffer queue state has been updated
                        // we will notify the client if applicable
                        queueCallbackCandidate = true;
                    }
                }

                if (queueCallbackCandidate) {
                    if (mAndroidBufferQueue->mCallbackEventsMask &
                            SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
                        callback = mAndroidBufferQueue->mCallback;
                        // save callback data while under lock
                        callbackPContext = mAndroidBufferQueue->mContext;
                        pBufferContext = (void *)oldFront->mBufferContext;
                        pBufferData    = (void *)oldFront->mDataBuffer;
                        dataSize       = oldFront->mDataSize;
                        // here a buffer is only dequeued when fully consumed
                        //dataUsed     = oldFront->mDataSizeConsumed;
                    }
                }
                //SL_LOGD("%d buffers available after reading from queue", mAvailableBuffers.size());
                if (!mAvailableBuffers.empty()) {
                    // there is still room in the shared memory, recheck later if we can pull
                    // data from the buffer queue and write it to shared memory
                    const sp<StreamPlayer> player(mPlayer.promote());
                    if (player != NULL) {
                        player->queueRefilled();
                    }
                }
            }

        } else { // empty queue
            SL_LOGD("ABQ empty, starving!");
        }

        interface_unlock_exclusive(mAndroidBufferQueue);

        // notify client of buffer processed
        if (NULL != callback) {
            SLresult result = (*callback)(&mAndroidBufferQueue->mItf, callbackPContext,
                                          pBufferContext, pBufferData, dataSize,
                                          dataSize, /* dataUsed  */
                                          // no messages during playback other than marking the buffer as processed
                                          (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
                                          NB_BUFFEREVENT_ITEM_FIELDS *sizeof(SLuint32) /* itemsLength */ );
            if (SL_RESULT_SUCCESS != result) {
                // Reserved for future use
                SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
            }
        }

        mCallbackProtector->exitCb();
    } // enterCbIfOk
}
ssize_t BufferQueueSource::readAt(off64_t offset, void *data, size_t size) {
    SL_LOGD("BufferQueueSource::readAt(offset=%lld, data=%p, size=%d)", offset, data, size);

    if (mEosReached) {
        // once EOS has been received from the buffer queue, you can't read anymore
        return 0;
    }

    ssize_t readSize;
    slAndroidBufferQueueCallback callback = NULL;
    void* pBufferContext, *pBufferData, *callbackPContext;
    uint32_t dataSize, dataUsed;

    interface_lock_exclusive(mAndroidBufferQueueSource);

    if (mAndroidBufferQueueSource->mState.count == 0) {
        readSize = 0;
    } else {
        assert(mAndroidBufferQueueSource->mFront != mAndroidBufferQueueSource->mRear);

        AdvancedBufferHeader *oldFront = mAndroidBufferQueueSource->mFront;
        AdvancedBufferHeader *newFront = &oldFront[1];

        // where to read from
        char *pSrc = NULL;
        // can this read operation cause us to call the buffer queue callback
        // (either because there was a command with no data, or all the data has been consumed)
        bool queueCallbackCandidate = false;

        // consume events when starting to read data from a buffer for the first time
        if (oldFront->mDataSizeConsumed == 0) {
            if (oldFront->mItems.mAdtsCmdData.mAdtsCmdCode & ANDROID_ADTSEVENT_EOS) {
                mEosReached = true;
                // EOS has no associated data
                queueCallbackCandidate = true;
            }
            oldFront->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
        }

        //assert(mStreamToBqOffset <= offset);
        CHECK_LE(mStreamToBqOffset, offset);

        if (offset + (off64_t) size <= mStreamToBqOffset + oldFront->mDataSize) {
            pSrc = ((char*)oldFront->mDataBuffer) + (offset - mStreamToBqOffset);

            if (offset - mStreamToBqOffset + size == oldFront->mDataSize) {
                // consumed buffer entirely
                oldFront->mDataSizeConsumed = oldFront->mDataSize;
                mStreamToBqOffset += oldFront->mDataSize;
                queueCallbackCandidate = true;

                // move queue to next buffer
                if (newFront == &mAndroidBufferQueueSource->
                        mBufferArray[mAndroidBufferQueueSource->mNumBuffers + 1]) {
                    // reached the end, circle back
                    newFront = mAndroidBufferQueueSource->mBufferArray;
                }
                mAndroidBufferQueueSource->mFront = newFront;
                // update the queue state
                mAndroidBufferQueueSource->mState.count--;
                mAndroidBufferQueueSource->mState.index++;
                SL_LOGV("BufferQueueSource moving to next buffer");
            }
        }

        // consume data: copy to given destination
        if (NULL != pSrc) {
            memcpy(data, pSrc, size);
            readSize = size;
        } else {
            readSize = 0;
        }

        if (queueCallbackCandidate) {
            // data has been consumed, and the buffer queue state has been updated
            // we will notify the client if applicable
            if (mAndroidBufferQueueSource->mCallbackEventsMask &
                    SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
                callback = mAndroidBufferQueueSource->mCallback;
                // save callback data while under lock
                callbackPContext = mAndroidBufferQueueSource->mContext;
                pBufferContext = (void *)oldFront->mBufferContext;
                pBufferData    = (void *)oldFront->mDataBuffer;
                dataSize       = oldFront->mDataSize;
                dataUsed       = oldFront->mDataSizeConsumed;
            }
        }
    }

    interface_unlock_exclusive(mAndroidBufferQueueSource);

    // notify client
    if (NULL != callback) {
        SLresult result = (*callback)(&mAndroidBufferQueueSource->mItf, callbackPContext,
                pBufferContext, pBufferData, dataSize, dataUsed,
                // no messages during playback other than marking the buffer as processed
                (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
                NB_BUFFEREVENT_ITEM_FIELDS * sizeof(SLuint32) /* itemsLength */ );
        if (SL_RESULT_SUCCESS != result) {
            // Reserved for future use
            SL_LOGW("Unsuccessful result %d returned from AndroidBufferQueueCallback", result);
        }
    }

    return readSize;
}
Esempio n. 5
0
static SLresult checkDataFormat(const char *name, void *pFormat, DataFormat *pDataFormat,
        SLuint32 allowedDataFormatMask, SLboolean isOutputFormat)
{
    assert(NULL != name && NULL != pDataFormat);
    SLresult result = SL_RESULT_SUCCESS;
    const SLuint32 *df_representation = NULL; // pointer to representation field, if it exists
    SLuint32 formatType;
    if (NULL == pFormat) {
        pDataFormat->mFormatType = formatType = SL_DATAFORMAT_NULL;
    } else {
        formatType = *(SLuint32 *)pFormat;
        switch (formatType) {
        case SL_ANDROID_DATAFORMAT_PCM_EX:
            pDataFormat->mPCMEx.representation =
                    ((SLAndroidDataFormat_PCM_EX *)pFormat)->representation;
            switch (pDataFormat->mPCMEx.representation) {
            case SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT:
            case SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT:
            case SL_ANDROID_PCM_REPRESENTATION_FLOAT:
                df_representation = &pDataFormat->mPCMEx.representation;
                break;
            default:
                SL_LOGE("%s: unsupported representation: %d", name,
                        pDataFormat->mPCMEx.representation);
                result = SL_RESULT_PARAMETER_INVALID;
                break;
            }
            // SL_ANDROID_DATAFORMAT_PCM_EX - fall through to next test.
        case SL_DATAFORMAT_PCM:
            pDataFormat->mPCM = *(SLDataFormat_PCM *)pFormat;
            do {
                if (pDataFormat->mPCM.numChannels == 0) {
                    result = SL_RESULT_PARAMETER_INVALID;
                } else if (pDataFormat->mPCM.numChannels > SL_ANDROID_SPEAKER_COUNT_MAX) {
                    result = SL_RESULT_CONTENT_UNSUPPORTED;
                }
                if (SL_RESULT_SUCCESS != result) {
                    SL_LOGE("%s: numChannels=%u", name, (unsigned) pDataFormat->mPCM.numChannels);
                    break;
                }

                // check the sampling rate
                if (pDataFormat->mPCM.samplesPerSec == 0) {
                    result = SL_RESULT_PARAMETER_INVALID;
                } else if (pDataFormat->mPCM.samplesPerSec < SL_SAMPLINGRATE_8 ||
                        pDataFormat->mPCM.samplesPerSec > SL_SAMPLINGRATE_192) {
                    result = SL_RESULT_CONTENT_UNSUPPORTED;
                }
                if (SL_RESULT_SUCCESS != result) {
                    SL_LOGE("%s: samplesPerSec=%u", name, pDataFormat->mPCM.samplesPerSec);
                    break;
                }

                // check the container bit depth and representation
                switch (pDataFormat->mPCM.containerSize) {
                case 8:
                    if (df_representation != NULL &&
                            *df_representation != SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT) {
                        result = SL_RESULT_PARAMETER_INVALID;
                    }
                    break;
                case 16:
                case 24:
                    if (df_representation != NULL &&
                            *df_representation != SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT) {
                        result = SL_RESULT_PARAMETER_INVALID;
                    }
                    break;
                case 32:
                    if (df_representation != NULL
                            && *df_representation != SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
                            && *df_representation != SL_ANDROID_PCM_REPRESENTATION_FLOAT) {
                        result = SL_RESULT_PARAMETER_INVALID;
                    }
                    break;
                default:
                    result = SL_RESULT_PARAMETER_INVALID;
                    break;
                }
                if (SL_RESULT_SUCCESS != result) {
                    SL_LOGE("%s: containerSize=%u", name, pDataFormat->mPCM.containerSize);
                    break;
                }

                // sample size cannot be zero, and container size cannot be less than sample size
                if (pDataFormat->mPCM.bitsPerSample == 0 ||
                        pDataFormat->mPCM.containerSize < pDataFormat->mPCM.bitsPerSample) {
                    result = SL_RESULT_PARAMETER_INVALID;
                }
                if (SL_RESULT_SUCCESS != result) {
                    SL_LOGE("%s: containerSize=%u, bitsPerSample=%u", name,
                            (unsigned) pDataFormat->mPCM.containerSize,
                            (unsigned) pDataFormat->mPCM.bitsPerSample);
                    break;
                }

                // check the channel mask
                SL_LOGV("%s: Requested channel mask of 0x%x for %d channel audio",
                    name,
                    pDataFormat->mPCM.channelMask,
                    pDataFormat->mPCM.numChannels);

                if (pDataFormat->mPCM.channelMask == 0) {
                    // We can derive the channel mask from the channel count,
                    // but issue a warning--the automatic mask generation
                    // makes a lot of assumptions that may or may not be what
                    // the app was expecting.
                    SLuint32 mask = isOutputFormat
                            ? sles_channel_out_mask_from_count(pDataFormat->mPCM.numChannels)
                            : sles_channel_in_mask_from_count(pDataFormat->mPCM.numChannels);
                    if (mask == SL_ANDROID_UNKNOWN_CHANNELMASK) {
                        SL_LOGE("No channel mask specified and no default mapping for"
                                "requested speaker count of %u", pDataFormat->mPCM.numChannels);
                        result = SL_RESULT_PARAMETER_INVALID;
                    } else {
                        pDataFormat->mPCM.channelMask = mask;
                        SL_LOGW("No channel mask specified; Using mask %#x based on requested"
                                        "speaker count of %u",
                                pDataFormat->mPCM.channelMask,
                                pDataFormat->mPCM.numChannels);
                    }
                }

                SLuint32 mask = pDataFormat->mPCM.channelMask;
                SLuint32 count = sles_channel_count_from_mask(mask);
                if (count != pDataFormat->mPCM.numChannels) {
                    SL_LOGE("%s: requested %d channels but mask (0x%x) has %d channel bits set",
                        name,
                        pDataFormat->mPCM.numChannels,
                        mask,
                        count);
                    result = SL_RESULT_PARAMETER_INVALID;
                    break;
                }

                SL_LOGV("%s: final channel mask is 0x%x", name, pDataFormat->mPCM.channelMask);

                // check the endianness / byte order
                switch (pDataFormat->mPCM.endianness) {
                case SL_BYTEORDER_LITTLEENDIAN:
                case SL_BYTEORDER_BIGENDIAN:
                    break;
                // native is proposed but not yet in spec
                default:
                    result = SL_RESULT_PARAMETER_INVALID;
                    break;
                }
                if (SL_RESULT_SUCCESS != result) {
                    SL_LOGE("%s: endianness=%u", name, (unsigned) pDataFormat->mPCM.endianness);
                    break;
                }

                // here if all checks passed successfully

            } while(0);
            break;

        case SL_DATAFORMAT_MIME:
            pDataFormat->mMIME = *(SLDataFormat_MIME *)pFormat;
            if (NULL != pDataFormat->mMIME.mimeType) {
                // NTH check address for validity
                size_t len = strlen((const char *) pDataFormat->mMIME.mimeType);
                SLchar *myMIME = (SLchar *) malloc(len + 1);
                if (NULL == myMIME) {
                    result = SL_RESULT_MEMORY_FAILURE;
                } else {
                    memcpy(myMIME, pDataFormat->mMIME.mimeType, len + 1);
                    // make sure MIME string was not modified asynchronously
                    if ('\0' != myMIME[len]) {
                        free(myMIME);
                        myMIME = NULL;
                        result = SL_RESULT_PRECONDITIONS_VIOLATED;
                    }
                }
                pDataFormat->mMIME.mimeType = myMIME;
            }
            break;

        case XA_DATAFORMAT_RAWIMAGE:
            pDataFormat->mRawImage = *(XADataFormat_RawImage *)pFormat;
            switch (pDataFormat->mRawImage.colorFormat) {
            case XA_COLORFORMAT_MONOCHROME:
            case XA_COLORFORMAT_8BITRGB332:
            case XA_COLORFORMAT_12BITRGB444:
            case XA_COLORFORMAT_16BITARGB4444:
            case XA_COLORFORMAT_16BITARGB1555:
            case XA_COLORFORMAT_16BITRGB565:
            case XA_COLORFORMAT_16BITBGR565:
            case XA_COLORFORMAT_18BITRGB666:
            case XA_COLORFORMAT_18BITARGB1665:
            case XA_COLORFORMAT_19BITARGB1666:
            case XA_COLORFORMAT_24BITRGB888:
            case XA_COLORFORMAT_24BITBGR888:
            case XA_COLORFORMAT_24BITARGB1887:
            case XA_COLORFORMAT_25BITARGB1888:
            case XA_COLORFORMAT_32BITBGRA8888:
            case XA_COLORFORMAT_32BITARGB8888:
            case XA_COLORFORMAT_YUV411PLANAR:
            case XA_COLORFORMAT_YUV420PLANAR:
            case XA_COLORFORMAT_YUV420SEMIPLANAR:
            case XA_COLORFORMAT_YUV422PLANAR:
            case XA_COLORFORMAT_YUV422SEMIPLANAR:
            case XA_COLORFORMAT_YCBYCR:
            case XA_COLORFORMAT_YCRYCB:
            case XA_COLORFORMAT_CBYCRY:
            case XA_COLORFORMAT_CRYCBY:
            case XA_COLORFORMAT_YUV444INTERLEAVED:
            case XA_COLORFORMAT_RAWBAYER8BIT:
            case XA_COLORFORMAT_RAWBAYER10BIT:
            case XA_COLORFORMAT_RAWBAYER8BITCOMPRESSED:
            case XA_COLORFORMAT_L2:
            case XA_COLORFORMAT_L4:
            case XA_COLORFORMAT_L8:
            case XA_COLORFORMAT_L16:
            case XA_COLORFORMAT_L24:
            case XA_COLORFORMAT_L32:
            case XA_COLORFORMAT_18BITBGR666:
            case XA_COLORFORMAT_24BITARGB6666:
            case XA_COLORFORMAT_24BITABGR6666:
                break;
            case XA_COLORFORMAT_UNUSED:
            default:
                result = XA_RESULT_PARAMETER_INVALID;
                SL_LOGE("%s: unsupported color format %d", name,
                    pDataFormat->mRawImage.colorFormat);
                break;
            }
            // no checks for height, width, or stride
            break;

        default:
            result = SL_RESULT_PARAMETER_INVALID;
            SL_LOGE("%s: formatType=%u", name, (unsigned) formatType);
            break;

        }

        // make sure format type was not modified asynchronously
        if ((SL_RESULT_SUCCESS == result) && (formatType != pDataFormat->mFormatType)) {
            SL_LOGE("%s: formatType changed from %u to %u", name, formatType,
                    pDataFormat->mFormatType);
            result = SL_RESULT_PRECONDITIONS_VIOLATED;
        }

    }

    // Verify that the data format type is allowed in this context
    if (SL_RESULT_SUCCESS == result) {
        SLuint32 actualMask;
        switch (formatType) {
        case SL_DATAFORMAT_NULL:
        case SL_DATAFORMAT_MIME:
        case SL_DATAFORMAT_PCM:
        case SL_ANDROID_DATAFORMAT_PCM_EX:
        case XA_DATAFORMAT_RAWIMAGE:
            actualMask = 1L << formatType;
            break;
        default:
            assert(false);
            actualMask = 0L;
            break;
        }
        if (!(allowedDataFormatMask & actualMask)) {
            SL_LOGE("%s: data format %d not allowed", name, formatType);
            result = SL_RESULT_CONTENT_UNSUPPORTED;
        }
    }

    return result;
}
Esempio n. 6
0
SLresult checkInterfaces(const ClassTable *clazz, SLuint32 numInterfaces,
    const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired,
    unsigned *pExposedMask, unsigned *pRequiredMask)
{
    assert(NULL != clazz && NULL != pExposedMask);
    // Initially no interfaces are exposed
    unsigned exposedMask = 0;
    unsigned requiredMask = 0;
    const struct iid_vtable *interfaces = clazz->mInterfaces;
    SLuint32 interfaceCount = clazz->mInterfaceCount;
    SLuint32 i;
    // Expose all implicit interfaces
    for (i = 0; i < interfaceCount; ++i) {
        switch (interfaces[i].mInterface) {
        case INTERFACE_IMPLICIT:
        case INTERFACE_IMPLICIT_PREREALIZE:
            // there must be an initialization hook present
            if (NULL != MPH_init_table[interfaces[i].mMPH].mInit) {
                exposedMask |= 1 << i;
            }
            break;
        case INTERFACE_EXPLICIT:
        case INTERFACE_DYNAMIC:
        case INTERFACE_UNAVAILABLE:
        case INTERFACE_EXPLICIT_PREREALIZE:
            break;
        default:
            assert(false);
            break;
        }
    }
    if (0 < numInterfaces) {
        if (NULL == pInterfaceIds || NULL == pInterfaceRequired) {
            return SL_RESULT_PARAMETER_INVALID;
        }
        bool anyRequiredButUnsupported = false;
        // Loop for each requested interface
        for (i = 0; i < numInterfaces; ++i) {
            SLInterfaceID iid = pInterfaceIds[i];
            if (NULL == iid) {
                return SL_RESULT_PARAMETER_INVALID;
            }
            SLboolean isRequired = pInterfaceRequired[i];
            int MPH, index;
            if ((0 > (MPH = IID_to_MPH(iid))) ||
                    // there must be an initialization hook present
                    (NULL == MPH_init_table[MPH].mInit) ||
                    (0 > (index = clazz->mMPH_to_index[MPH])) ||
                    (INTERFACE_UNAVAILABLE == interfaces[index].mInterface)) {
                // Here if interface was not found, or is not available for this object type
                if (isRequired) {
                    // Application said it required the interface, so give up
                    SL_LOGE("class %s interface %u required but unavailable MPH=%d",
                            clazz->mName, i, MPH);
                    anyRequiredButUnsupported = true;
                }
                // Application said it didn't really need the interface, so ignore with warning
                SL_LOGW("class %s interface %u requested but unavailable MPH=%d",
                        clazz->mName, i, MPH);
                continue;
            }
            if (isRequired) {
                requiredMask |= (1 << index);
            }
            // The requested interface was both found and available, so expose it
            exposedMask |= (1 << index);
            // Note that we ignore duplicate requests, including equal and aliased IDs
        }
        if (anyRequiredButUnsupported) {
            return SL_RESULT_FEATURE_UNSUPPORTED;
        }
    }
    *pExposedMask = exposedMask;
    if (NULL != pRequiredMask) {
        *pRequiredMask = requiredMask;
    }
    return SL_RESULT_SUCCESS;
}
// Called from android_audioRecorder_realize for a PCM buffer queue recorder before creating the
// AudioRecord to determine which performance modes are allowed based on effect interfaces present
static void checkAndSetPerformanceModePre(CAudioRecorder* ar)
{
    SLuint32 allowedModes = ANDROID_PERFORMANCE_MODE_ALL;
    assert(ar->mAndroidObjType == AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE);

    // no need to check the buffer queue size, application side
    // double-buffering (and more) is not a requirement for using fast tracks

    // Check a blacklist of interfaces that are incompatible with fast tracks.
    // The alternative, to check a whitelist of compatible interfaces, is
    // more maintainable but is too slow.  As a compromise, in a debug build
    // we use both methods and warn if they produce different results.
    // In release builds, we only use the blacklist method.
    // If a blacklisted interface is added after realization using
    // DynamicInterfaceManagement::AddInterface,
    // then this won't be detected but the interface will be ineffective.
    static const unsigned blacklist[] = {
        MPH_ANDROIDACOUSTICECHOCANCELLATION,
        MPH_ANDROIDAUTOMATICGAINCONTROL,
        MPH_ANDROIDNOISESUPPRESSION,
        MPH_ANDROIDEFFECT,
        // FIXME The problem with a blacklist is remembering to add new interfaces here
    };

    for (unsigned i = 0; i < sizeof(blacklist)/sizeof(blacklist[0]); ++i) {
        if (IsInterfaceInitialized(&ar->mObject, blacklist[i])) {
            uint32_t flags = 0;

            allowedModes &= ~ANDROID_PERFORMANCE_MODE_LATENCY;

            // if generic effect interface is used we don't know which effect will be used and
            // disable all low latency performance modes
            if (blacklist[i] != MPH_ANDROIDEFFECT) {
                switch (blacklist[i]) {
                case MPH_ANDROIDACOUSTICECHOCANCELLATION:
                    SL_LOGV("checkAndSetPerformanceModePre found AEC name %s",
                            ar->mAcousticEchoCancellation.mAECDescriptor.name);
                    flags = ar->mAcousticEchoCancellation.mAECDescriptor.flags;
                    break;
                case MPH_ANDROIDAUTOMATICGAINCONTROL:
                    SL_LOGV("checkAndSetPerformanceModePre found AGC name %s",
                            ar->mAutomaticGainControl.mAGCDescriptor.name);
                    flags = ar->mAutomaticGainControl.mAGCDescriptor.flags;
                    break;
                case MPH_ANDROIDNOISESUPPRESSION:
                    SL_LOGV("checkAndSetPerformanceModePre found NS name %s",
                            ar->mNoiseSuppression.mNSDescriptor.name);
                    flags = ar->mNoiseSuppression.mNSDescriptor.flags;
                    break;
                default:
                    break;
                }
            }
            if ((flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) {
                allowedModes &= ~ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
                break;
            }
        }
    }
#if LOG_NDEBUG == 0
    bool blacklistResult = (
            (allowedModes &
                (ANDROID_PERFORMANCE_MODE_LATENCY|ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS)) != 0);
    bool whitelistResult = true;
    static const unsigned whitelist[] = {
        MPH_BUFFERQUEUE,
        MPH_DYNAMICINTERFACEMANAGEMENT,
        MPH_OBJECT,
        MPH_RECORD,
        MPH_ANDROIDCONFIGURATION,
        MPH_ANDROIDSIMPLEBUFFERQUEUE,
    };
    for (unsigned mph = MPH_MIN; mph < MPH_MAX; ++mph) {
        for (unsigned i = 0; i < sizeof(whitelist)/sizeof(whitelist[0]); ++i) {
            if (mph == whitelist[i]) {
                goto compatible;
            }
        }
        if (IsInterfaceInitialized(&ar->mObject, mph)) {
            whitelistResult = false;
            break;
        }
compatible: ;
    }
    if (whitelistResult != blacklistResult) {
        SL_LOGW("whitelistResult != blacklistResult");
    }
#endif
    if (ar->mPerformanceMode == ANDROID_PERFORMANCE_MODE_LATENCY) {
        if ((allowedModes & ANDROID_PERFORMANCE_MODE_LATENCY) == 0) {
            ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
        }
    }
    if (ar->mPerformanceMode == ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) {
        if ((allowedModes & ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) == 0) {
            ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_NONE;
        }
    }
}