// AudioAdapterNode.cpp

#include "AudioAdapterNode.h"
#include "AudioAdapterParams.h"

#include "SoundUtils.h"


// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //

_AudioAdapterNode::~_AudioAdapterNode() {}

_AudioAdapterNode::_AudioAdapterNode(
	const char*									name,
	IAudioOpFactory*						opFactory,
	BMediaAddOn*								addOn) :
	
	BMediaNode(name),
	AudioFilterNode(name, opFactory, addOn) {
		
	PRINT((
		"\n"
		"--*-- _AudioAdapterNode() [%s] --*--\n\n",
		__BUILD_DATE));
}

// -------------------------------------------------------- //
// AudioFilterNode
// -------------------------------------------------------- //

status_t _AudioAdapterNode::getRequiredInputFormat(
	media_format&								ioFormat) {
		
	status_t err = getPreferredInputFormat(ioFormat);
	if(err < B_OK)
		return err;

	// 16sep99: input byte-swapping now supported		
	ioFormat.u.raw_audio.byte_order = media_raw_audio_format::wildcard.byte_order;
		
//	ioFormat.u.raw_audio.format = media_raw_audio_format::wildcard.format;
//	ioFormat.u.raw_audio.channel_count = media_raw_audio_format::wildcard.channel_count;
	_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
	ASSERT(p);
	
//	media_raw_audio_format& w = media_raw_audio_format::wildcard;
	
	// copy user preferences
	ioFormat.u.raw_audio.format = p->inputFormat.format;
	ioFormat.u.raw_audio.channel_count = p->inputFormat.channel_count;


	// don't require a buffer size until format & channel_count are known [16sep99]
	ioFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size;

	if(output().destination == media_destination::null) {
		// frame rate isn't constrained yet
		ioFormat.u.raw_audio.frame_rate = media_raw_audio_format::wildcard.frame_rate;
	}
				
	return B_OK;
}

// +++++ 17sep99: use parameter data!

status_t _AudioAdapterNode::getPreferredInputFormat(
	media_format&								ioFormat) {

	status_t err = _inherited::getPreferredInputFormat(ioFormat);
	if(err < B_OK)
		return err;
		
	_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
	ASSERT(p);
	
	media_raw_audio_format& w = media_raw_audio_format::wildcard;
	
	// copy user preferences
	ioFormat.u.raw_audio.format = p->inputFormat.format;
	ioFormat.u.raw_audio.channel_count = p->inputFormat.channel_count;
		
//	// if one end is connected, prefer not to do channel conversions [15sep99]
//	if(output().destination != media_destination::null)
//		ioFormat.u.raw_audio.channel_count = output().format.u.raw_audio.channel_count;	

	// if output connected, constrain:
	//   buffer_size
	//   frame_rate
	if(output().destination != media_destination::null) {
		// if the user doesn't care, default to the output's frame format
		if(ioFormat.u.raw_audio.format == w.format)
			ioFormat.u.raw_audio.format = output().format.u.raw_audio.format;
		if(ioFormat.u.raw_audio.channel_count == w.channel_count)
			ioFormat.u.raw_audio.channel_count = output().format.u.raw_audio.channel_count;

		ioFormat.u.raw_audio.buffer_size =
			bytes_per_frame(ioFormat.u.raw_audio) *
				frames_per_buffer(output().format.u.raw_audio);
		ioFormat.u.raw_audio.frame_rate = output().format.u.raw_audio.frame_rate;		
	}

	return B_OK;
}
	
status_t _AudioAdapterNode::getRequiredOutputFormat(
	media_format&								ioFormat) {
		
	status_t err = getPreferredOutputFormat(ioFormat);
	if(err < B_OK)
		return err;
		
	ioFormat.u.raw_audio.format = media_raw_audio_format::wildcard.format;
	ioFormat.u.raw_audio.channel_count = media_raw_audio_format::wildcard.channel_count;

	_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
	ASSERT(p);
	
//	media_raw_audio_format& w = media_raw_audio_format::wildcard;
	
	// copy user preferences
	ioFormat.u.raw_audio.format = p->outputFormat.format;
	ioFormat.u.raw_audio.channel_count = p->outputFormat.channel_count;

	// don't require a buffer size until format & channel_count are known [16sep99]
	ioFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size;
		
	if(input().source == media_source::null) {
		// frame rate isn't constrained yet
		ioFormat.u.raw_audio.frame_rate = media_raw_audio_format::wildcard.frame_rate;
	}
		
	return B_OK;
}
	
