<commit_before>/**
 * FreeRDP: A Remote Desktop Protocol Implementation
 * Audio Input Redirection Virtual Channel - OpenSL ES implementation
 *
 * Copyright 2013 <NAME> <<EMAIL>>
 *
 * 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/cmdline.h>

#include <freerdp/addin.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/channels/rdpsnd.h>

#include <SLES/OpenSLES.h>

#include "audin_main.h"
#include "opensl_io.h"

typedef struct _AudinOpenSLESDevice
{
	IAudinDevice iface;

	char* device_name;
	OPENSL_STREAM *stream;

	UINT32 frames_per_packet;
	UINT32 rate;
	UINT32 channels;

	UINT32 bytes_per_channel;

	UINT32 format;
	UINT32 block_size;

	FREERDP_DSP_CONTEXT* dsp_context;
	AudinReceive receive;

	HANDLE thread;
	HANDLE stopEvent;

	void* user_data;
} AudinOpenSLESDevice;

static void* audin_opensles_thread_func(void* arg)
{
	union
	{
		void *v;
		short* s;
		BYTE *b;
	} buffer;
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) arg;

	DEBUG_DVC("opensles=%p", opensles);
	
	assert(opensles);
	assert(opensles->frames_per_packet > 0);
	assert(opensles->dsp_context);
	assert(opensles->stopEvent);
	assert(opensles->stream);

	buffer.v = calloc(opensles->bytes_per_channel, opensles->frames_per_packet);
	ZeroMemory(buffer.v, opensles->frames_per_packet);
	freerdp_dsp_context_reset_adpcm(opensles->dsp_context);

	while (!(WaitForSingleObject(opensles->stopEvent, 0) == WAIT_OBJECT_0))
	{
		size_t encoded_size;
		void *encoded_data;

		int rc = android_RecIn(opensles->stream, buffer.s,
				opensles->frames_per_packet);
		if (rc < 0)
		{
			DEBUG_WARN("android_RecIn %d", rc);
			continue;
		}

		if (opensles->format == WAVE_FORMAT_ADPCM)
		{
			opensles->dsp_context->encode_ms_adpcm(opensles->dsp_context,
				buffer.b, rc * opensles->bytes_per_channel,
				opensles->channels, opensles->block_size);

			encoded_data = opensles->dsp_context->adpcm_buffer;
			encoded_size = opensles->dsp_context->adpcm_size;
		}
		else if (opensles->format == WAVE_FORMAT_DVI_ADPCM)
		{
			opensles->dsp_context->encode_ima_adpcm(opensles->dsp_context,
				buffer.b, rc * opensles->bytes_per_channel,
				opensles->channels, opensles->block_size);

			encoded_data = opensles->dsp_context->adpcm_buffer;
			encoded_size = opensles->dsp_context->adpcm_size;
		}
		else
		{
			encoded_data = buffer.v;
			encoded_size = rc * opensles->bytes_per_channel;
		}

		DEBUG_DVC("encoded %d [%d] to %d [%X]", rc,
				opensles->bytes_per_channel, encoded_size, opensles->format);
		rc = opensles->receive(encoded_data, encoded_size, opensles->user_data);
		if (!rc)
			break;
	}

	free(buffer.v);

	DEBUG_DVC("thread shutdown.");

	ExitThread(0);
	return NULL;
}

static void audin_opensles_free(IAudinDevice* device)
{
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;

	DEBUG_DVC("device=%p", device);

	/* The function may have been called out of order,
	 * ignore duplicate requests. */
	if (!opensles)
		return;

	assert(opensles);
	assert(opensles->dsp_context);
	assert(!opensles->stream);

	freerdp_dsp_context_free(opensles->dsp_context);

	if (opensles->device_name)
		free(opensles->device_name);

	free(opensles);
}

