/*
 * OpenMRCP - Open Source Media Resource Control Protocol Stack
 * Copyright (C) 2007, Cepstral LLC
 *
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Author(s):
 * Arsen Chaloyan <achaloyan@yahoo.com>
 *
 * Contributor(s):
 *
 */

#include <stdio.h>
#include "media_context.h"
#include "audio_source.h"
#include "audio_sink.h"

struct media_connector_t {
	media_context_t base;

	media_frame_t   media_frame;

	audio_source_t *source;
	audio_sink_t   *sink;

	FILE           *capture;
};


static apr_status_t media_connector_destroy(media_context_t *context)
{
	media_connector_t *connector = (media_connector_t*)context;
	if(connector->capture) {
		fclose(connector->capture);
		connector->capture = NULL;
	}
	return APR_SUCCESS;
}

static apr_status_t media_connector_audio_source_add(media_context_t *context, audio_source_t *source)
{
	media_connector_t *connector = (media_connector_t*)context;
	if(connector->source != source) {
		connector->source = source;
		if(source->method_set->open) {
			source->method_set->open(source);
		}
	}
	return APR_SUCCESS;
}

static apr_status_t media_connector_audio_source_remove(media_context_t *context, audio_source_t *source)
{
	media_connector_t *connector = (media_connector_t*)context;
	if(connector->source == source) {
		if(source->method_set->close) {
			source->method_set->close(source);
		}
		connector->source = NULL;
	}
	return APR_SUCCESS;
}

static apr_status_t media_connector_audio_sink_add(media_context_t *context, audio_sink_t *sink)
{
	media_connector_t *connector = (media_connector_t*)context;
	if(connector->sink != sink) {
		connector->sink = sink;
		if(sink->method_set->open) {
			sink->method_set->open(sink);
		}
	}
	return APR_SUCCESS;
}

static apr_status_t media_connector_audio_sink_remove(media_context_t *context, audio_sink_t *sink)
{
	media_connector_t *connector = (media_connector_t*)context;
	if(connector->sink == sink) {
		if(sink->method_set->close) {
			sink->method_set->close(sink);
		}
		connector->sink = NULL;
	}
	return APR_SUCCESS;
}

static apr_status_t media_connector_capture(media_connector_t *connector)
{
	fwrite(	connector->media_frame.codec_frame.buffer,
			1,
			connector->media_frame.codec_frame.size,
			connector->capture);
	return APR_SUCCESS;
}

static apr_status_t media_connector_process(media_context_t *context)
{
	media_connector_t *connector = (media_connector_t*)context;
	connector->media_frame.type = MEDIA_FRAME_TYPE_NONE;
	if(connector->source) {
		connector->source->method_set->read_frame(connector->source,&connector->media_frame);
	}
	if((connector->media_frame.type & MEDIA_FRAME_TYPE_AUDIO) == 0) {
		memset(	connector->media_frame.codec_frame.buffer,
				0,
				connector->media_frame.codec_frame.size);
	}
	if(connector->capture) {
		media_connector_capture(connector);
	}
	if(connector->sink) {
		connector->sink->method_set->write_frame(connector->sink,&connector->media_frame);
	}
	return APR_SUCCESS;
}


static const media_context_method_set_t method_set = {
	media_connector_destroy,
	media_connector_audio_source_add,
	media_connector_audio_source_remove,
	media_connector_audio_sink_add,
	media_connector_audio_sink_remove,
	media_connector_process
};

media_context_t* media_connector_create(apr_uint16_t sampling_rate, apr_pool_t *pool)
{
	media_connector_t *connector = apr_palloc(pool,sizeof(media_connector_t));
	media_context_init(&connector->base,pool);
	connector->base.method_set = &method_set;

	connector->media_frame.codec_frame.size = 2 * CODEC_FRAME_TIME_BASE * sampling_rate / 1000;
	connector->media_frame.codec_frame.buffer = apr_palloc(pool,connector->media_frame.codec_frame.size);

	connector->source = NULL;
	connector->sink = NULL;
	connector->capture = NULL;
#if 0
	connector->capture = fopen("capture.pcm","wb");
#endif
	return &connector->base;
}