// +++++ 17sep99: use parameter data!

status_t _AudioAdapterNode::getPreferredOutputFormat(
	media_format&								ioFormat) {

	status_t err = _inherited::getPreferredOutputFormat(ioFormat);
	if(err < B_OK)
		return err;
		
	_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
	ASSERT(p);
	
	media_raw_audio_format& w = media_raw_audio_format::wildcard;
	
	// copy user preferences
	ioFormat.u.raw_audio.format = p->outputFormat.format;
	ioFormat.u.raw_audio.channel_count = p->outputFormat.channel_count;

////	// if one end is connected, prefer not to do channel conversions [15sep99]
////	if(input().source != media_source::null)
////		ioFormat.u.raw_audio.channel_count = input().format.u.raw_audio.channel_count;
		
	// if input connected, constrain:
	//   buffer_size
	//   frame_rate
	if(input().source != media_source::null) {		
		// if the user doesn't care, default to the input's frame format
		if(ioFormat.u.raw_audio.format == w.format)
			ioFormat.u.raw_audio.format = input().format.u.raw_audio.format;
		if(ioFormat.u.raw_audio.channel_count == w.channel_count)
			ioFormat.u.raw_audio.channel_count = input().format.u.raw_audio.channel_count;

		ioFormat.u.raw_audio.buffer_size =
			bytes_per_frame(ioFormat.u.raw_audio) *
				frames_per_buffer(input().format.u.raw_audio);
		PRINT(("##### preferred output buffer_size: %ld (%x)\n", ioFormat.u.raw_audio.buffer_size, ioFormat.u.raw_audio.buffer_size));
		ioFormat.u.raw_audio.frame_rate = input().format.u.raw_audio.frame_rate;

	}

	return B_OK;
}
	
status_t _AudioAdapterNode::validateProposedInputFormat(
	const media_format&					preferredFormat,
	media_format&								ioProposedFormat) {
		
	status_t err = _inherited::validateProposedInputFormat(
		preferredFormat, ioProposedFormat);
		
	media_raw_audio_format& w = media_raw_audio_format::wildcard;
		
	if(output().destination != media_destination::null) {

		// an output connection exists; constrain the input format
		
		// is there enough information to suggest a buffer size?
		if(
			ioProposedFormat.u.raw_audio.format != w.format &&
			ioProposedFormat.u.raw_audio.channel_count != w.channel_count) {
					
			size_t target_buffer_size = 
				bytes_per_frame(ioProposedFormat.u.raw_audio) *
					frames_per_buffer(output().format.u.raw_audio);
	
			if(ioProposedFormat.u.raw_audio.buffer_size != target_buffer_size) {
				if(ioProposedFormat.u.raw_audio.buffer_size != w.buffer_size)
					err = B_MEDIA_BAD_FORMAT;

				ioProposedFormat.u.raw_audio.buffer_size = target_buffer_size;
			}
		}
			
		// require output frame rate
		if(ioProposedFormat.u.raw_audio.frame_rate != output().format.u.raw_audio.frame_rate) {
			if(ioProposedFormat.u.raw_audio.frame_rate != w.frame_rate)
				err = B_MEDIA_BAD_FORMAT;

			ioProposedFormat.u.raw_audio.frame_rate = output().format.u.raw_audio.frame_rate;
		}
	}
		
	char fmt_string[256];
	string_for_format(ioProposedFormat, fmt_string, 255);
		PRINT((
		"### _AudioAdapterNode::validateProposedInputFormat():\n"
		"    %s\n", fmt_string));
	return err;
}