static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* format)
{
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
	
	DEBUG_DVC("device=%p, format=%p", opensles, format);

	assert(format);

	switch (format->wFormatTag)
	{
		case WAVE_FORMAT_PCM: /* PCM */
			if (format->cbSize == 0 &&
				(format->nSamplesPerSec <= 48000) &&
				(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
				(format->nChannels >= 1 && format->nChannels <= 2))
			{
				return TRUE;
			}
			break;
//		case WAVE_FORMAT_ADPCM: /* IMA ADPCM */
		case WAVE_FORMAT_DVI_ADPCM: 
			if ((format->nSamplesPerSec <= 48000) &&
				(format->wBitsPerSample == 4) &&
				(format->nChannels == 1 || format->nChannels == 2))
			{
				return TRUE;
			}
			break;
		default:
			DEBUG_DVC("Encoding '%s' [%08X] not supported",
				rdpsnd_get_audio_tag_string(format->wFormatTag),
				format->wFormatTag); 
			break;
	}

	return FALSE;
}

static void audin_opensles_set_format(IAudinDevice* device,
		audinFormat* format, UINT32 FramesPerPacket)
{
	int bs;
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;

	DEBUG_DVC("device=%p, format=%p, FramesPerPacket=%d",<commit_msg>Deactivated formats not working.<commit_after>/**
 * FreeRDP: A Remote Desktop Protocol Implementation
 * Audio Input Redirection Virtual Channel - OpenSL ES implementation
 *
 * Copyright 2013 <NAME> <<EMAIL>>
 *
 * 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/cmdline.h>

#include <freerdp/addin.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/channels/rdpsnd.h>

#include <SLES/OpenSLES.h>

#include "audin_main.h"
#include "opensl_io.h"

typedef struct _AudinOpenSLESDevice
{
	IAudinDevice iface;

	char* device_name;
	OPENSL_STREAM *stream;

	UINT32 frames_per_packet;
	UINT32 rate;
	UINT32 channels;

	UINT32 bytes_per_channel;

	UINT32 format;
	UINT32 block_size;

	FREERDP_DSP_CONTEXT* dsp_context;
	AudinReceive receive;

	HANDLE thread;
	HANDLE stopEvent;

	void* user_data;
} AudinOpenSLESDevice;

static void* audin_opensles_thread_func(void* arg)
{
	union
	{
		void *v;
		short* s;
		BYTE *b;
	} buffer;
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) arg;

	DEBUG_DVC("opensles=%p", opensles);
	
	assert(opensles);
	assert(opensles->frames_per_packet > 0);
	assert(opensles->dsp_context);
	assert(opensles->stopEvent);
	assert(opensles->stream);

	buffer.v = calloc(opensles->bytes_per_channel, opensles->frames_per_packet);
	ZeroMemory(buffer.v, opensles->frames_per_packet);
	freerdp_dsp_context_reset_adpcm(opensles->dsp_context);

	while (!(WaitForSingleObject(opensles->stopEvent, 0) == WAIT_OBJECT_0))
	{
		size_t encoded_size;
		void *encoded_data;

		int rc = android_RecIn(opensles->stream, buffer.s,
				opensles->frames_per_packet);
		if (rc < 0)
		{
			DEBUG_WARN("android_RecIn %d", rc);
			continue;
		}

		if (opensles->format == WAVE_FORMAT_ADPCM)
		{
			opensles->dsp_context->encode_ms_adpcm(opensles->dsp_context,
				buffer.b, rc * opensles->bytes_per_channel,
				opensles->channels, opensles->block_size);

			encoded_data = opensles->dsp_context->adpcm_buffer;
			encoded_size = opensles->dsp_context->adpcm_size;
		}
		else if (opensles->format == WAVE_FORMAT_DVI_ADPCM)
		{
			opensles->dsp_context->encode_ima_adpcm(opensles->dsp_context,
				buffer.b, rc * opensles->bytes_per_channel,
				opensles->channels, opensles->block_size);

			encoded_data = opensles->dsp_context->adpcm_buffer;
			encoded_size = opensles->dsp_context->adpcm_size;
		}
		else
		{
			encoded_data = buffer.v;
			encoded_size = rc * opensles->bytes_per_channel;
		}

		DEBUG_DVC("encoded %d [%d] to %d [%X]", rc,
				opensles->bytes_per_channel, encoded_size, opensles->format);
		rc = opensles->receive(encoded_data, encoded_size, opensles->user_data);
		if (!rc)
			break;
	}

	free(buffer.v);

	DEBUG_DVC("thread shutdown.");

	ExitThread(0);
	return NULL;
}

static void audin_opensles_free(IAudinDevice* device)
{
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;

	DEBUG_DVC("device=%p", device);

	/* The function may have been called out of order,
	 * ignore duplicate requests. */
	if (!opensles)
		return;

	assert(opensles);
	assert(opensles->dsp_context);
	assert(!opensles->stream);

	freerdp_dsp_context_free(opensles->dsp_context);

	if (opensles->device_name)
		free(opensles->device_name);

	free(opensles);
}

static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* format)
{
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
	
	DEBUG_DVC("device=%p, format=%p", opensles, format);

	assert(format);

	switch (format->wFormatTag)
	{
		/* TODO: Deactivated, untested */
#if 0
		case WAVE_FORMAT_PCM: /* PCM */
			if (format->cbSize == 0 &&
				(format->nSamplesPerSec <= 48000) &&
				(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
				(format->nChannels >= 1 && format->nChannels <= 2))
			{
				return TRUE;
			}
			break;
#endif
			/* TODO: Deactivated format, does not work, find out why */
//		case WAVE_FORMAT_ADPCM: /* IMA ADPCM */
		case WAVE_FORMAT_DVI_ADPCM: 
			if ((format->nSamplesPerSec <= 48000) &&
				(format->wBitsPerSample == 4) &&
				(format->nChannels == 1 || format->nChannels == 2))
			{
				return TRUE;
			}
			break;
		default:
			DEBUG_DVC("Encoding '%s' [%08X] not supported",
				rdpsnd_get_audio_tag_string(format->wFormatTag),
				format->wFormatTag); 
			break;
	}

	return FALSE;
}

static void audin_opensles_set_format(IAudinDevice* device,
		audinFormat* format, UINT32 FramesPerPacket)
{
	int bs;
	AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;

	DEBUG_DVC("device=%p, format=%p, FramesPerPacket=%d",
{'fraction_non_alphanumeric': 0.12661926560825948, 'fraction_numerical': 0.009447745203077822, 'mean_word_length': 4.682346430547869, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 149, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3306662', 'n_tokens_mistral': 4039, 'n_tokens_neox': 3647, 'n_words': 783}