/* * 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. */ /* OpenSL ES private and global functions not associated with an interface or class */ #include "sles_allinclusive.h" /** \brief Return true if the specified interface exists and has been initialized for this object. * Returns false if the class does not support this kind of interface, or the class supports the * interface but this particular object has not had the interface exposed at object creation time * or by DynamicInterface::AddInterface. Note that the return value is not affected by whether * the application has requested access to the interface with Object::GetInterface. Assumes on * entry that the object is locked for either shared or exclusive access. */ bool IsInterfaceInitialized(IObject *this, unsigned MPH) { assert(NULL != this); assert( /* (MPH_MIN <= MPH) && */ (MPH < (unsigned) MPH_MAX)); const ClassTable *class__ = this->mClass; assert(NULL != class__); int index; if (0 > (index = class__->mMPH_to_index[MPH])) { return false; } assert(MAX_INDEX >= class__->mInterfaceCount); assert(class__->mInterfaceCount > (unsigned) index); switch (this->mInterfaceStates[index]) { case INTERFACE_EXPOSED: case INTERFACE_ADDED: return true; default: return false; } } /** \brief Map an IObject to it's "object ID" (which is really a class ID) */ SLuint32 IObjectToObjectID(IObject *this) { assert(NULL != this); return this->mClass->mObjectID; } /** \brief Acquire a strong reference to an object. * Check that object has the specified "object ID" (which is really a class ID) and is in the * realized state. If so, then acquire a strong reference to it and return true. * Otherwise return false. */ SLresult AcquireStrongRef(IObject *object, SLuint32 expectedObjectID) { if (NULL == object) { return SL_RESULT_PARAMETER_INVALID; } // NTH additional validity checks on address here SLresult result; object_lock_exclusive(object); SLuint32 actualObjectID = IObjectToObjectID(object); if (expectedObjectID != actualObjectID) { SL_LOGE("object %p has object ID %lu but expected %lu", object, actualObjectID, expectedObjectID); result = SL_RESULT_PARAMETER_INVALID; } else if (SL_OBJECT_STATE_REALIZED != object->mState) { SL_LOGE("object %p with object ID %lu is not realized", object, actualObjectID); result = SL_RESULT_PRECONDITIONS_VIOLATED; } else { ++object->mStrongRefCount; result = SL_RESULT_SUCCESS; } object_unlock_exclusive(object); return result; } /** \brief Release a strong reference to an object. * Entry condition: the object is locked. * Exit condition: the object is unlocked. * Finishes the destroy if needed. */ void ReleaseStrongRefAndUnlockExclusive(IObject *object) { #ifdef USE_DEBUG assert(pthread_equal(pthread_self(), object->mOwner)); #endif assert(0 < object->mStrongRefCount); if ((0 == --object->mStrongRefCount) && (SL_OBJECT_STATE_DESTROYING == object->mState)) { // FIXME do the destroy here - merge with IDestroy // but can't do this until we move Destroy to the sync thread // as Destroy is now a blocking operation, and to avoid a race } else { object_unlock_exclusive(object); } } /** \brief Release a strong reference to an object. * Entry condition: the object is unlocked. * Exit condition: the object is unlocked. * Finishes the destroy if needed. */ void ReleaseStrongRef(IObject *object) { assert(NULL != object); object_lock_exclusive(object); ReleaseStrongRefAndUnlockExclusive(object); } /** \brief Convert POSIX pthread error code to OpenSL ES result code */ SLresult err_to_result(int err) { if (EAGAIN == err || ENOMEM == err) { return SL_RESULT_RESOURCE_ERROR; } if (0 != err) { return SL_RESULT_INTERNAL_ERROR; } return SL_RESULT_SUCCESS; } /** \brief Check the interface IDs passed into a Create operation */ SLresult checkInterfaces(const ClassTable *class__, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired, unsigned *pExposedMask) { assert(NULL != class__ && NULL != pExposedMask); // Initially no interfaces are exposed unsigned exposedMask = 0; const struct iid_vtable *interfaces = class__->mInterfaces; SLuint32 interfaceCount = class__->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; } 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 = class__->mMPH_to_index[MPH])) || (INTERFACE_UNAVAILABLE == interfaces[index].mInterface)) { // Here if interface was not found, or is not available for this object type if (pInterfaceRequired[i]) { // Application said it required the interface, so give up SL_LOGE("class %s interface %lu required but unavailable MPH=%d", class__->mName, i, MPH); anyRequiredButUnsupported = true; } // Application said it didn't really need the interface, so ignore with warning SL_LOGW("class %s interface %lu requested but unavailable MPH=%d", class__->mName, i, MPH); continue; } // 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; return SL_RESULT_SUCCESS; } /** \brief Helper shared by decoder and encoder */ SLresult GetCodecCapabilities(SLuint32 codecId, SLuint32 *pIndex, SLAudioCodecDescriptor *pDescriptor, const CodecDescriptor *codecDescriptors) { if (NULL == pIndex) { return SL_RESULT_PARAMETER_INVALID; } const CodecDescriptor *cd = codecDescriptors; SLuint32 index; if (NULL == pDescriptor) { for (index = 0 ; NULL != cd->mDescriptor; ++cd) { if (cd->mCodecID == codecId) { ++index; } } *pIndex = index; return SL_RESULT_SUCCESS; } index = *pIndex; for ( ; NULL != cd->mDescriptor; ++cd) { if (cd->mCodecID == codecId) { if (0 == index) { *pDescriptor = *cd->mDescriptor; #if 0 // Temporary workaround for Khronos bug 6331 if (0 < pDescriptor->numSampleRatesSupported) { // The malloc is not in the 1.0.1 specification SLmilliHertz *temp = (SLmilliHertz *) malloc(sizeof(SLmilliHertz) * pDescriptor->numSampleRatesSupported); assert(NULL != temp); memcpy(temp, pDescriptor->pSampleRatesSupported, sizeof(SLmilliHertz) * pDescriptor->numSampleRatesSupported); pDescriptor->pSampleRatesSupported = temp; } else { pDescriptor->pSampleRatesSupported = NULL; } #endif return SL_RESULT_SUCCESS; } --index; } } return SL_RESULT_PARAMETER_INVALID; } /** \brief Check a data locator and make local deep copy */ static SLresult checkDataLocator(void *pLocator, DataLocator *pDataLocator) { if (NULL == pLocator) { pDataLocator->mLocatorType = SL_DATALOCATOR_NULL; return SL_RESULT_SUCCESS; } SLresult result; SLuint32 locatorType = *(SLuint32 *)pLocator; switch (locatorType) { case SL_DATALOCATOR_ADDRESS: pDataLocator->mAddress = *(SLDataLocator_Address *)pLocator; // if length is greater than zero, then the address must be non-NULL if ((0 < pDataLocator->mAddress.length) && (NULL == pDataLocator->mAddress.pAddress)) { SL_LOGE("pAddress is NULL"); return SL_RESULT_PARAMETER_INVALID; } break; case SL_DATALOCATOR_BUFFERQUEUE: #ifdef ANDROID // This is an alias that is _not_ converted; the rest of the code must check for both locator // types. That's because it is only an alias for audio players, not audio recorder objects // so we have to remember the distinction. case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: #endif pDataLocator->mBufferQueue = *(SLDataLocator_BufferQueue *)pLocator; // number of buffers must be specified, there is no default value, and must not be excessive if (!((1 <= pDataLocator->mBufferQueue.numBuffers) && (pDataLocator->mBufferQueue.numBuffers <= 255))) { SL_LOGE("numBuffers=%u", (unsigned) pDataLocator->mBufferQueue.numBuffers); return SL_RESULT_PARAMETER_INVALID; } break; case SL_DATALOCATOR_IODEVICE: { pDataLocator->mIODevice = *(SLDataLocator_IODevice *)pLocator; SLuint32 deviceType = pDataLocator->mIODevice.deviceType; SLObjectItf device = pDataLocator->mIODevice.device; if (NULL != device) { pDataLocator->mIODevice.deviceID = 0; SLuint32 expectedObjectID; switch (deviceType) { case SL_IODEVICE_LEDARRAY: expectedObjectID = SL_OBJECTID_LEDDEVICE; break; case SL_IODEVICE_VIBRA: expectedObjectID = SL_OBJECTID_VIBRADEVICE; break; // audio input and audio output cannot be specified via objects case SL_IODEVICE_AUDIOINPUT: // worse yet, an SL_IODEVICE enum constant for audio output does not exist yet // case SL_IODEVICE_AUDIOOUTPUT: default: SL_LOGE("invalid deviceType %lu", deviceType); pDataLocator->mIODevice.device = NULL; return SL_RESULT_PARAMETER_INVALID; } // check that device has the correct object ID and is realized, // and acquire a strong reference to it result = AcquireStrongRef((IObject *) device, expectedObjectID); if (SL_RESULT_SUCCESS != result) { SL_LOGE("locator type is IODEVICE, but device field %p has wrong object ID or is " \ "not realized", device); pDataLocator->mIODevice.device = NULL; return result; } } else { SLuint32 deviceID = pDataLocator->mIODevice.deviceID; switch (deviceType) { case SL_IODEVICE_LEDARRAY: if (SL_DEFAULTDEVICEID_LED != deviceID) { SL_LOGE("invalid LED deviceID %lu", deviceID); return SL_RESULT_PARAMETER_INVALID; } break; case SL_IODEVICE_VIBRA: if (SL_DEFAULTDEVICEID_VIBRA != deviceID) { SL_LOGE("invalid vibra deviceID %lu", deviceID); return SL_RESULT_PARAMETER_INVALID; } break; case SL_IODEVICE_AUDIOINPUT: if (SL_DEFAULTDEVICEID_AUDIOINPUT != deviceID) { SL_LOGE("invalid audio input deviceID %lu", deviceID); return SL_RESULT_PARAMETER_INVALID; } break; default: SL_LOGE("invalid deviceType %lu", deviceType); return SL_RESULT_PARAMETER_INVALID; } } } break; case SL_DATALOCATOR_MIDIBUFFERQUEUE: pDataLocator->mMIDIBufferQueue = *(SLDataLocator_MIDIBufferQueue *)pLocator; if (0 == pDataLocator->mMIDIBufferQueue.tpqn) { pDataLocator->mMIDIBufferQueue.tpqn = 192; } // number of buffers must be specified, there is no default value, and must not be excessive if (!((1 <= pDataLocator->mMIDIBufferQueue.numBuffers) && (pDataLocator->mMIDIBufferQueue.numBuffers <= 255))) { SL_LOGE("invalid MIDI buffer queue"); return SL_RESULT_PARAMETER_INVALID; } break; case SL_DATALOCATOR_OUTPUTMIX: pDataLocator->mOutputMix = *(SLDataLocator_OutputMix *)pLocator; // check that output mix object has the correct object ID and is realized, // and acquire a strong reference to it result = AcquireStrongRef((IObject *) pDataLocator->mOutputMix.outputMix, SL_OBJECTID_OUTPUTMIX); if (SL_RESULT_SUCCESS != result) { SL_LOGE("locatorType is SL_DATALOCATOR_OUTPUTMIX, but outputMix field %p does not " \ "refer to an SL_OBJECTID_OUTPUTMIX or the output mix is not realized", \ pDataLocator->mOutputMix.outputMix); pDataLocator->mOutputMix.outputMix = NULL; return result; } break; case SL_DATALOCATOR_URI: { pDataLocator->mURI = *(SLDataLocator_URI *)pLocator; if (NULL == pDataLocator->mURI.URI) { SL_LOGE("invalid URI"); return SL_RESULT_PARAMETER_INVALID; } // NTH verify URI address for validity size_t len = strlen((const char *) pDataLocator->mURI.URI); SLchar *myURI = (SLchar *) malloc(len + 1); if (NULL == myURI) { pDataLocator->mURI.URI = NULL; return SL_RESULT_MEMORY_FAILURE; } memcpy(myURI, pDataLocator->mURI.URI, len + 1); // Verify that another thread didn't change the NUL-terminator after we used it // to determine length of string to copy. It's OK if the string became shorter. if ('\0' != myURI[len]) { free(myURI); pDataLocator->mURI.URI = NULL; return SL_RESULT_PARAMETER_INVALID; } pDataLocator->mURI.URI = myURI; } break; #ifdef ANDROID case SL_DATALOCATOR_ANDROIDFD: { pDataLocator->mFD = *(SLDataLocator_AndroidFD *)pLocator; SL_LOGV("Data locator FD: fd=%ld offset=%lld length=%lld", pDataLocator->mFD.fd, pDataLocator->mFD.offset, pDataLocator->mFD.length); // NTH check against process fd limit if (0 > pDataLocator->mFD.fd) { return SL_RESULT_PARAMETER_INVALID; } } break; #endif default: SL_LOGE("invalid locatorType %lu", locatorType); return SL_RESULT_PARAMETER_INVALID; } // Verify that another thread didn't change the locatorType field after we used it // to determine sizeof struct to copy. if (locatorType != pDataLocator->mLocatorType) { return SL_RESULT_PARAMETER_INVALID; } return SL_RESULT_SUCCESS; } /** \brief Free the local deep copy of a data locator */ static void freeDataLocator(DataLocator *pDataLocator) { switch (pDataLocator->mLocatorType) { case SL_DATALOCATOR_URI: if (NULL != pDataLocator->mURI.URI) { free(pDataLocator->mURI.URI); pDataLocator->mURI.URI = NULL; } pDataLocator->mURI.URI = NULL; break; case SL_DATALOCATOR_IODEVICE: if (NULL != pDataLocator->mIODevice.device) { ReleaseStrongRef((IObject *) pDataLocator->mIODevice.device); pDataLocator->mIODevice.device = NULL; } break; case SL_DATALOCATOR_OUTPUTMIX: if (NULL != pDataLocator->mOutputMix.outputMix) { ReleaseStrongRef((IObject *) pDataLocator->mOutputMix.outputMix); pDataLocator->mOutputMix.outputMix = NULL; } break; default: break; } } /** \brief Check a data format and make local deep copy */ static SLresult checkDataFormat(void *pFormat, DataFormat *pDataFormat) { SLresult result = SL_RESULT_SUCCESS; if (NULL == pFormat) { pDataFormat->mFormatType = SL_DATAFORMAT_NULL; } else { SLuint32 formatType = *(SLuint32 *)pFormat; switch (formatType) { case SL_DATAFORMAT_PCM: pDataFormat->mPCM = *(SLDataFormat_PCM *)pFormat; do { // check the channel count switch (pDataFormat->mPCM.numChannels) { case 1: // mono case 2: // stereo break; case 0: // unknown result = SL_RESULT_PARAMETER_INVALID; break; default: // multi-channel result = SL_RESULT_CONTENT_UNSUPPORTED; break; } if (SL_RESULT_SUCCESS != result) { SL_LOGE("numChannels=%u", (unsigned) pDataFormat->mPCM.numChannels); break; } // check the sampling rate switch (pDataFormat->mPCM.samplesPerSec) { case SL_SAMPLINGRATE_8: case SL_SAMPLINGRATE_11_025: case SL_SAMPLINGRATE_12: case SL_SAMPLINGRATE_16: case SL_SAMPLINGRATE_22_05: case SL_SAMPLINGRATE_24: case SL_SAMPLINGRATE_32: case SL_SAMPLINGRATE_44_1: case SL_SAMPLINGRATE_48: case SL_SAMPLINGRATE_64: case SL_SAMPLINGRATE_88_2: case SL_SAMPLINGRATE_96: case SL_SAMPLINGRATE_192: break; case 0: result = SL_RESULT_PARAMETER_INVALID; break; default: result = SL_RESULT_CONTENT_UNSUPPORTED; break; } if (SL_RESULT_SUCCESS != result) { SL_LOGE("samplesPerSec=%u", (unsigned) pDataFormat->mPCM.samplesPerSec); break; } // check the sample bit depth switch (pDataFormat->mPCM.bitsPerSample) { case SL_PCMSAMPLEFORMAT_FIXED_8: case SL_PCMSAMPLEFORMAT_FIXED_16: break; case SL_PCMSAMPLEFORMAT_FIXED_20: case SL_PCMSAMPLEFORMAT_FIXED_24: case SL_PCMSAMPLEFORMAT_FIXED_28: case SL_PCMSAMPLEFORMAT_FIXED_32: result = SL_RESULT_CONTENT_UNSUPPORTED; break; default: result = SL_RESULT_PARAMETER_INVALID; break; } if (SL_RESULT_SUCCESS != result) { SL_LOGE("bitsPerSample=%u", (unsigned) pDataFormat->mPCM.bitsPerSample); break; } // check the container bit depth if (pDataFormat->mPCM.containerSize < pDataFormat->mPCM.bitsPerSample) { result = SL_RESULT_PARAMETER_INVALID; } else if (pDataFormat->mPCM.containerSize != pDataFormat->mPCM.bitsPerSample) { result = SL_RESULT_CONTENT_UNSUPPORTED; } if (SL_RESULT_SUCCESS != result) { SL_LOGE("containerSize=%u, bitsPerSample=%u", (unsigned) pDataFormat->mPCM.containerSize, (unsigned) pDataFormat->mPCM.bitsPerSample); break; } // check the channel mask switch (pDataFormat->mPCM.channelMask) { case SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT: if (2 != pDataFormat->mPCM.numChannels) { result = SL_RESULT_PARAMETER_INVALID; } break; case SL_SPEAKER_FRONT_LEFT: case SL_SPEAKER_FRONT_RIGHT: case SL_SPEAKER_FRONT_CENTER: if (1 != pDataFormat->mPCM.numChannels) { result = SL_RESULT_PARAMETER_INVALID; } break; case 0: pDataFormat->mPCM.channelMask = pDataFormat->mPCM.numChannels == 2 ? SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT : SL_SPEAKER_FRONT_CENTER; break; default: result = SL_RESULT_PARAMETER_INVALID; break; } if (SL_RESULT_SUCCESS != result) { SL_LOGE("channelMask=0x%lx numChannels=%lu", pDataFormat->mPCM.channelMask, pDataFormat->mPCM.numChannels); break; } // 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("endianness=%u", (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; default: result = SL_RESULT_PARAMETER_INVALID; SL_LOGE("formatType=%u", (unsigned) formatType); break; } // make sure format type was not modified asynchronously if ((SL_RESULT_SUCCESS == result) && (formatType != pDataFormat->mFormatType)) { result = SL_RESULT_PRECONDITIONS_VIOLATED; } } return result; } /** \brief Check interface ID compatibility with respect to a particular data locator format */ SLresult checkSourceFormatVsInterfacesCompatibility(const DataLocatorFormat *pDataLocatorFormat, const ClassTable *class__, unsigned exposedMask) { int index; switch (pDataLocatorFormat->mLocator.mLocatorType) { case SL_DATALOCATOR_BUFFERQUEUE: #ifdef ANDROID case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: #endif // can't request SLSeekItf if data source is a buffer queue index = class__->mMPH_to_index[MPH_SEEK]; if (0 <= index) { if (exposedMask & (1 << index)) { SL_LOGE("can't request SL_IID_SEEK with a buffer queue data source"); return SL_RESULT_FEATURE_UNSUPPORTED; } } // can't request SLMuteSoloItf if data source is a mono buffer queue index = class__->mMPH_to_index[MPH_MUTESOLO]; if (0 <= index) { if ((exposedMask & (1 << index)) && (SL_DATAFORMAT_PCM == pDataLocatorFormat->mFormat.mFormatType) && (1 == pDataLocatorFormat->mFormat.mPCM.numChannels)) { SL_LOGE("can't request SL_IID_MUTESOLO with a mono buffer queue data source"); return SL_RESULT_FEATURE_UNSUPPORTED; } } break; default: // can't request SLBufferQueueItf or its alias SLAndroidSimpleBufferQueueItf // if the data source is not a buffer queue index = class__->mMPH_to_index[MPH_BUFFERQUEUE]; #ifdef ANDROID assert(index == class__->mMPH_to_index[MPH_ANDROIDSIMPLEBUFFERQUEUE]); #endif if (0 <= index) { if (exposedMask & (1 << index)) { SL_LOGE("can't request SL_IID_BUFFERQUEUE " #ifdef ANDROID "or SL_IID_ANDROIDSIMPLEBUFFERQUEUE " #endif "with a non-buffer queue data source"); return SL_RESULT_FEATURE_UNSUPPORTED; } } break; } return SL_RESULT_SUCCESS; } /** \brief Free the local deep copy of a data format */ static void freeDataFormat(DataFormat *pDataFormat) { switch (pDataFormat->mFormatType) { case SL_DATAFORMAT_MIME: if (NULL != pDataFormat->mMIME.mimeType) { free(pDataFormat->mMIME.mimeType); pDataFormat->mMIME.mimeType = NULL; } break; default: break; } } /** \brief Check a data source and make local deep copy */ SLresult checkDataSource(const SLDataSource *pDataSrc, DataLocatorFormat *pDataLocatorFormat) { if (NULL == pDataSrc) { SL_LOGE("pDataSrc NULL"); return SL_RESULT_PARAMETER_INVALID; } SLDataSource myDataSrc = *pDataSrc; SLresult result; result = checkDataLocator(myDataSrc.pLocator, &pDataLocatorFormat->mLocator); if (SL_RESULT_SUCCESS != result) { return result; } switch (pDataLocatorFormat->mLocator.mLocatorType) { case SL_DATALOCATOR_URI: case SL_DATALOCATOR_ADDRESS: case SL_DATALOCATOR_BUFFERQUEUE: case SL_DATALOCATOR_MIDIBUFFERQUEUE: #ifdef ANDROID case SL_DATALOCATOR_ANDROIDFD: case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: #endif result = checkDataFormat(myDataSrc.pFormat, &pDataLocatorFormat->mFormat); if (SL_RESULT_SUCCESS != result) { freeDataLocator(&pDataLocatorFormat->mLocator); return result; } break; case SL_DATALOCATOR_NULL: case SL_DATALOCATOR_OUTPUTMIX: default: // invalid but fall through; the invalid locator will be caught later SL_LOGE("mLocatorType=%u", (unsigned) pDataLocatorFormat->mLocator.mLocatorType); // keep going case SL_DATALOCATOR_IODEVICE: // for these data locator types, ignore the pFormat as it might be uninitialized pDataLocatorFormat->mFormat.mFormatType = SL_DATAFORMAT_NULL; break; } pDataLocatorFormat->u.mSource.pLocator = &pDataLocatorFormat->mLocator; pDataLocatorFormat->u.mSource.pFormat = &pDataLocatorFormat->mFormat; return SL_RESULT_SUCCESS; } /** \brief Check a data sink and make local deep copy */ SLresult checkDataSink(const SLDataSink *pDataSink, DataLocatorFormat *pDataLocatorFormat, SLuint32 objType) { if (NULL == pDataSink) { SL_LOGE("pDataSink NULL"); return SL_RESULT_PARAMETER_INVALID; } SLDataSink myDataSink = *pDataSink; SLresult result; result = checkDataLocator(myDataSink.pLocator, &pDataLocatorFormat->mLocator); if (SL_RESULT_SUCCESS != result) { return result; } switch (pDataLocatorFormat->mLocator.mLocatorType) { case SL_DATALOCATOR_URI: case SL_DATALOCATOR_ADDRESS: result = checkDataFormat(myDataSink.pFormat, &pDataLocatorFormat->mFormat); if (SL_RESULT_SUCCESS != result) { freeDataLocator(&pDataLocatorFormat->mLocator); return result; } break; case SL_DATALOCATOR_BUFFERQUEUE: #ifdef ANDROID case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: #endif if (SL_OBJECTID_AUDIOPLAYER == objType) { SL_LOGE("buffer queue can't be used as data sink for audio player"); result = SL_RESULT_PARAMETER_INVALID; } else if (SL_OBJECTID_AUDIORECORDER == objType) { #ifdef ANDROID if (SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE != pDataLocatorFormat->mLocator.mLocatorType) { SL_LOGE("audio recorder source locator must be SL_DATALOCATOR_ANDROIDBUFFERQUEUE"); result = SL_RESULT_PARAMETER_INVALID; } else { result = checkDataFormat(myDataSink.pFormat, &pDataLocatorFormat->mFormat); } #else SL_LOGE("mLocatorType=%u", (unsigned) pDataLocatorFormat->mLocator.mLocatorType); result = SL_RESULT_PARAMETER_INVALID; #endif } if (SL_RESULT_SUCCESS != result) { freeDataLocator(&pDataLocatorFormat->mLocator); return result; } break; case SL_DATALOCATOR_NULL: case SL_DATALOCATOR_MIDIBUFFERQUEUE: default: // invalid but fall through; the invalid locator will be caught later SL_LOGE("mLocatorType=%u", (unsigned) pDataLocatorFormat->mLocator.mLocatorType); // keep going case SL_DATALOCATOR_IODEVICE: case SL_DATALOCATOR_OUTPUTMIX: // for these data locator types, ignore the pFormat as it might be uninitialized pDataLocatorFormat->mFormat.mFormatType = SL_DATAFORMAT_NULL; break; } pDataLocatorFormat->u.mSink.pLocator = &pDataLocatorFormat->mLocator; pDataLocatorFormat->u.mSink.pFormat = &pDataLocatorFormat->mFormat; return SL_RESULT_SUCCESS; } /** \brief Free the local deep copy of a data locator format */ void freeDataLocatorFormat(DataLocatorFormat *dlf) { freeDataLocator(&dlf->mLocator); freeDataFormat(&dlf->mFormat); } /* Interface initialization hooks */ extern void I3DCommit_init(void *), I3DDoppler_init(void *), I3DGrouping_init(void *), I3DLocation_init(void *), I3DMacroscopic_init(void *), I3DSource_init(void *), IAndroidConfiguration_init(void *), IAndroidEffect_init(void *), IAndroidEffectCapabilities_init(void *), IAndroidEffectSend_init(void *), IAudioDecoderCapabilities_init(void *), IAudioEncoder_init(void *), IAudioEncoderCapabilities_init(void *), IAudioIODeviceCapabilities_init(void *), IBassBoost_init(void *), IBufferQueue_init(void *), IDeviceVolume_init(void *), IDynamicInterfaceManagement_init(void *), IDynamicSource_init(void *), IEffectSend_init(void *), IEngine_init(void *), IEngineCapabilities_init(void *), IEnvironmentalReverb_init(void *), IEqualizer_init(void *), ILEDArray_init(void *), IMIDIMessage_init(void *), IMIDIMuteSolo_init(void *), IMIDITempo_init(void *), IMIDITime_init(void *), IMetadataExtraction_init(void *), IMetadataTraversal_init(void *), IMuteSolo_init(void *), IObject_init(void *), IOutputMix_init(void *), IOutputMixExt_init(void *), IPitch_init(void *), IPlay_init(void *), IPlaybackRate_init(void *), IPrefetchStatus_init(void *), IPresetReverb_init(void *), IRatePitch_init(void *), IRecord_init(void *), ISeek_init(void *), IThreadSync_init(void *), IVibra_init(void *), IVirtualizer_init(void *), IVisualization_init(void *), IVolume_init(void *); extern void I3DGrouping_deinit(void *), IAndroidEffect_deinit(void *), IAndroidEffectCapabilities_deinit(void *), IBassBoost_deinit(void *), IBufferQueue_deinit(void *), IEngine_deinit(void *), IEnvironmentalReverb_deinit(void *), IEqualizer_deinit(void *), IObject_deinit(void *), IPresetReverb_deinit(void *), IThreadSync_deinit(void *), IVirtualizer_deinit(void *); extern bool IAndroidEffectCapabilities_Expose(void *), IBassBoost_Expose(void *), IEnvironmentalReverb_Expose(void *), IEqualizer_Expose(void *), IPresetReverb_Expose(void *), IVirtualizer_Expose(void *); #if !(USE_PROFILES & USE_PROFILES_MUSIC) #define IDynamicSource_init NULL #define IMetadataExtraction_init NULL #define IMetadataTraversal_init NULL #define IVisualization_init NULL #endif #if !(USE_PROFILES & USE_PROFILES_GAME) #define I3DCommit_init NULL #define I3DDoppler_init NULL #define I3DGrouping_init NULL #define I3DLocation_init NULL #define I3DMacroscopic_init NULL #define I3DSource_init NULL #define IMIDIMessage_init NULL #define IMIDIMuteSolo_init NULL #define IMIDITempo_init NULL #define IMIDITime_init NULL #define IPitch_init NULL #define IRatePitch_init NULL #define I3DGrouping_deinit NULL #endif #if !(USE_PROFILES & USE_PROFILES_BASE) #define IAudioDecoderCapabilities_init NULL #define IAudioEncoderCapabilities_init NULL #define IAudioEncoder_init NULL #define IAudioIODeviceCapabilities_init NULL #define IDeviceVolume_init NULL #define IEngineCapabilities_init NULL #define IThreadSync_init NULL #define IThreadSync_deinit NULL #endif #if !(USE_PROFILES & USE_PROFILES_OPTIONAL) #define ILEDArray_init NULL #define IVibra_init NULL #endif #ifndef ANDROID #define IAndroidConfiguration_init NULL #define IAndroidEffect_init NULL #define IAndroidEffectCapabilities_init NULL #define IAndroidEffectSend_init NULL #define IAndroidEffect_deinit NULL #define IAndroidEffectCapabilities_deinit NULL #define IAndroidEffectCapabilities_Expose NULL #endif #ifndef USE_OUTPUTMIXEXT #define IOutputMixExt_init NULL #endif /*static*/ const struct MPH_init MPH_init_table[MPH_MAX] = { { /* MPH_3DCOMMIT, */ I3DCommit_init, NULL, NULL, NULL, NULL }, { /* MPH_3DDOPPLER, */ I3DDoppler_init, NULL, NULL, NULL, NULL }, { /* MPH_3DGROUPING, */ I3DGrouping_init, NULL, I3DGrouping_deinit, NULL, NULL }, { /* MPH_3DLOCATION, */ I3DLocation_init, NULL, NULL, NULL, NULL }, { /* MPH_3DMACROSCOPIC, */ I3DMacroscopic_init, NULL, NULL, NULL, NULL }, { /* MPH_3DSOURCE, */ I3DSource_init, NULL, NULL, NULL, NULL }, { /* MPH_AUDIODECODERCAPABILITIES, */ IAudioDecoderCapabilities_init, NULL, NULL, NULL, NULL }, { /* MPH_AUDIOENCODER, */ IAudioEncoder_init, NULL, NULL, NULL, NULL }, { /* MPH_AUDIOENCODERCAPABILITIES, */ IAudioEncoderCapabilities_init, NULL, NULL, NULL, NULL }, { /* MPH_AUDIOIODEVICECAPABILITIES, */ IAudioIODeviceCapabilities_init, NULL, NULL, NULL, NULL }, { /* MPH_BASSBOOST, */ IBassBoost_init, NULL, IBassBoost_deinit, IBassBoost_Expose, NULL }, { /* MPH_BUFFERQUEUE, */ IBufferQueue_init, NULL, IBufferQueue_deinit, NULL, NULL }, { /* MPH_DEVICEVOLUME, */ IDeviceVolume_init, NULL, NULL, NULL, NULL }, { /* MPH_DYNAMICINTERFACEMANAGEMENT, */ IDynamicInterfaceManagement_init, NULL, NULL, NULL, NULL }, { /* MPH_DYNAMICSOURCE, */ IDynamicSource_init, NULL, NULL, NULL, NULL }, { /* MPH_EFFECTSEND, */ IEffectSend_init, NULL, NULL, NULL, NULL }, { /* MPH_ENGINE, */ IEngine_init, NULL, IEngine_deinit, NULL, NULL }, { /* MPH_ENGINECAPABILITIES, */ IEngineCapabilities_init, NULL, NULL, NULL, NULL }, { /* MPH_ENVIRONMENTALREVERB, */ IEnvironmentalReverb_init, NULL, IEnvironmentalReverb_deinit, IEnvironmentalReverb_Expose, NULL }, { /* MPH_EQUALIZER, */ IEqualizer_init, NULL, IEqualizer_deinit, IEqualizer_Expose, NULL }, { /* MPH_LED, */ ILEDArray_init, NULL, NULL, NULL, NULL }, { /* MPH_METADATAEXTRACTION, */ IMetadataExtraction_init, NULL, NULL, NULL, NULL }, { /* MPH_METADATATRAVERSAL, */ IMetadataTraversal_init, NULL, NULL, NULL, NULL }, { /* MPH_MIDIMESSAGE, */ IMIDIMessage_init, NULL, NULL, NULL, NULL }, { /* MPH_MIDITIME, */ IMIDITime_init, NULL, NULL, NULL, NULL }, { /* MPH_MIDITEMPO, */ IMIDITempo_init, NULL, NULL, NULL, NULL }, { /* MPH_MIDIMUTESOLO, */ IMIDIMuteSolo_init, NULL, NULL, NULL, NULL }, { /* MPH_MUTESOLO, */ IMuteSolo_init, NULL, NULL, NULL, NULL }, { /* MPH_NULL, */ NULL, NULL, NULL, NULL, NULL }, { /* MPH_OBJECT, */ IObject_init, NULL, IObject_deinit, NULL, NULL }, { /* MPH_OUTPUTMIX, */ IOutputMix_init, NULL, NULL, NULL, NULL }, { /* MPH_PITCH, */ IPitch_init, NULL, NULL, NULL, NULL }, { /* MPH_PLAY, */ IPlay_init, NULL, NULL, NULL, NULL }, { /* MPH_PLAYBACKRATE, */ IPlaybackRate_init, NULL, NULL, NULL, NULL }, { /* MPH_PREFETCHSTATUS, */ IPrefetchStatus_init, NULL, NULL, NULL, NULL }, { /* MPH_PRESETREVERB, */ IPresetReverb_init, NULL, IPresetReverb_deinit, IPresetReverb_Expose, NULL }, { /* MPH_RATEPITCH, */ IRatePitch_init, NULL, NULL, NULL, NULL }, { /* MPH_RECORD, */ IRecord_init, NULL, NULL, NULL, NULL }, { /* MPH_SEEK, */ ISeek_init, NULL, NULL, NULL, NULL }, { /* MPH_THREADSYNC, */ IThreadSync_init, NULL, IThreadSync_deinit, NULL, NULL }, { /* MPH_VIBRA, */ IVibra_init, NULL, NULL, NULL, NULL }, { /* MPH_VIRTUALIZER, */ IVirtualizer_init, NULL, IVirtualizer_deinit, IVirtualizer_Expose, NULL }, { /* MPH_VISUALIZATION, */ IVisualization_init, NULL, NULL, NULL, NULL }, { /* MPH_VOLUME, */ IVolume_init, NULL, NULL, NULL, NULL }, { /* MPH_OUTPUTMIXEXT, */ IOutputMixExt_init, NULL, NULL, NULL, NULL }, { /* MPH_ANDROIDEFFECT */ IAndroidEffect_init, NULL, IAndroidEffect_deinit, NULL, NULL }, { /* MPH_ANDROIDEFFECTCAPABILITIES */ IAndroidEffectCapabilities_init, NULL, IAndroidEffectCapabilities_deinit, IAndroidEffectCapabilities_Expose, NULL }, { /* MPH_ANDROIDEFFECTSEND */ IAndroidEffectSend_init, NULL, NULL, NULL, NULL }, { /* MPH_ANDROIDCONFIGURATION */ IAndroidConfiguration_init, NULL, NULL, NULL, NULL }, { /* MPH_ANDROIDSIMPLEBUFFERQUEUE, */ IBufferQueue_init /* alias */, NULL, NULL, NULL, NULL } }; /** \brief Construct a new instance of the specified class, exposing selected interfaces */ IObject *construct(const ClassTable *class__, unsigned exposedMask, SLEngineItf engine) { IObject *this; // Do not change this to malloc; we depend on the object being memset to zero this = (IObject *) calloc(1, class__->mSize); if (NULL != this) { SL_LOGV("construct %s at %p", class__->mName, this); unsigned lossOfControlMask = 0; // a NULL engine means we are constructing the engine IEngine *thisEngine = (IEngine *) engine; if (NULL == thisEngine) { thisEngine = &((CEngine *) this)->mEngine; } else { interface_lock_exclusive(thisEngine); if (MAX_INSTANCE <= thisEngine->mInstanceCount) { SL_LOGE("Too many objects"); interface_unlock_exclusive(thisEngine); free(this); return NULL; } // pre-allocate a pending slot, but don't assign bit from mInstanceMask yet ++thisEngine->mInstanceCount; assert(((unsigned) ~0) != thisEngine->mInstanceMask); interface_unlock_exclusive(thisEngine); // const, no lock needed if (thisEngine->mLossOfControlGlobal) { lossOfControlMask = ~0; } } this->mLossOfControlMask = lossOfControlMask; this->mClass = class__; this->mEngine = thisEngine; const struct iid_vtable *x = class__->mInterfaces; SLuint8 *interfaceStateP = this->mInterfaceStates; SLuint32 index; for (index = 0; index < class__->mInterfaceCount; ++index, ++x, exposedMask >>= 1) { SLuint8 state; // initialize all interfaces with init hooks, even if not exposed const struct MPH_init *mi = &MPH_init_table[x->mMPH]; VoidHook init = mi->mInit; if (NULL != init) { void *self = (char *) this + x->mOffset; // IObject does not have an mThis, so [1] is not always defined if (index) { ((IObject **) self)[1] = this; } // call the initialization hook (*init)(self); // IObject does not require a call to GetInterface if (index) { // This trickery invalidates the v-table until GetInterface ((size_t *) self)[0] ^= ~0; } // if interface is exposed, also call the optional expose hook BoolHook expose; state = (exposedMask & 1) && ((NULL == (expose = mi->mExpose)) || (*expose)(self)) ? INTERFACE_EXPOSED : INTERFACE_INITIALIZED; // FIXME log or report to application if an expose hook on a // required explicit interface fails at creation time } else { state = INTERFACE_UNINITIALIZED; } *interfaceStateP++ = state; } // note that the new object is not yet published; creator must call IObject_Publish } return this; } /* This implementation supports at most one engine */ static CEngine *theOneTrueEngine = NULL; static pthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER; /** \brief Called by dlopen when .so is loaded */ __attribute__((constructor)) static void onDlOpen(void) { } /** \brief Called by dlclose when .so is unloaded */ __attribute__((destructor)) static void onDlClose(void) { if (NULL != theOneTrueEngine) { SL_LOGE("Object::Destroy omitted for engine %p", theOneTrueEngine); } } /** \brief Called by IObject::Destroy after engine is destroyed. The parameter refers to the * previous engine, which is now undefined memory. */ void CEngine_Destroyed(CEngine *self) { int ok; ok = pthread_mutex_lock(&theOneTrueMutex); assert(0 == ok); assert(self == theOneTrueEngine); theOneTrueEngine = NULL; ok = pthread_mutex_unlock(&theOneTrueMutex); assert(0 == ok); } /* Initial global entry points */ /** \brief slCreateEngine Function */ SLresult SLAPIENTRY slCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, const SLEngineOption *pEngineOptions, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired) { SL_ENTER_GLOBAL int ok; ok = pthread_mutex_lock(&theOneTrueMutex); assert(0 == ok); do { #ifdef ANDROID android::ProcessState::self()->startThreadPool(); #ifndef USE_BACKPORT android::DataSource::RegisterDefaultSniffers(); #endif #endif if (NULL == pEngine) { result = SL_RESULT_PARAMETER_INVALID; break; } *pEngine = NULL; if (NULL != theOneTrueEngine) { SL_LOGE("slCreateEngine while another engine %p is active", theOneTrueEngine); result = SL_RESULT_RESOURCE_ERROR; break; } if ((0 < numOptions) && (NULL == pEngineOptions)) { SL_LOGE("numOptions=%lu and pEngineOptions=NULL", numOptions); result = SL_RESULT_PARAMETER_INVALID; break; } // default values SLboolean threadSafe = SL_BOOLEAN_TRUE; SLboolean lossOfControlGlobal = SL_BOOLEAN_FALSE; // process engine options SLuint32 i; const SLEngineOption *option = pEngineOptions; result = SL_RESULT_SUCCESS; for (i = 0; i < numOptions; ++i, ++option) { switch (option->feature) { case SL_ENGINEOPTION_THREADSAFE: threadSafe = SL_BOOLEAN_FALSE != (SLboolean) option->data; // normalize break; case SL_ENGINEOPTION_LOSSOFCONTROL: lossOfControlGlobal = SL_BOOLEAN_FALSE != (SLboolean) option->data; // normalize break; default: SL_LOGE("unknown engine option: feature=%lu data=%lu", option->feature, option->data); result = SL_RESULT_PARAMETER_INVALID; break; } } if (SL_RESULT_SUCCESS != result) { break; } unsigned exposedMask; const ClassTable *pCEngine_class = objectIDtoClass(SL_OBJECTID_ENGINE); assert(NULL != pCEngine_class); result = checkInterfaces(pCEngine_class, numInterfaces, pInterfaceIds, pInterfaceRequired, &exposedMask); if (SL_RESULT_SUCCESS != result) { break; } CEngine *this = (CEngine *) construct(pCEngine_class, exposedMask, NULL); if (NULL == this) { result = SL_RESULT_MEMORY_FAILURE; break; } // initialize fields not associated with an interface memset(&this->mSyncThread, 0, sizeof(pthread_t)); // initialize fields related to an interface this->mObject.mLossOfControlMask = lossOfControlGlobal ? ~0 : 0; this->mEngine.mLossOfControlGlobal = lossOfControlGlobal; this->mEngineCapabilities.mThreadSafe = threadSafe; IObject_Publish(&this->mObject); theOneTrueEngine = this; // return the new engine object *pEngine = &this->mObject.mItf; } while(0); ok = pthread_mutex_unlock(&theOneTrueMutex); assert(0 == ok); SL_LEAVE_GLOBAL } /** \brief slQueryNumSupportedEngineInterfaces Function */ SLresult SLAPIENTRY slQueryNumSupportedEngineInterfaces(SLuint32 *pNumSupportedInterfaces) { SL_ENTER_GLOBAL if (NULL == pNumSupportedInterfaces) { result = SL_RESULT_PARAMETER_INVALID; } else { const ClassTable *class__ = objectIDtoClass(SL_OBJECTID_ENGINE); assert(NULL != class__); SLuint32 count = 0; SLuint32 i; for (i = 0; i < class__->mInterfaceCount; ++i) { switch (class__->mInterfaces[i].mInterface) { case INTERFACE_IMPLICIT: case INTERFACE_IMPLICIT_PREREALIZE: case INTERFACE_EXPLICIT: case INTERFACE_EXPLICIT_PREREALIZE: case INTERFACE_DYNAMIC: ++count; break; case INTERFACE_UNAVAILABLE: break; default: assert(false); break; } } *pNumSupportedInterfaces = count; result = SL_RESULT_SUCCESS; } SL_LEAVE_GLOBAL } /** \brief slQuerySupportedEngineInterfaces Function */ SLresult SLAPIENTRY slQuerySupportedEngineInterfaces(SLuint32 index, SLInterfaceID *pInterfaceId) { SL_ENTER_GLOBAL if (NULL == pInterfaceId) { result = SL_RESULT_PARAMETER_INVALID; } else { *pInterfaceId = NULL; const ClassTable *class__ = objectIDtoClass(SL_OBJECTID_ENGINE); assert(NULL != class__); result = SL_RESULT_PARAMETER_INVALID; // will be reset later SLuint32 i; for (i = 0; i < class__->mInterfaceCount; ++i) { switch (class__->mInterfaces[i].mInterface) { case INTERFACE_IMPLICIT: case INTERFACE_IMPLICIT_PREREALIZE: case INTERFACE_EXPLICIT: case INTERFACE_EXPLICIT_PREREALIZE: case INTERFACE_DYNAMIC: break; case INTERFACE_UNAVAILABLE: continue; default: assert(false); break; } if (index == 0) { // The engine has no aliases, but if it did, this would return only the primary *pInterfaceId = &SL_IID_array[class__->mInterfaces[i].mMPH]; result = SL_RESULT_SUCCESS; break; } --index; } } SL_LEAVE_GLOBAL }