status_t _AudioAdapterNode::validateProposedOutputFormat(
	const media_format&					preferredFormat,
	media_format&								ioProposedFormat) {
		
	status_t err = _inherited::validateProposedOutputFormat(
		preferredFormat, ioProposedFormat);
		
	media_raw_audio_format& w = media_raw_audio_format::wildcard;
		
	if(input().source != media_source::null) {

		// an input connection exists; constrain the output format

		// is there enough information to suggest a buffer size?
		if(
			ioProposedFormat.u.raw_audio.format != w.format &&
			ioProposedFormat.u.raw_audio.channel_count != w.channel_count) {
					
			size_t target_buffer_size = 
				bytes_per_frame(ioProposedFormat.u.raw_audio) *
					frames_per_buffer(input().format.u.raw_audio);

			if(ioProposedFormat.u.raw_audio.buffer_size != target_buffer_size) {
				if(ioProposedFormat.u.raw_audio.buffer_size != w.buffer_size)
					err = B_MEDIA_BAD_FORMAT;

				ioProposedFormat.u.raw_audio.buffer_size = target_buffer_size;
			}
		}
		
		// require same frame rate as input
		if(ioProposedFormat.u.raw_audio.frame_rate != input().format.u.raw_audio.frame_rate) {
			if(ioProposedFormat.u.raw_audio.frame_rate != w.frame_rate)
				err = B_MEDIA_BAD_FORMAT;

			ioProposedFormat.u.raw_audio.frame_rate = input().format.u.raw_audio.frame_rate;
		}
	}
	
	char fmt_string[256];
	string_for_format(ioProposedFormat, fmt_string, 255);
	PRINT((
		"### _AudioAdapterNode::validateProposedOutputFormat():\n"
		"    %s\n", fmt_string));
	return err;
}

// -------------------------------------------------------- //
// BBufferProducer/Consumer
// -------------------------------------------------------- //

// lock input
status_t _AudioAdapterNode::Connected(
	const media_source&					source,
	const media_destination&		destination,
	const media_format&					format,
	media_input*								outInput) {
	
	status_t err = _inherited::Connected(
		source, destination, format, outInput);
	
	if(err == B_OK) {
		_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
		ASSERT(p);	
		p->inputLocked = true;
	}
	
	return err;
}	

// unlock input
void _AudioAdapterNode::Disconnected(
	const media_source&					source,
	const media_destination&		destination) {
	
	_inherited::Disconnected(
		source, destination);
		
	_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
	ASSERT(p);	
	p->inputLocked = false;
}

// lock output
void _AudioAdapterNode::Connect(
	status_t										status,
	const media_source&					source,
	const media_destination&		destination,
	const media_format&					format,
	char*												ioName) {

	if(status == B_OK) {
		_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
		ASSERT(p);	
		p->outputLocked = true;
	}	
	
	_inherited::Connect(
		status, source, destination, format, ioName);
}
		
// unlock output
void _AudioAdapterNode::Disconnect(
	const media_source&					source,
	const media_destination&		destination) {
	
	_AudioAdapterParams* p = dynamic_cast<_AudioAdapterParams*>(parameterSet());
	ASSERT(p);	
	p->outputLocked = false;
	
	return _inherited::Disconnect(
		source, destination);
}

//// AudioFilterNode::FormatProposal() simply validates the proposed format.
//// 17sep99: if an input connection's been made, specialize the given output
//// format enough to suggest a buffer size (format & channel_count.)
//
//// +++++ with user assistance via format/channel_count, is this still needed?
////       17sep99
//status_t _AudioAdapterNode::FormatProposal(
//	const media_source&					source,
//	media_format*								ioFormat) {
//
//	PRINT(("### _AudioAdapterNode::FormatProposal()\n"));
//	// hand off to base implementation (which calls validateProposedOutputFormat().)
//	status_t err = _inherited::FormatProposal(source, ioFormat);
//
//	media_raw_audio_format& w = media_raw_audio_format::wildcard;
//
//	if(input().source != media_source::null) {
//		
//		// an input connection exists; make sure the format carries enough information
//		// to determine frame size (format & channel_count).  prefer not to convert
//		// from the input format.
//		
//		if(ioFormat->u.raw_audio.format == w.format)
//			ioFormat->u.raw_audio.format = input().format.u.raw_audio.format;
//
//		if(ioFormat->u.raw_audio.channel_count == w.channel_count)
//			ioFormat->u.raw_audio.channel_count = input().format.u.raw_audio.channel_count;
//		
//		// figure required buffer size for this format
//		size_t target_buffer_size = 
//			bytes_per_frame(ioFormat->u.raw_audio) *
//				frames_per_buffer(input().format.u.raw_audio);
//
//		if(ioFormat->u.raw_audio.buffer_size != target_buffer_size) {
//			if(ioFormat->u.raw_audio.buffer_size != w.buffer_size)
//				err = B_MEDIA_BAD_FORMAT;
//
//			ioFormat->u.raw_audio.buffer_size = target_buffer_size;
//		}			
//	}
//
//	char fmt_buffer[256];
//	string_for_format(*ioFormat, fmt_buffer, 255);
//	PRINT(("### END: FormatProposal() '%s'\n", fmt_buffer));
//	
//	return err;
//}


// END -- AudioAdapterNode.cpp --