diff --git a/channels/rdpsnd/client/opensles/opensl_io.c b/channels/rdpsnd/client/opensles/opensl_io.c index d93aaae85..c18326b01 100644 --- a/channels/rdpsnd/client/opensles/opensl_io.c +++ b/channels/rdpsnd/client/opensles/opensl_io.c @@ -34,12 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CONV16BIT 32768 #define CONVMYFLT (1./32768.) -static void* createThreadLock(void); -static int waitThreadLock(void *lock); -static void notifyThreadLock(void *lock); -static void destroyThreadLock(void *lock); static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context); -static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context); // creates the OpenSL ES audio engine static SLresult openSLCreateEngine(OPENSL_STREAM *p) @@ -196,128 +191,6 @@ static SLresult openSLPlayOpen(OPENSL_STREAM *p) return SL_RESULT_SUCCESS; } -// Open the OpenSL ES device for input -static SLresult openSLRecOpen(OPENSL_STREAM *p){ - - SLresult result; - SLuint32 sr = p->sr; - SLuint32 channels = p->inchannels; - - if(channels){ - - switch(sr){ - - case 8000: - sr = SL_SAMPLINGRATE_8; - break; - case 11025: - sr = SL_SAMPLINGRATE_11_025; - break; - case 16000: - sr = SL_SAMPLINGRATE_16; - break; - case 22050: - sr = SL_SAMPLINGRATE_22_05; - break; - case 24000: - sr = SL_SAMPLINGRATE_24; - break; - case 32000: - sr = SL_SAMPLINGRATE_32; - break; - case 44100: - sr = SL_SAMPLINGRATE_44_1; - break; - case 48000: - sr = SL_SAMPLINGRATE_48; - break; - case 64000: - sr = SL_SAMPLINGRATE_64; - break; - case 88200: - sr = SL_SAMPLINGRATE_88_2; - break; - case 96000: - sr = SL_SAMPLINGRATE_96; - break; - case 192000: - sr = SL_SAMPLINGRATE_192; - break; - default: - return -1; - } - - // configure audio source - SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, - SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; - SLDataSource audioSrc = {&loc_dev, NULL}; - - // configure audio sink - int speakers; - if(channels > 1) - speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - else speakers = SL_SPEAKER_FRONT_CENTER; - SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; - SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, sr, - SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, - speakers, SL_BYTEORDER_LITTLEENDIAN}; - SLDataSink audioSnk = {&loc_bq, &format_pcm}; - - // create audio recorder - // (requires the RECORD_AUDIO permission) - const SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME}; - const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine, - &(p->recorderObject), &audioSrc, &audioSnk, 2, id, req); - DEBUG_SND("p->recorderObject=%p", p->recorderObject); - assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; - - // realize the audio recorder - result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE); - DEBUG_SND("Realize=%d", result); - assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; - - // get the record interface - result = (*p->recorderObject)->GetInterface(p->recorderObject, - SL_IID_RECORD, &(p->recorderRecord)); - DEBUG_SND("p->recorderRecord=%p", p->recorderRecord); - assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; - - // get the buffer queue interface - result = (*p->recorderObject)->GetInterface(p->recorderObject, - SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &(p->recorderBufferQueue)); - DEBUG_SND("p->recorderBufferQueue=%p", p->recorderBufferQueue); - assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; - - // get the record volume - result = (*p->recorderObject)->GetInterface(p->recorderObject, - SL_IID_VOLUME, &(p->recorderVolume)); - DEBUG_SND("p->recorderVolume=%p", p->recorderVolume); - assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; - - // register callback on the buffer queue - result = (*p->recorderBufferQueue)->RegisterCallback(p->recorderBufferQueue, - bqRecorderCallback, p); - DEBUG_SND("p->recorderBufferQueue=%p", p->recorderBufferQueue); - assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; - result = (*p->recorderRecord)->SetRecordState(p->recorderRecord, - SL_RECORDSTATE_RECORDING); - - end_recopen: - return result; - } - else return SL_RESULT_SUCCESS; - - -} - // close the OpenSL IO and destroy the audio engine static void openSLDestroyEngine(OPENSL_STREAM *p){ @@ -331,15 +204,6 @@ static void openSLDestroyEngine(OPENSL_STREAM *p){ p->bqPlayerEffectSend = NULL; } - // destroy audio recorder object, and invalidate all associated interfaces - if (p->recorderObject != NULL) { - (*p->recorderObject)->Destroy(p->recorderObject); - p->recorderObject = NULL; - p->recorderRecord = NULL; - p->recorderVolume = NULL; - p->recorderBufferQueue = NULL; - } - // destroy output mix object, and invalidate all associated interfaces if (p->outputMixObject != NULL) { (*p->outputMixObject)->Destroy(p->outputMixObject); @@ -356,59 +220,30 @@ static void openSLDestroyEngine(OPENSL_STREAM *p){ } -// open the android audio device for input and/or output -OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels, int bufferframes){ +// open the android audio device for and/or output +OPENSL_STREAM *android_OpenAudioDevice(int sr, int outchannels, int bufferframes){ OPENSL_STREAM *p; p = (OPENSL_STREAM *) calloc(sizeof(OPENSL_STREAM),1); + memset(p, 0, sizeof(OPENSL_STREAM)); - p->inchannels = inchannels; p->outchannels = outchannels; p->sr = sr; - p->inlock = createThreadLock(); - p->outlock = createThreadLock(); - if((p->outBufSamples = bufferframes*outchannels) != 0) { - if((p->outputBuffer[0] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL || - (p->outputBuffer[1] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL) { - android_CloseAudioDevice(p); - return NULL; - } - } - - if((p->inBufSamples = bufferframes*inchannels) != 0){ - if((p->inputBuffer[0] = (short *) calloc(p->inBufSamples, sizeof(short))) == NULL || - (p->inputBuffer[1] = (short *) calloc(p->inBufSamples, sizeof(short))) == NULL){ - android_CloseAudioDevice(p); - return NULL; - } - } - - p->currentInputIndex = 0; - p->currentOutputBuffer = 0; - p->currentInputIndex = p->inBufSamples; - p->currentInputBuffer = 0; - if(openSLCreateEngine(p) != SL_RESULT_SUCCESS) { android_CloseAudioDevice(p); return NULL; } - if(openSLRecOpen(p) != SL_RESULT_SUCCESS) { - android_CloseAudioDevice(p); - return NULL; - } - if(openSLPlayOpen(p) != SL_RESULT_SUCCESS) { android_CloseAudioDevice(p); return NULL; } - notifyThreadLock(p->outlock); - notifyThreadLock(p->inlock); - p->time = 0.; - return p; + p->next = CreateEvent(NULL, TRUE, FALSE, NULL); + + return p; } // close the android audio device @@ -418,38 +253,7 @@ void android_CloseAudioDevice(OPENSL_STREAM *p){ return; openSLDestroyEngine(p); - - if (p->inlock != NULL) { - notifyThreadLock(p->inlock); - destroyThreadLock(p->inlock); - p->inlock = NULL; - } - - if (p->outlock != NULL) { - notifyThreadLock(p->outlock); - destroyThreadLock(p->outlock); - p->inlock = NULL; - } - - if (p->outputBuffer[0] != NULL) { - free(p->outputBuffer[0]); - p->outputBuffer[0] = NULL; - } - - if (p->outputBuffer[1] != NULL) { - free(p->outputBuffer[1]); - p->outputBuffer[1] = NULL; - } - - if (p->inputBuffer[0] != NULL) { - free(p->inputBuffer[0]); - p->inputBuffer[0] = NULL; - } - - if (p->inputBuffer[1] != NULL) { - free(p->inputBuffer[1]); - p->inputBuffer[1] = NULL; - } + CloseHandle(p->next); free(p); } @@ -459,88 +263,50 @@ double android_GetTimestamp(OPENSL_STREAM *p){ return p->time; } - -// this callback handler is called every time a buffer finishes recording -void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) -{ - OPENSL_STREAM *p = (OPENSL_STREAM *) context; - notifyThreadLock(p->inlock); -} - -// gets a buffer of size samples from the device -int android_AudioIn(OPENSL_STREAM *p,float *buffer,int size){ - short *inBuffer; - int i, bufsamps = p->inBufSamples, index = p->currentInputIndex; - if(p == NULL || bufsamps == 0) return 0; - - inBuffer = p->inputBuffer[p->currentInputBuffer]; - for(i=0; i < size; i++){ - if (index >= bufsamps) { - waitThreadLock(p->inlock); - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - inBuffer,bufsamps*sizeof(short)); - p->currentInputBuffer = (p->currentInputBuffer ? 0 : 1); - index = 0; - inBuffer = p->inputBuffer[p->currentInputBuffer]; - } - buffer[i] = (float) inBuffer[index++]*CONVMYFLT; - } - p->currentInputIndex = index; - if(p->outchannels == 0) p->time += (double) size/(p->sr*p->inchannels); - return i; -} - // this callback handler is called every time a buffer finishes playing void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { OPENSL_STREAM *p = (OPENSL_STREAM *) context; - notifyThreadLock(p->outlock); + + assert(p); + assert(p->next); + + SetEvent(p->next); } // puts a buffer of size samples to the device -int android_AudioOut(OPENSL_STREAM *p, short *buffer,int size){ - - short *outBuffer; - int i, bufsamps = p->outBufSamples, index = p->currentOutputIndex; - +int android_AudioOut(OPENSL_STREAM *p, const short *buffer,int size) +{ assert(p); assert(buffer); assert(size > 0); - if(p == NULL || bufsamps == 0) - return 0; - outBuffer = p->outputBuffer[p->currentOutputBuffer]; - - for(i=0; i < size; i++){ - outBuffer[index++] = buffer[i]; - if (index >= p->outBufSamples) { - waitThreadLock(p->outlock); - (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, - outBuffer,bufsamps*sizeof(short)); - p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1); - index = 0; - outBuffer = p->outputBuffer[p->currentOutputBuffer]; - } - } - p->currentOutputIndex = index; - p->time += (double) size/(p->sr*p->outchannels); - return i; + (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, + buffer, sizeof(short) * size); + WaitForSingleObject(p->next, INFINITE); + + return size; } -int android_GetInputVolume(OPENSL_STREAM *p){ - SLmillibel level; +int android_GetOutputMute(OPENSL_STREAM *p) { + SLboolean mute; assert(p); - assert(p->recorderVolume); + assert(p->bqPlayerVolume); - SLresult rc = (*p->recorderVolume)->GetVolumeLevel(p->recorderVolume, &level); + SLresult rc = (*p->bqPlayerVolume)->GetMute(p->bqPlayerVolume, &mute); assert(SL_RESULT_SUCCESS == rc); - return level; + return mute; } -void android_SetInputVolume(OPENSL_STREAM *p, int level){ - SLresult rc = (*p->recorderVolume)->SetVolumeLevel(p->recorderVolume, level); +void android_SetOutputMute(OPENSL_STREAM *p, BOOL _mute) { + SLboolean mute = _mute; + + assert(p); + assert(p->bqPlayerVolume); + + SLresult rc = (*p->bqPlayerVolume)->SetMute(p->bqPlayerVolume, mute); assert(SL_RESULT_SUCCESS == rc); } @@ -556,68 +322,21 @@ int android_GetOutputVolume(OPENSL_STREAM *p){ return level; } +int android_GetOutputVolumeMax(OPENSL_STREAM *p){ + SLmillibel level; + + assert(p); + assert(p->bqPlayerVolume); + + SLresult rc = (*p->bqPlayerVolume)->GetMaxVolumeLevel(p->bqPlayerVolume, &level); + assert(SL_RESULT_SUCCESS == rc); + + return level; +} + + void android_SetOutputVolume(OPENSL_STREAM *p, int level){ SLresult rc = (*p->bqPlayerVolume)->SetVolumeLevel(p->bqPlayerVolume, level); assert(SL_RESULT_SUCCESS == rc); } -//---------------------------------------------------------------------- -// thread Locks -// to ensure synchronisation between callbacks and processing code -void* createThreadLock(void) -{ - threadLock *p; - p = (threadLock*) malloc(sizeof(threadLock)); - if (p == NULL) - return NULL; - memset(p, 0, sizeof(threadLock)); - if (pthread_mutex_init(&(p->m), (pthread_mutexattr_t*) NULL) != 0) { - free((void*) p); - return NULL; - } - if (pthread_cond_init(&(p->c), (pthread_condattr_t*) NULL) != 0) { - pthread_mutex_destroy(&(p->m)); - free((void*) p); - return NULL; - } - p->s = (unsigned char) 1; - - return p; -} - -int waitThreadLock(void *lock) -{ - threadLock *p; - int retval = 0; - p = (threadLock*) lock; - pthread_mutex_lock(&(p->m)); - while (!p->s) { - pthread_cond_wait(&(p->c), &(p->m)); - } - p->s = (unsigned char) 0; - pthread_mutex_unlock(&(p->m)); - - return retval; -} - -void notifyThreadLock(void *lock) -{ - threadLock *p; - p = (threadLock*) lock; - pthread_mutex_lock(&(p->m)); - p->s = (unsigned char) 1; - pthread_cond_signal(&(p->c)); - pthread_mutex_unlock(&(p->m)); -} - -void destroyThreadLock(void *lock) -{ - threadLock *p; - p = (threadLock*) lock; - if (p == NULL) - return; - notifyThreadLock(p); - pthread_cond_destroy(&(p->c)); - pthread_mutex_destroy(&(p->m)); - free(p); -} diff --git a/channels/rdpsnd/client/opensles/opensl_io.h b/channels/rdpsnd/client/opensles/opensl_io.h index 42c1d9d48..93dd2b53d 100644 --- a/channels/rdpsnd/client/opensles/opensl_io.h +++ b/channels/rdpsnd/client/opensles/opensl_io.h @@ -32,21 +32,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include - -typedef struct threadLock_{ - pthread_mutex_t m; - pthread_cond_t c; - unsigned char s; -} threadLock; +#include #ifdef __cplusplus extern "C" { #endif typedef struct opensl_stream { - // engine interfaces SLObjectItf engineObject; SLEngineItf engineEngine; @@ -61,72 +54,52 @@ typedef struct opensl_stream { SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; SLEffectSendItf bqPlayerEffectSend; - // recorder interfaces - SLObjectItf recorderObject; - SLRecordItf recorderRecord; - SLVolumeItf recorderVolume; - SLAndroidSimpleBufferQueueItf recorderBufferQueue; - - // buffer indexes - int currentInputIndex; - int currentOutputIndex; - - // current buffer half (0, 1) - int currentOutputBuffer; - int currentInputBuffer; - - // buffers - short *outputBuffer[2]; - short *inputBuffer[2]; - - // size of buffers - int outBufSamples; - int inBufSamples; - - // locks - void* inlock; - void* outlock; - double time; - int inchannels; - int outchannels; - int sr; + unsigned int outchannels; + unsigned int sr; + HANDLE next; } OPENSL_STREAM; /* - Open the audio device with a given sampling rate (sr), input and output channels and IO buffer size + Open the audio device with a given sampling rate (sr), output channels and IO buffer size in frames. Returns a handle to the OpenSL stream */ - OPENSL_STREAM* android_OpenAudioDevice(int sr, int inchannels, int outchannels, int bufferframes); + OPENSL_STREAM* android_OpenAudioDevice(int sr, int outchannels, int bufferframes); /* Close the audio device */ void android_CloseAudioDevice(OPENSL_STREAM *p); - /* - Read a buffer from the OpenSL stream *p, of size samples. Returns the number of samples read. - */ - int android_AudioIn(OPENSL_STREAM *p, float *buffer,int size); /* Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written. */ - int android_AudioOut(OPENSL_STREAM *p, short *buffer,int size); + int android_AudioOut(OPENSL_STREAM *p, const short *buffer, int size); /* Get the current IO block time in seconds */ double android_GetTimestamp(OPENSL_STREAM *p); - /* - * Get the current input volume level. - */ - int android_GetInputVolume(OPENSL_STREAM *p); + /* * Set the volume input level. */ - void android_SetInputVolume(OPENSL_STREAM *p, int level); + void android_SetOutputVolume(OPENSL_STREAM *p, int level); + /* + * Get the current output mute setting. + */ + int android_GetOutputMute(OPENSL_STREAM *p); + /* + * Change the current output mute setting. + */ + void android_SetOutputMute(OPENSL_STREAM *p, BOOL mute); /* * Get the current output volume level. */ int android_GetOutputVolume(OPENSL_STREAM *p); + /* + * Get the maximum output volume level. + */ + int android_GetOutputVolumeMax(OPENSL_STREAM *p); + /* * Set the volume output level. */ diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensl_es.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c similarity index 68% rename from channels/rdpsnd/client/opensles/rdpsnd_opensl_es.c rename to channels/rdpsnd/client/opensles/rdpsnd_opensles.c index 5d1789d34..acd00ffef 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensl_es.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -60,12 +61,63 @@ struct rdpsnd_opensles_plugin FREERDP_DSP_CONTEXT* dsp_context; }; +static int rdpsnd_opensles_volume_to_millibel(unsigned short level, int max) +{ + const int min = SL_MILLIBEL_MIN; + const int step = max - min; + const int rc = (level * step / 0xFFFF) + min; + + DEBUG_SND("level=%d, min=%d, max=%d, step=%d, result=%d", + level, min, max, step, rc); + + return rc; +} + +static unsigned short rdpsnd_opensles_millibel_to_volume(int millibel, int max) +{ + const int min = SL_MILLIBEL_MIN; + const int range = max - min; + const int rc = ((millibel - min) * 0xFFFF + range / 2 + 1) / range; + + DEBUG_SND("millibel=%d, min=%d, max=%d, range=%d, result=%d", + millibel, min, max, range, rc); + + return rc; +} + +static bool rdpsnd_opensles_check_handle(const rdpsndopenslesPlugin *hdl) +{ + bool rc = true; + + assert(hdl); + if (!hdl) + rc = false; + else + { + assert(hdl->dsp_context); + if (!hdl->dsp_context) + rc = false; + assert(hdl->stream); + if (!hdl->stream) + rc = false; + } + + return rc; +} + static void rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, UINT32 volume); static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles) { DEBUG_SND("opensles=%p", opensles); + rdpsnd_opensles_check_handle(opensles); + + if (opensles->stream) + android_CloseAudioDevice(opensles->stream); + + opensles->stream = android_OpenAudioDevice( + opensles->rate, opensles->channels, opensles->rate); return 0; } @@ -74,11 +126,16 @@ static void rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + rdpsnd_opensles_check_handle(opensles); DEBUG_SND("opensles=%p format=%p, latency=%d", opensles, format, latency); if (format) { + DEBUG_SND("format=%d, cbsize=%d, samples=%d, bits=%d, channels=%d, align=%d", + format->wFormatTag, format->cbSize, format->nSamplesPerSec, + format->wBitsPerSample, format->nChannels, format->nBlockAlign); + opensles->rate = format->nSamplesPerSec; opensles->channels = format->nChannels; @@ -103,10 +160,10 @@ static void rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, case WAVE_FORMAT_ADPCM: case WAVE_FORMAT_DVI_ADPCM: - opensles->format = WAVE_FORMAT_ADPCM; + opensles->format = format->wFormatTag; break; } - + opensles->wformat = format->wFormatTag; opensles->block_size = format->nBlockAlign; } @@ -121,27 +178,34 @@ static void rdpsnd_opensles_open(rdpsndDevicePlugin* device, { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p format=%p, latency=%d", opensles, format, latency); + DEBUG_SND("opensles=%p format=%p, latency=%d, rate=%d", + opensles, format, latency, opensles->rate); if (opensles->stream) return; opensles->stream = android_OpenAudioDevice( - opensles->rate, 0, opensles->channels, opensles->rate * 100); + opensles->rate, opensles->channels, opensles->rate); + assert(opensles->stream); + if (!opensles->stream) DEBUG_WARN("android_OpenAudioDevice failed"); else rdpsnd_opensles_set_volume(device, opensles->volume); + + rdpsnd_opensles_set_format(device, format, latency); } static void rdpsnd_opensles_close(rdpsndDevicePlugin* device) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + rdpsnd_opensles_check_handle(opensles); DEBUG_SND("opensles=%p", opensles); if (!opensles->stream) return; android_CloseAudioDevice(opensles->stream); + opensles->stream = NULL; } static void rdpsnd_opensles_free(rdpsndDevicePlugin* device) @@ -149,9 +213,12 @@ static void rdpsnd_opensles_free(rdpsndDevicePlugin* device) rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; DEBUG_SND("opensles=%p", opensles); + assert(opensles); + assert(opensles->device_name); free(opensles->device_name); + assert(opensles->dsp_context); freerdp_dsp_context_free(opensles->dsp_context); free(opensles); @@ -162,8 +229,13 @@ static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p, format=%p", opensles, format); - + DEBUG_SND("format=%d, cbsize=%d, samples=%d, bits=%d, channels=%d, align=%d", + format->wFormatTag, format->cbSize, format->nSamplesPerSec, + format->wBitsPerSample, format->nChannels, format->nBlockAlign); + + assert(opensles); + assert(format); + switch (format->wFormatTag) { case WAVE_FORMAT_PCM: @@ -178,23 +250,18 @@ static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, case WAVE_FORMAT_ADPCM: case WAVE_FORMAT_DVI_ADPCM: - /* if (format->nSamplesPerSec <= 48000 && format->wBitsPerSample == 4 && (format->nChannels == 1 || format->nChannels == 2)) { return TRUE; } - */ break; case WAVE_FORMAT_ALAW: - break; - case WAVE_FORMAT_MULAW: - break; - case WAVE_FORMAT_GSM610: + default: break; } @@ -206,11 +273,23 @@ static UINT32 rdpsnd_opensles_get_volume(rdpsndDevicePlugin* device) rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; DEBUG_SND("opensles=%p", opensles); + assert(opensles); if (opensles->stream) - return android_GetOutputVolume(opensles->stream); - else - return opensles->volume; + { + const int max = android_GetOutputVolumeMax(opensles->stream); + const int rc = android_GetOutputVolume(opensles->stream); + + if (android_GetOutputMute(opensles->stream)) + opensles->volume = 0; + else + { + const unsigned short vol = rdpsnd_opensles_millibel_to_volume(rc, max); + opensles->volume = (vol << 16) | (vol & 0xFFFF); + } + } + + return opensles->volume; } static void rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, @@ -219,74 +298,81 @@ static void rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; DEBUG_SND("opensles=%p, value=%d", opensles, value); + assert(opensles); opensles->volume = value; + + return; if (opensles->stream) - android_SetOutputVolume(opensles->stream, value); + { + if (0 == opensles->volume) + android_SetOutputMute(opensles->stream, true); + else + { + const int max = android_GetOutputVolumeMax(opensles->stream); + const int vol = rdpsnd_opensles_volume_to_millibel(value & 0xFFFF, max); + + android_SetOutputMute(opensles->stream, false); + android_SetOutputVolume(opensles->stream, vol); + } + } } static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, BYTE *data, int size) { - BYTE* src; - int len; + union + { + BYTE *b; + short *s; + } src; + int ret; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; DEBUG_SND("opensles=%p, data=%p, size=%d", opensles, data, size); - assert(opensles); - if (!opensles->stream) + if (!rdpsnd_opensles_check_handle(opensles)) return; if (opensles->format == WAVE_FORMAT_ADPCM) { + DEBUG_SND("dsp_context=%p, channels=%d, block_size=%d", + opensles->dsp_context, opensles->channels, opensles->block_size); + opensles->dsp_context->decode_ms_adpcm(opensles->dsp_context, data, size, opensles->channels, opensles->block_size); size = opensles->dsp_context->adpcm_size; - src = opensles->dsp_context->adpcm_buffer; + src.b = opensles->dsp_context->adpcm_buffer; } else if (opensles->format == WAVE_FORMAT_DVI_ADPCM) { + DEBUG_SND("dsp_context=%p, channels=%d, block_size=%d", + opensles->dsp_context, opensles->channels, opensles->block_size); + opensles->dsp_context->decode_ima_adpcm(opensles->dsp_context, data, size, opensles->channels, opensles->block_size); size = opensles->dsp_context->adpcm_size; - src = opensles->dsp_context->adpcm_buffer; + src.b = opensles->dsp_context->adpcm_buffer; } else { - src = data; + src.b = data; } - len = size; - while (size > 0) - { - int ret; - - if (len < 0) - break; - - if (len > size) - len = size; - - DEBUG_SND("len=%d, src=%p", len, src); - ret = android_AudioOut(opensles->stream, (short*)src, len / 2); - if (ret < 0) - { - DEBUG_WARN("android_AudioOut failed (%d)", ret); - break; - } - - DEBUG_SND("foobar XXXXXXXXXXXX opensles=%p, data=%p, size=%d", opensles, data, size); - - src += len; - size -= len; - } + DEBUG_SND("size=%d, src=%p", size, src.b); + assert(0 == size % 2); + assert(size > 0); + assert(src.b); + ret = android_AudioOut(opensles->stream, src.s, size / 2); + if (ret < 0) + DEBUG_WARN("android_AudioOut failed (%d)", ret); } static void rdpsnd_opensles_start(rdpsndDevicePlugin* device) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + rdpsnd_opensles_check_handle(opensles); DEBUG_SND("opensles=%p", opensles); } @@ -306,6 +392,9 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, COMMAND_LINE_ARGUMENT_A* arg; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + assert(opensles); + assert(args); + DEBUG_SND("opensles=%p, args=%p", opensles, args); flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; @@ -368,7 +457,7 @@ int freerdp_rdpsnd_client_subsystem_entry( if (!opensles->device_name) opensles->device_name = _strdup("default"); - opensles->rate = 22050; + opensles->rate = 44100; opensles->channels = 2; opensles->format = WAVE_FORMAT_ADPCM; diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 844521317..b17418267 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -83,7 +83,7 @@ struct rdpsnd_plugin rdpsndDevicePlugin* device; }; -void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo); +static void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo); static void* rdpsnd_schedule_thread(void* arg) { @@ -117,6 +117,7 @@ static void* rdpsnd_schedule_thread(void* arg) rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo); free(wave); + message.wParam = NULL; } return NULL; @@ -258,13 +259,14 @@ void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) UINT16 wVersion; AUDIO_FORMAT* format; UINT16 wNumberOfFormats; + UINT32 dwVolume; rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd->NumberOfServerFormats = 0; rdpsnd->ServerFormats = NULL; Stream_Seek_UINT32(s); /* dwFlags */ - Stream_Seek_UINT32(s); /* dwVolume */ + Stream_Read_UINT32(s, dwVolume); /* dwVolume */ Stream_Seek_UINT32(s); /* dwPitch */ Stream_Seek_UINT16(s); /* wDGramPort */ Stream_Read_UINT16(s, wNumberOfFormats); @@ -297,6 +299,9 @@ void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) if (wVersion >= 6) rdpsnd_send_quality_mode_pdu(rdpsnd); + + if (rdpsnd->device) + IFCALL(rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); } void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, UINT16 wPackSize) @@ -379,7 +384,7 @@ void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu); } -void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) { MessageQueue_Post(device->rdpsnd->queue, NULL, 0, (void*) wave, NULL); }