/*
 * Copyright (C) Volition, Inc. 1999.  All rights reserved.
 *
 * All source code herein is the property of Volition, Inc. You may not sell 
 * or otherwise commercially exploit the source or things you created based on the 
 * source.
 *
*/

#include "globalincs/pstypes.h"
#include "sound/ds.h"
#include "sound/dscap.h"
#include "sound/openal.h"

#include <string>


int dscap_inited = 0;						// flag to indicate that DirectSoundCapture inited ok
int dscap_recording = 0;						// flag to indicate that sound is being recorded

typedef struct ALcapture_t {
	uint samples_per_second;
	uint bits_per_sample;
	uint n_channels;
	uint block_align;

	ALenum format;
	ALsizei buffer_size;
} ALcapture_t;

static ALcapture_t ALCaptureInfo;

static ALCdevice *ds_capture_device = NULL;
static SCP_string capture_dev_name;


// init the capture system
// exit:	0	->		success
//			!0	->		failure
int dscap_init()
{
	if (dscap_inited) {
		return 0;
	}

	bool rval = openal_init_device(NULL, &capture_dev_name);

	if ( !rval || capture_dev_name.empty() ) {
		dscap_inited = 0;

		return -1;
	}

	dscap_inited = 1;

	return 0;
}

void dscap_release_buffer()
{
	if (ds_capture_device != NULL) {
		OpenAL_C_ErrorPrint( alcCaptureCloseDevice(ds_capture_device) );
		ds_capture_device = NULL;
	}
}

// create a capture buffer with the specified format
// exit:	0	->		buffer created successfully
//			!0	->		error creating the buffer
int dscap_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
{
	ALenum al_format = AL_FORMAT_MONO8;
	ALsizei buf_size = freq * nseconds;

	if ( !dscap_inited ) {
		dscap_init();
	}

	//Just in case we couldn't init for whatever reason
	if ( !dscap_inited ) { //-V581
		return -1;
	}

	Assert( (nchannels == 1) || (nchannels == 2) );
	Assert( (bits_per_sample == 8) || (bits_per_sample == 16) );

	if (nchannels == 1) {
		if (bits_per_sample == 8)  {
			al_format = AL_FORMAT_MONO8;
		} else if (bits_per_sample == 16) {
			al_format = AL_FORMAT_MONO16;
		}
	} else if (nchannels == 2) {
		if (bits_per_sample == 8) {
			al_format = AL_FORMAT_STEREO8;
		} else if (bits_per_sample == 16) {
			al_format = AL_FORMAT_STEREO16;
		}
	}

	const ALCchar *dev_name = (const ALCchar*) capture_dev_name.c_str();
	ds_capture_device = alcCaptureOpenDevice(dev_name, freq, al_format, buf_size);

	if (ds_capture_device == NULL) {
		return -1;
	}

	if ( alcGetError(ds_capture_device) != ALC_NO_ERROR ) {
		return -1;
	}

	ALCaptureInfo.format = al_format;
	ALCaptureInfo.bits_per_sample = bits_per_sample;
	ALCaptureInfo.n_channels = nchannels;
	ALCaptureInfo.samples_per_second = freq;
	ALCaptureInfo.block_align = (nchannels * bits_per_sample) / 8;

	return 0;
}

// check if DirectSoundCapture is supported
int dscap_supported()
{
	if ( !dscap_inited ) {
		dscap_init();
	}

	return dscap_inited;
}

// start recording into the buffer
int dscap_start_record()
{
	if ( !dscap_inited ) {
		return -1;
	}

	if (dscap_recording) {
		return -1;
	}

	OpenAL_C_ErrorCheck( alcCaptureStart(ds_capture_device), return -1 );

	dscap_recording = 1;

//	nprintf(("Alan","RTVOICE => start record\n"));

	return 0;
}

// stop recording into the buffer
int dscap_stop_record()
{
	if ( !dscap_inited ) {
		return -1;
	}

	if ( !dscap_recording ) {
		return -1;
	}

	OpenAL_C_ErrorCheck( alcCaptureStop(ds_capture_device), return -1 );

	dscap_recording = 0;

//	nprintf(("Alan","RTVOICE => stop record\n"));

	return 0;
}

// close the DirectSoundCapture system
void dscap_close()
{
	dscap_stop_record();

	if (ds_capture_device != NULL) {
		OpenAL_C_ErrorPrint( alcCaptureCloseDevice(ds_capture_device) );
		ds_capture_device = NULL;
	}
}

// return the max buffer size
int dscap_max_buffersize()
{
	if ( !dscap_inited ) {
		dscap_init();
	}

	//Just in case we're still not initialized
	if ( !dscap_inited ) { //-V581
		return -1;
	}

	ALCsizei num_samples = 0;

	OpenAL_C_ErrorCheck( alcGetIntegerv(ds_capture_device, ALC_CAPTURE_SAMPLES, sizeof(ALCsizei), &num_samples), return -1 );

	return (num_samples * ALCaptureInfo.block_align);
}

// retreive the recorded voice data
int dscap_get_raw_data(unsigned char *outbuf, unsigned int max_size)
{
	if ( !dscap_inited ) {
		dscap_init();
	}

	//Just in case we're still not initialized
	if ( !dscap_inited ) { //-V581
		return 0;
	}

	if (outbuf == NULL) {
		return 0;
	}

	ALCsizei num_samples = 0;

	OpenAL_C_ErrorPrint( alcGetIntegerv(ds_capture_device, ALC_CAPTURE_SAMPLES, sizeof(ALCsizei), &num_samples) );

	if (num_samples <= 0) {
		return 0;
	}

	ALCsizei max_buf_size = MIN(num_samples, ALsizei(max_size / ALCaptureInfo.block_align));

	OpenAL_C_ErrorCheck( alcCaptureSamples(ds_capture_device, outbuf, max_buf_size), return 0 );

	return (int)max_buf_size * ALCaptureInfo.block_align;
}

