Skip to content

Commit

Permalink
Add float playback capability to OpenSL ES
Browse files Browse the repository at this point in the history
Add SLAndroidDataFormat_PCM_EX to match OpenSLES 1.1 header file,
together with related SL_ANDROID_PCM_REPRESENTATION_* constants.
Use slesTest_playbq as the test application.

Change-Id: I04bcd170f5c517051a799bacf8f52da5f1353ad6
  • Loading branch information
xt0032rus committed May 29, 2014
1 parent 1580f7a commit e57c133
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 39 deletions.
23 changes: 18 additions & 5 deletions include/SLES/OpenSLES_Android.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,24 @@ typedef sl_uint64_t SLAuint64; /* 64 bit unsigned integer */
/*---------------------------------------------------------------------------*/
/* Android PCM Data Format */
/*---------------------------------------------------------------------------*/
#define SL_ANDROID_PCMSAMPLEFORMAT ((SLuint16) 0x8000)
#define SL_ANDROID_PCMSAMPLEFORMAT_FLT ((SLuint16) 0x4000)
#define SL_ANDROID_PCMSAMPLEFORMAT_24_PACKED (SL_ANDROID_PCMSAMPLEFORMAT | ((SLuint16) 0x0018))
#define SL_ANDROID_PCMSAMPLEFORMAT_FLOAT (SL_ANDROID_PCMSAMPLEFORMAT | \
SL_ANDROID_PCMSAMPLEFORMAT_FLT | ((SLuint16) 0x0020))

/* The following pcm representations and data formats map to those in OpenSLES 1.1 */
#define SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT ((SLuint32) 0x00000001)
#define SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT ((SLuint32) 0x00000002)
#define SL_ANDROID_PCM_REPRESENTATION_FLOAT ((SLuint32) 0x00000003)

#define SL_ANDROID_DATAFORMAT_PCM_EX ((SLuint32) 0x00000004)

typedef struct SLAndroidDataFormat_PCM_EX_ {
SLuint32 formatType;
SLuint32 numChannels;
SLuint32 sampleRate;
SLuint32 bitsPerSample;
SLuint32 containerSize;
SLuint32 channelMask;
SLuint32 endianness;
SLuint32 representation;
} SLAndroidDataFormat_PCM_EX;

/*---------------------------------------------------------------------------*/
/* Android Effect interface */
Expand Down
35 changes: 34 additions & 1 deletion src/android/AudioPlayer_to_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,8 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer)
const SLuint32 sourceFormatType = *(SLuint32 *)pAudioSrc->pFormat;
const SLuint32 sinkFormatType = *(SLuint32 *)pAudioSnk->pFormat;

const SLuint32 *df_representation = NULL; // pointer to representation field, if it exists

