/***************************************************************************
 *   Copyright (C) 2007 by Sergio Pistone                                  *
 *   sergio_pistone@yahoo.com.ar                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "xineinput.h"

static xine_t* xine;
static xine_audio_port_t* audio_port;

XineInput::XineInput( std::string mrl, unsigned long timeLimitMS ):
	Input( timeLimitMS ),
	m_mrl( mrl ),
	m_stream( 0 ),
	m_hasMoreFrames( false ),
	m_framePos( 0 ),
	m_frameSize( 0 )
{
	xine = xine_new();
	//xine_engine_set_param( xine, XINE_ENGINE_PARAM_VERBOSITY, 10 );
	xine_init( xine );
	audio_port = xine_new_framegrab_audio_port( xine );
}

XineInput::~XineInput()
{
	if ( isOpened() )
		_close();

	xine_close_audio_driver( xine, audio_port );
	xine_exit( xine );
}

bool XineInput::setStreamMRL( std::string mrl )
{
	if ( isOpened() )
		return false;

	m_mrl = mrl;
	return true;
}

unsigned int XineInput::getBlockAlign()
{
	return isOpened() ? m_blockAlign : 0;
}

bool XineInput::_open()
{
	m_stream = xine_stream_new( xine, audio_port, NULL );
	xine_set_param( m_stream, XINE_PARAM_IGNORE_VIDEO, 1 );

	if ( ! xine_open( m_stream, m_mrl.c_str() ) )
		return false;

	xine_play( m_stream, 0, 0 );

	int posStream, posTime, totalTime;
	xine_get_pos_length( m_stream, &posStream, &posTime, &totalTime );
	m_totalTimeMS = totalTime;
	m_currentTimeMS = 0;

	m_hasMoreFrames = xine_get_next_audio_frame( audio_port, &m_frame );
	if ( ! m_hasMoreFrames )
	{
		xine_close( m_stream );
		xine_dispose( m_stream );
		return false;
	}

	m_sampleRate = m_frame.sample_rate;
	m_channels = m_frame.num_channels;
	m_bitsPerSample = m_frame.bits_per_sample;

	m_blockAlign = Input::getBlockAlign( m_channels, m_bitsPerSample );
	m_framePos = 0;
	m_frameSize = m_frame.num_samples*m_blockAlign;

	return true;
}

bool XineInput::_close()
{
	if ( m_hasMoreFrames )
		xine_free_audio_frame( audio_port, &m_frame );

	m_hasMoreFrames = false;
	m_blockAlign = 0;
	m_framePos = 0;
	m_frameSize = 0;

	m_sampleRate = 0;
	m_channels = 0;
	m_bitsPerSample = 0;

	//xine_stop( stream );
	//xine_close( stream );
	xine_dispose( m_stream );
	m_stream = 0;

	return true;
}

bool XineInput::_getPCMChunk( unsigned char* data, unsigned long limit, unsigned long &read )
{
	unsigned long chunkSize = 0;

	do
	{
		if ( limit && m_framePos < m_frameSize )
		{
			chunkSize = m_frameSize - m_framePos;
			if ( chunkSize > limit )
				chunkSize = limit;
			memcpy( data+read, m_frame.data+m_framePos, chunkSize );
			m_framePos += chunkSize;
			limit -= chunkSize;
			read += chunkSize;
		}

		if ( ! limit )
			break;

		if ( m_hasMoreFrames && m_framePos >= m_frameSize )
		{
			m_currentTimeMS = m_frame.pos_time;

			xine_free_audio_frame( audio_port, &m_frame );
			m_hasMoreFrames = xine_get_next_audio_frame( audio_port, &m_frame ) > 0;
			m_framePos = 0;
			m_frameSize = m_hasMoreFrames ? m_frame.num_samples*m_blockAlign : 0;
		}
	}
	while ( m_hasMoreFrames );

	return m_hasMoreFrames || m_framePos < m_frameSize;
}

/*typedef struct {
int64_t  vpts;       // timestamp 1/90000 sec for a/v sync
int      num_samples;
int      sample_rate;
int      num_channels;
int      bits_per_sample; // per channel

off_t    pos_stream; // bytes from stream start
int      pos_time;   // milliseconds

uint8_t *data;
void    *xine_frame; // used internally by xine engine
} xine_audio_frame_t;*/

/* To compile: gcc xinedump.c -lxine -D_FILE_OFFSET_BITS=64 */
