Fixed audio recording with opensles.
This commit is contained in:
parent
2e1bf90bd9
commit
47f8804073
@ -29,8 +29,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
#include <winpr/synch.h>
|
|
||||||
#include <winpr/thread.h>
|
|
||||||
#include <winpr/cmdline.h>
|
#include <winpr/cmdline.h>
|
||||||
|
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
@ -56,85 +54,29 @@ typedef struct _AudinOpenSLESDevice
|
|||||||
|
|
||||||
AudinReceive receive;
|
AudinReceive receive;
|
||||||
|
|
||||||
HANDLE thread;
|
|
||||||
HANDLE stopEvent;
|
|
||||||
|
|
||||||
void* user_data;
|
void* user_data;
|
||||||
|
|
||||||
rdpContext* rdpcontext;
|
rdpContext* rdpcontext;
|
||||||
wLog* log;
|
wLog* log;
|
||||||
} AudinOpenSLESDevice;
|
} AudinOpenSLESDevice;
|
||||||
|
|
||||||
static DWORD WINAPI audin_opensles_thread_func(LPVOID arg)
|
static UINT audin_opensles_close(IAudinDevice* device);
|
||||||
|
|
||||||
|
static void audin_receive(void* context, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
union
|
UINT error;
|
||||||
|
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) context;
|
||||||
|
|
||||||
|
if (!opensles || !data)
|
||||||
{
|
{
|
||||||
void* v;
|
WLog_ERR(TAG, "[%s] Invalid arguments context=%p, data=%p", __FUNCTION__, opensles, data);
|
||||||
short* s;
|
return;
|
||||||
BYTE* b;
|
|
||||||
} buffer;
|
|
||||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) arg;
|
|
||||||
const size_t raw_size = opensles->frames_per_packet * opensles->bytes_per_channel;
|
|
||||||
int rc = CHANNEL_RC_OK;
|
|
||||||
UINT error = CHANNEL_RC_OK;
|
|
||||||
DWORD status;
|
|
||||||
WLog_Print(opensles->log, WLOG_DEBUG, "opensles=%p", (void*) opensles);
|
|
||||||
assert(opensles);
|
|
||||||
assert(opensles->frames_per_packet > 0);
|
|
||||||
assert(opensles->stopEvent);
|
|
||||||
assert(opensles->stream);
|
|
||||||
buffer.v = calloc(1, raw_size);
|
|
||||||
|
|
||||||
if (!buffer.v)
|
|
||||||
{
|
|
||||||
error = CHANNEL_RC_NO_MEMORY;
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "calloc failed!");
|
|
||||||
|
|
||||||
if (opensles->rdpcontext)
|
|
||||||
setChannelError(opensles->rdpcontext, CHANNEL_RC_NO_MEMORY,
|
|
||||||
"audin_opensles_thread_func reported an error");
|
|
||||||
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1)
|
error = opensles->receive(&opensles->format, data, size, opensles->user_data);
|
||||||
{
|
|
||||||
status = WaitForSingleObject(opensles->stopEvent, 0);
|
|
||||||
|
|
||||||
if (status == WAIT_FAILED)
|
|
||||||
{
|
|
||||||
error = GetLastError();
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"!", error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == WAIT_OBJECT_0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
rc = android_RecIn(opensles->stream, buffer.s, raw_size);
|
|
||||||
|
|
||||||
if (rc < 0)
|
|
||||||
{
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "android_RecIn %d", rc);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = opensles->receive(&opensles->format,
|
|
||||||
buffer.v, raw_size, opensles->user_data);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer.v);
|
|
||||||
out:
|
|
||||||
WLog_Print(opensles->log, WLOG_DEBUG, "thread shutdown.");
|
|
||||||
|
|
||||||
if (error && opensles->rdpcontext)
|
if (error && opensles->rdpcontext)
|
||||||
setChannelError(opensles->rdpcontext, error, "audin_opensles_thread_func reported an error");
|
setChannelError(opensles->rdpcontext, error, "audin_receive reported an error");
|
||||||
|
|
||||||
ExitThread(error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,8 +98,6 @@ static UINT audin_opensles_free(IAudinDevice* device)
|
|||||||
if (!opensles)
|
if (!opensles)
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
|
|
||||||
assert(opensles);
|
|
||||||
assert(!opensles->stream);
|
|
||||||
free(opensles->device_name);
|
free(opensles->device_name);
|
||||||
free(opensles);
|
free(opensles);
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
@ -274,46 +214,26 @@ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive,
|
|||||||
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*) device,
|
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*) device,
|
||||||
(void*) receive,
|
(void*) receive,
|
||||||
(void*) user_data);
|
(void*) user_data);
|
||||||
assert(opensles);
|
|
||||||
|
|
||||||
/* The function may have been called out of order,
|
|
||||||
* ignore duplicate open requests. */
|
|
||||||
if (opensles->stream)
|
if (opensles->stream)
|
||||||
return CHANNEL_RC_OK;
|
goto error_out;
|
||||||
|
|
||||||
if (!(opensles->stream = android_OpenRecDevice(
|
if (!(opensles->stream = android_OpenRecDevice(
|
||||||
opensles->device_name,
|
opensles, audin_receive,
|
||||||
opensles->format.nSamplesPerSec,
|
opensles->format.nSamplesPerSec,
|
||||||
opensles->format.nChannels,
|
opensles->format.nChannels,
|
||||||
opensles->frames_per_packet,
|
opensles->frames_per_packet,
|
||||||
opensles->format.wBitsPerSample)))
|
opensles->format.wBitsPerSample)))
|
||||||
{
|
{
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "android_OpenRecDevice failed!");
|
WLog_Print(opensles->log, WLOG_ERROR, "android_OpenRecDevice failed!");
|
||||||
return ERROR_INTERNAL_ERROR;
|
goto error_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
opensles->receive = receive;
|
opensles->receive = receive;
|
||||||
opensles->user_data = user_data;
|
opensles->user_data = user_data;
|
||||||
|
|
||||||
if (!(opensles->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
|
||||||
{
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "CreateEvent failed!");
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(opensles->thread = CreateThread(NULL, 0,
|
|
||||||
audin_opensles_thread_func, opensles, 0, NULL)))
|
|
||||||
{
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "CreateThread failed!");
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
error_out:
|
error_out:
|
||||||
android_CloseRecDevice(opensles->stream);
|
audin_opensles_close(opensles);
|
||||||
opensles->stream = NULL;
|
|
||||||
CloseHandle(opensles->stopEvent);
|
|
||||||
opensles->stopEvent = NULL;
|
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,38 +242,15 @@ error_out:
|
|||||||
*
|
*
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
* @return 0 on success, otherwise a Win32 error code
|
||||||
*/
|
*/
|
||||||
static UINT audin_opensles_close(IAudinDevice* device)
|
UINT audin_opensles_close(IAudinDevice* device)
|
||||||
{
|
{
|
||||||
UINT error;
|
|
||||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
|
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
|
||||||
|
|
||||||
|
if (!opensles)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device);
|
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device);
|
||||||
assert(opensles);
|
|
||||||
|
|
||||||
/* The function may have been called out of order,
|
|
||||||
* ignore duplicate requests. */
|
|
||||||
if (!opensles->stopEvent)
|
|
||||||
{
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "[ERROR] function called without matching open.");
|
|
||||||
return ERROR_REQUEST_OUT_OF_SEQUENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(opensles->stopEvent);
|
|
||||||
assert(opensles->thread);
|
|
||||||
assert(opensles->stream);
|
|
||||||
SetEvent(opensles->stopEvent);
|
|
||||||
|
|
||||||
if (WaitForSingleObject(opensles->thread, INFINITE) == WAIT_FAILED)
|
|
||||||
{
|
|
||||||
error = GetLastError();
|
|
||||||
WLog_Print(opensles->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"", error);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(opensles->stopEvent);
|
|
||||||
CloseHandle(opensles->thread);
|
|
||||||
android_CloseRecDevice(opensles->stream);
|
android_CloseRecDevice(opensles->stream);
|
||||||
opensles->stopEvent = NULL;
|
|
||||||
opensles->thread = NULL;
|
|
||||||
opensles->receive = NULL;
|
opensles->receive = NULL;
|
||||||
opensles->user_data = NULL;
|
opensles->user_data = NULL;
|
||||||
opensles->stream = NULL;
|
opensles->stream = NULL;
|
||||||
|
@ -34,6 +34,39 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#define CONV16BIT 32768
|
#define CONV16BIT 32768
|
||||||
#define CONVMYFLT (1./32768.)
|
#define CONVMYFLT (1./32768.)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
void* data;
|
||||||
|
} queue_element;
|
||||||
|
|
||||||
|
struct opensl_stream
|
||||||
|
{
|
||||||
|
// engine interfaces
|
||||||
|
SLObjectItf engineObject;
|
||||||
|
SLEngineItf engineEngine;
|
||||||
|
|
||||||
|
// device interfaces
|
||||||
|
SLDeviceVolumeItf deviceVolume;
|
||||||
|
|
||||||
|
// recorder interfaces
|
||||||
|
SLObjectItf recorderObject;
|
||||||
|
SLRecordItf recorderRecord;
|
||||||
|
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
||||||
|
|
||||||
|
unsigned int inchannels;
|
||||||
|
unsigned int sr;
|
||||||
|
unsigned int buffersize;
|
||||||
|
unsigned int bits_per_sample;
|
||||||
|
|
||||||
|
queue_element* prep;
|
||||||
|
queue_element* next;
|
||||||
|
|
||||||
|
void* context;
|
||||||
|
opensl_receive_t receive;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
|
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
|
||||||
|
|
||||||
// creates the OpenSL ES audio engine
|
// creates the OpenSL ES audio engine
|
||||||
@ -236,42 +269,84 @@ static void openSLDestroyEngine(OPENSL_STREAM* p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static queue_element* opensles_queue_element_new(size_t size)
|
||||||
|
{
|
||||||
|
queue_element* q = calloc(1, sizeof(queue_element));
|
||||||
|
|
||||||
|
if (!q)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
q->size = size;
|
||||||
|
q->data = malloc(size);
|
||||||
|
|
||||||
|
if (!q->data)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return q;
|
||||||
|
fail:
|
||||||
|
free(q);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void opensles_queue_element_free(void* obj)
|
||||||
|
{
|
||||||
|
queue_element* e = (queue_element*)obj;
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
free(e->data);
|
||||||
|
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
|
||||||
// open the android audio device for input
|
// open the android audio device for input
|
||||||
OPENSL_STREAM* android_OpenRecDevice(char* name, int sr, int inchannels,
|
OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive,
|
||||||
|
int sr,
|
||||||
|
int inchannels,
|
||||||
int bufferframes, int bits_per_sample)
|
int bufferframes, int bits_per_sample)
|
||||||
{
|
{
|
||||||
OPENSL_STREAM* p;
|
OPENSL_STREAM* p;
|
||||||
|
|
||||||
|
if (!context || !receive)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
p = (OPENSL_STREAM*) calloc(1, sizeof(OPENSL_STREAM));
|
p = (OPENSL_STREAM*) calloc(1, sizeof(OPENSL_STREAM));
|
||||||
|
|
||||||
if (!p)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
p->context = context;
|
||||||
|
p->receive = receive;
|
||||||
p->inchannels = inchannels;
|
p->inchannels = inchannels;
|
||||||
p->sr = sr;
|
p->sr = sr;
|
||||||
p->queue = Queue_New(TRUE, -1, -1);
|
|
||||||
p->buffersize = bufferframes;
|
p->buffersize = bufferframes;
|
||||||
p->bits_per_sample = bits_per_sample;
|
p->bits_per_sample = bits_per_sample;
|
||||||
|
|
||||||
if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16))
|
if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16))
|
||||||
{
|
goto fail;
|
||||||
android_CloseRecDevice(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openSLCreateEngine(p) != SL_RESULT_SUCCESS)
|
if (openSLCreateEngine(p) != SL_RESULT_SUCCESS)
|
||||||
{
|
goto fail;
|
||||||
android_CloseRecDevice(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openSLRecOpen(p) != SL_RESULT_SUCCESS)
|
if (openSLRecOpen(p) != SL_RESULT_SUCCESS)
|
||||||
{
|
goto fail;
|
||||||
android_CloseRecDevice(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Create receive buffers, prepare them and start recording */
|
||||||
|
p->prep = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
|
||||||
|
p->next = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
|
||||||
|
|
||||||
|
if (!p->prep || !p->next)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
|
||||||
|
p->next->data, p->next->size);
|
||||||
|
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
|
||||||
|
p->prep->data, p->prep->size);
|
||||||
|
(*p->recorderRecord)->SetRecordState(p->recorderRecord,
|
||||||
|
SL_RECORDSTATE_RECORDING);
|
||||||
return p;
|
return p;
|
||||||
|
fail:
|
||||||
|
android_CloseRecDevice(p);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// close the android audio device
|
// close the android audio device
|
||||||
@ -280,30 +355,8 @@ void android_CloseRecDevice(OPENSL_STREAM* p)
|
|||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (p->queue)
|
opensles_queue_element_free(p->next);
|
||||||
{
|
opensles_queue_element_free(p->prep);
|
||||||
while (Queue_Count(p->queue) > 0)
|
|
||||||
{
|
|
||||||
queue_element* e = Queue_Dequeue(p->queue);
|
|
||||||
free(e->data);
|
|
||||||
free(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Queue_Free(p->queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->next)
|
|
||||||
{
|
|
||||||
free(p->next->data);
|
|
||||||
free(p->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->prep)
|
|
||||||
{
|
|
||||||
free(p->prep->data);
|
|
||||||
free(p->prep);
|
|
||||||
}
|
|
||||||
|
|
||||||
openSLDestroyEngine(p);
|
openSLDestroyEngine(p);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
@ -311,86 +364,25 @@ void android_CloseRecDevice(OPENSL_STREAM* p)
|
|||||||
// this callback handler is called every time a buffer finishes recording
|
// this callback handler is called every time a buffer finishes recording
|
||||||
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
|
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
|
||||||
{
|
{
|
||||||
queue_element* e;
|
|
||||||
OPENSL_STREAM* p = (OPENSL_STREAM*) context;
|
OPENSL_STREAM* p = (OPENSL_STREAM*) context;
|
||||||
assert(p);
|
queue_element* e;
|
||||||
assert(p->next);
|
|
||||||
assert(p->prep);
|
if (!p)
|
||||||
assert(p->queue);
|
return;
|
||||||
e = calloc(1, sizeof(queue_element));
|
|
||||||
|
e = p->next;
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e->data = calloc(p->buffersize, p->bits_per_sample / 8);
|
if (!p->context || !p->receive)
|
||||||
|
WLog_WARN(TAG, "Missing receive callback=%p, context=%p", p->receive, p->context);
|
||||||
|
else
|
||||||
|
p->receive(p->context, e->data, e->size);
|
||||||
|
|
||||||
if (!e->data)
|
|
||||||
{
|
|
||||||
free(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e->size = p->buffersize * p->bits_per_sample / 8;
|
|
||||||
Queue_Enqueue(p->queue, p->next);
|
|
||||||
p->next = p->prep;
|
p->next = p->prep;
|
||||||
p->prep = e;
|
p->prep = e;
|
||||||
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
|
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
|
||||||
e->data, e->size);
|
e->data, e->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets a buffer of size samples from the device
|
|
||||||
int android_RecIn(OPENSL_STREAM* p, short* buffer, int size)
|
|
||||||
{
|
|
||||||
queue_element* e;
|
|
||||||
int rc;
|
|
||||||
DWORD status;
|
|
||||||
assert(p);
|
|
||||||
assert(buffer);
|
|
||||||
assert(size > 0);
|
|
||||||
|
|
||||||
/* Initial trigger for the queue. */
|
|
||||||
if (!p->prep)
|
|
||||||
{
|
|
||||||
p->prep = calloc(1, sizeof(queue_element));
|
|
||||||
p->prep->data = calloc(p->buffersize, p->bits_per_sample / 8);
|
|
||||||
p->prep->size = p->buffersize * p->bits_per_sample / 8;
|
|
||||||
p->next = calloc(1, sizeof(queue_element));
|
|
||||||
p->next->data = calloc(p->buffersize, p->bits_per_sample / 8);
|
|
||||||
p->next->size = p->buffersize * p->bits_per_sample / 8;
|
|
||||||
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
|
|
||||||
p->next->data, p->next->size);
|
|
||||||
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
|
|
||||||
p->prep->data, p->prep->size);
|
|
||||||
(*p->recorderRecord)->SetRecordState(p->recorderRecord,
|
|
||||||
SL_RECORDSTATE_RECORDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for queue to be filled... */
|
|
||||||
if (!Queue_Count(p->queue))
|
|
||||||
{
|
|
||||||
status = WaitForSingleObject(p->queue->event, INFINITE);
|
|
||||||
|
|
||||||
if (status == WAIT_FAILED)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", GetLastError());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e = Queue_Dequeue(p->queue);
|
|
||||||
|
|
||||||
if (!e)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[ERROR] got e=NULL from queue");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = (e->size < size) ? e->size : size;
|
|
||||||
assert(size == e->size);
|
|
||||||
assert(p->buffersize * p->bits_per_sample / 8 == size);
|
|
||||||
memcpy(buffer, e->data, rc);
|
|
||||||
free(e->data);
|
|
||||||
free(e);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -33,9 +33,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <SLES/OpenSLES.h>
|
#include <SLES/OpenSLES.h>
|
||||||
#include <SLES/OpenSLES_Android.h>
|
#include <SLES/OpenSLES_Android.h>
|
||||||
|
|
||||||
#include <winpr/synch.h>
|
|
||||||
#include <winpr/collections.h>
|
|
||||||
|
|
||||||
#include <freerdp/api.h>
|
#include <freerdp/api.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -44,51 +41,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct
|
typedef struct opensl_stream OPENSL_STREAM;
|
||||||
{
|
|
||||||
size_t size;
|
|
||||||
void* data;
|
|
||||||
} queue_element;
|
|
||||||
|
|
||||||
typedef struct opensl_stream
|
typedef void (*opensl_receive_t)(void* context, const void* data, size_t size);
|
||||||
{
|
|
||||||
// engine interfaces
|
|
||||||
SLObjectItf engineObject;
|
|
||||||
SLEngineItf engineEngine;
|
|
||||||
|
|
||||||
// device interfaces
|
|
||||||
SLDeviceVolumeItf deviceVolume;
|
|
||||||
|
|
||||||
// recorder interfaces
|
|
||||||
SLObjectItf recorderObject;
|
|
||||||
SLRecordItf recorderRecord;
|
|
||||||
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
|
||||||
|
|
||||||
unsigned int inchannels;
|
|
||||||
unsigned int sr;
|
|
||||||
unsigned int buffersize;
|
|
||||||
unsigned int bits_per_sample;
|
|
||||||
|
|
||||||
wQueue* queue;
|
|
||||||
queue_element* prep;
|
|
||||||
queue_element* 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), input and output channels and IO buffer size
|
||||||
in frames. Returns a handle to the OpenSL stream
|
in frames. Returns a handle to the OpenSL stream
|
||||||
*/
|
*/
|
||||||
FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(char* name, int sr,
|
FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context,
|
||||||
|
opensl_receive_t receive, int sr,
|
||||||
int inchannels,
|
int inchannels,
|
||||||
int bufferframes, int bits_per_sample);
|
int bufferframes, int bits_per_sample);
|
||||||
/*
|
/*
|
||||||
Close the audio device
|
Close the audio device
|
||||||
*/
|
*/
|
||||||
FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p);
|
FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p);
|
||||||
/*
|
|
||||||
Read a buffer from the OpenSL stream *p, of size samples. Returns the number of samples read.
|
|
||||||
*/
|
|
||||||
FREERDP_LOCAL int android_RecIn(OPENSL_STREAM* p, short* buffer, int size);
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user