switch (sourceLocatorType) {
//------------------
// Buffer Queues
Expand All @@ -938,6 +940,21 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer)
// Buffer format
switch (sourceFormatType) {
// currently only PCM buffer queues are supported,
case SL_ANDROID_DATAFORMAT_PCM_EX: {
SLAndroidDataFormat_PCM_EX *df_pcm =
(SLAndroidDataFormat_PCM_EX *) pAudioSrc->pFormat;
switch (df_pcm->representation) {
case SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT:
case SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT:
case SL_ANDROID_PCM_REPRESENTATION_FLOAT:
df_representation = &df_pcm->representation;
break;
default:
SL_LOGE("Cannot create audio player: unsupported representation: %d",
df_pcm->representation);
return SL_RESULT_CONTENT_UNSUPPORTED;
}
}; // SL_ANDROID_DATAFORMAT_PCM_EX - fall through to next test.
case SL_DATAFORMAT_PCM: {
SLDataFormat_PCM *df_pcm = (SLDataFormat_PCM *) pAudioSrc->pFormat;
SLresult result = android_audioPlayer_validateChannelMask(df_pcm->channelMask,
Expand Down Expand Up @@ -970,12 +987,28 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer)
}
switch (df_pcm->bitsPerSample) {
case SL_PCMSAMPLEFORMAT_FIXED_8:
if (df_representation &&
*df_representation != SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT) {
goto default_err;
}
break;
case SL_PCMSAMPLEFORMAT_FIXED_16:
case SL_PCMSAMPLEFORMAT_FIXED_24:
if (df_representation &&
*df_representation != SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT) {
goto default_err;
}
break;
case SL_PCMSAMPLEFORMAT_FIXED_32:
if (df_representation
&& *df_representation != SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
&& *df_representation != SL_ANDROID_PCM_REPRESENTATION_FLOAT) {
goto default_err;
}
break;
// others
default:
default_err:
// this should have already been rejected by checkDataFormat
SL_LOGE("Cannot create audio player: unsupported sample bit depth %u",
(SLuint32)df_pcm->bitsPerSample);
Expand Down Expand Up @@ -1491,7 +1524,7 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async
pAudioPlayer->mAudioTrack = new android::AudioTrack(
pAudioPlayer->mStreamType, // streamType
sampleRate, // sampleRate
sles_to_android_sampleFormat(df_pcm->formatType, df_pcm->containerSize), // format
sles_to_android_sampleFormat(df_pcm), // format
sles_to_android_channelMaskOut(df_pcm->numChannels, df_pcm->channelMask),
// channel mask
0, // frameCount
Expand Down
38 changes: 33 additions & 5 deletions src/android/android_sles_conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,10 @@ static inline uint32_t sles_to_android_sampleRate(SLuint32 sampleRateMilliHertz)
return (uint32_t)(sampleRateMilliHertz / 1000);
}

static inline audio_format_t sles_to_android_sampleFormat(SLuint32 formatType,
SLuint32 containerSize) {
switch (formatType) {
static inline audio_format_t sles_to_android_sampleFormat(const SLDataFormat_PCM *df_pcm) {
switch (df_pcm->formatType) {
case SL_DATAFORMAT_PCM:
switch (containerSize) {
switch (df_pcm->containerSize) {
case 8:
return AUDIO_FORMAT_PCM_8_BIT;
case 16:
Expand All @@ -60,7 +59,36 @@ static inline audio_format_t sles_to_android_sampleFormat(SLuint32 formatType,
default:
return AUDIO_FORMAT_INVALID;
}
break;
case SL_ANDROID_DATAFORMAT_PCM_EX:
switch (((SLAndroidDataFormat_PCM_EX *)df_pcm)->representation) {
case SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT:
switch (df_pcm->containerSize) {
case 8:
return AUDIO_FORMAT_PCM_8_BIT;
default:
return AUDIO_FORMAT_INVALID;
}
case SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT:
switch (df_pcm->containerSize) {
case 16:
return AUDIO_FORMAT_PCM_16_BIT;
case 24:
return AUDIO_FORMAT_PCM_24_BIT_PACKED;
case 32:
return AUDIO_FORMAT_PCM_32_BIT;
default:
return AUDIO_FORMAT_INVALID;
}
case SL_ANDROID_PCM_REPRESENTATION_FLOAT:
switch (df_pcm->containerSize) {
case 32:
return AUDIO_FORMAT_PCM_FLOAT;
default:
return AUDIO_FORMAT_INVALID;
}
default:
return AUDIO_FORMAT_INVALID;
}
default:
return AUDIO_FORMAT_INVALID;
}
Expand Down
64 changes: 45 additions & 19 deletions src/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,29 @@ static SLresult checkDataFormat(const char *name, void *pFormat, DataFormat *pDa
{
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 {
Expand Down Expand Up @@ -407,31 +422,40 @@ static SLresult checkDataFormat(const char *name, void *pFormat, DataFormat *pDa
break;
}

// check the sample bit depth
switch (pDataFormat->mPCM.bitsPerSample) {
case SL_PCMSAMPLEFORMAT_FIXED_8:
case SL_PCMSAMPLEFORMAT_FIXED_16:
case SL_PCMSAMPLEFORMAT_FIXED_24:
case SL_PCMSAMPLEFORMAT_FIXED_32:
// check the container bit depth
switch (pDataFormat->mPCM.containerSize) {
case 8:
if (df_representation &&
*df_representation != SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT) {
result = SL_RESULT_PARAMETER_INVALID;
}
break;
case SL_PCMSAMPLEFORMAT_FIXED_20:
case SL_PCMSAMPLEFORMAT_FIXED_28:
result = SL_RESULT_CONTENT_UNSUPPORTED;
case 16:
case 24:
if (df_representation &&
*df_representation != SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT) {
result = SL_RESULT_PARAMETER_INVALID;
}
break;
case 32:
if (df_representation
&& *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: bitsPerSample=%u", name, pDataFormat->mPCM.bitsPerSample);
SL_LOGE("%s: containerSize=%u", name, pDataFormat->mPCM.containerSize);
break;
}

// check the container bit depth
// container size cannot be less than sample size
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("%s: containerSize=%u, bitsPerSample=%u", name,
Expand Down Expand Up @@ -601,6 +625,7 @@ static SLresult checkDataFormat(const char *name, void *pFormat, DataFormat *pDa
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;
Expand Down Expand Up @@ -749,6 +774,7 @@ static void freeDataFormat(DataFormat *pDataFormat)
pDataFormat->mMIME.mimeType = NULL;
}
break;
case SL_ANDROID_DATAFORMAT_PCM_EX:
case SL_DATAFORMAT_PCM:
case XA_DATAFORMAT_RAWIMAGE:
case SL_DATAFORMAT_NULL:
Expand Down Expand Up @@ -795,7 +821,7 @@ SLresult checkDataSource(const char *name, const SLDataSource *pDataSrc,
break;
case SL_DATALOCATOR_ADDRESS:
case SL_DATALOCATOR_BUFFERQUEUE:
allowedDataFormatMask &= DATAFORMAT_MASK_PCM;
allowedDataFormatMask &= DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX;
break;
// Per the spec, the pFormat field is ignored in some cases
case SL_DATALOCATOR_IODEVICE:
Expand All @@ -814,7 +840,7 @@ SLresult checkDataSource(const char *name, const SLDataSource *pDataSrc,
allowedDataFormatMask &= DATAFORMAT_MASK_MIME;
break;
case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
allowedDataFormatMask &= DATAFORMAT_MASK_PCM;
allowedDataFormatMask &= DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX;
break;
case SL_DATALOCATOR_ANDROIDBUFFERQUEUE:
allowedDataFormatMask &= DATAFORMAT_MASK_MIME;;
Expand Down Expand Up @@ -872,7 +898,7 @@ SLresult checkDataSink(const char *name, const SLDataSink *pDataSink,
break;
case SL_DATALOCATOR_ADDRESS:
case SL_DATALOCATOR_BUFFERQUEUE:
allowedDataFormatMask &= DATAFORMAT_MASK_PCM;
allowedDataFormatMask &= DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX;
break;
// Per the spec, the pFormat field is ignored in some cases
case SL_DATALOCATOR_IODEVICE:
Expand All @@ -889,7 +915,7 @@ SLresult checkDataSink(const char *name, const SLDataSink *pDataSink,
allowedDataFormatMask = DATAFORMAT_MASK_NONE;
break;
case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
allowedDataFormatMask &= DATAFORMAT_MASK_PCM;
allowedDataFormatMask &= DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX;
break;
case SL_DATALOCATOR_ANDROIDBUFFERQUEUE:
allowedDataFormatMask = DATAFORMAT_MASK_NONE;
Expand Down
2 changes: 2 additions & 0 deletions src/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef union {
typedef union {
SLuint32 mFormatType;
SLDataFormat_PCM mPCM;
SLAndroidDataFormat_PCM_EX mPCMEx;
SLDataFormat_MIME mMIME;
XADataFormat_RawImage mRawImage;
} DataFormat;
Expand Down Expand Up @@ -81,6 +82,7 @@ typedef struct {
#define DATAFORMAT_MASK_NULL (1L << SL_DATAFORMAT_NULL)
#define DATAFORMAT_MASK_MIME (1L << SL_DATAFORMAT_MIME)
#define DATAFORMAT_MASK_PCM (1L << SL_DATAFORMAT_PCM)
#define DATAFORMAT_MASK_PCM_EX (1L << SL_ANDROID_DATAFORMAT_PCM_EX)
#define DATAFORMAT_MASK_RAWIMAGE (1L << XA_DATAFORMAT_RAWIMAGE)
#define DATAFORMAT_MASK_ALL 0xFL

Expand Down
14 changes: 9 additions & 5 deletions src/itf/IEngine.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
| DATALOCATOR_MASK_ANDROIDFD | DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE
| DATALOCATOR_MASK_ANDROIDBUFFERQUEUE
#endif
, DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM);
, DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX);

if (SL_RESULT_SUCCESS != result) {
break;
Expand All @@ -266,7 +266,7 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
#endif
, DATAFORMAT_MASK_NULL
#ifdef ANDROID
| DATAFORMAT_MASK_PCM // for decode to PCM
| DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX // for decode to PCM
#endif
);
if (SL_RESULT_SUCCESS != result) {
Expand Down Expand Up @@ -299,7 +299,9 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
#endif
usesSimpleBufferQueue = true;
nbBuffers = (SLuint16) thiz->mDataSource.mLocator.mBufferQueue.numBuffers;
assert(SL_DATAFORMAT_PCM == thiz->mDataSource.mFormat.mFormatType);
assert(SL_DATAFORMAT_PCM == thiz->mDataSource.mFormat.mFormatType
|| SL_ANDROID_DATAFORMAT_PCM_EX
== thiz->mDataSource.mFormat.mFormatType);
thiz->mNumChannels = thiz->mDataSource.mFormat.mPCM.numChannels;
thiz->mSampleRateMilliHz = thiz->mDataSource.mFormat.mPCM.samplesPerSec;
break;
Expand All @@ -320,7 +322,9 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
usesSimpleBufferQueue = true;
nbBuffers = thiz->mDataSink.mLocator.mBufferQueue.numBuffers;
assert(SL_DATAFORMAT_PCM == thiz->mDataSink.mFormat.mFormatType);
assert(SL_DATAFORMAT_PCM == thiz->mDataSink.mFormat.mFormatType
|| SL_ANDROID_DATAFORMAT_PCM_EX
== thiz->mDataSink.mFormat.mFormatType);
// FIXME The values specified by the app are meaningless. We get the
// real values from the decoder. But the data sink checks currently require
// that the app specify these useless values. Needs doc/fix.
Expand Down Expand Up @@ -467,7 +471,7 @@ static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pReco
#ifdef ANDROID
| DATALOCATOR_MASK_ANDROIDSIMPLEBUFFERQUEUE
#endif
, DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM
, DATAFORMAT_MASK_MIME | DATAFORMAT_MASK_PCM | DATAFORMAT_MASK_PCM_EX
);
if (SL_RESULT_SUCCESS != result) {
break;
Expand Down
Loading

0 comments on commit e57c133

Please sign in to comment.