/*
 * audioreceiver.c
 */

#include "audioreceiver.h"
#include "postproc.h"


/* --- cAudioReceiver ------------------------------------------------------- */

cAudioReceiver::cAudioReceiver(const cChannel *_channel) 

#if VDRVERSNUM >= 10500
:cReceiver(_channel->GetChannelID(), -2, _channel->Apid(0)), cThread()
#else
:cReceiver(0, -2, _channel->Apid(0)), cThread()
#endif
{
        channel = _channel;
        
        active = false;
        
        pes_sync = false;
	device_number = -1;
	recstat = recWait;
        
        buffer = NULL;
        rds = NULL;
        postdata = NULL;
        
        dsyslog("[audiorecorder]: receiver for channel <%s> created on pid %d "
                "(%s, %s())", channel->Name(), channel->Apid(0), __FILE__,
                __func__);
}


cAudioReceiver::~cAudioReceiver(void)
{
	Activate(false);
        
        DELETE(buffer);
        DELETE(rds);
        DELETE(postdata);
}


void cAudioReceiver::Receive(uchar *data, int length)
{
        int ts_header_len, header_len, data_len, rb_len;
        
        if (! active || data[0] != 0x47)
                return;
        
        /* check adaptation field */ 
        switch (data[3] & 0x30) {
        case 0x10:
                /* no adaptation field, payload only */
                ts_header_len = 4;
                break;
        case 0x30:
                /* adaptation field followed by payload */
                ts_header_len = data[4] + 5;
                break;
        default:
                return;
        }
        
        header_len = ts_header_len;
        
        /* check payload unit start indicator */
        if ((data[1] & 0x40) == 0x40) {
                /* ts-header is followed by a pes-header */
                header_len  += data[ts_header_len + 8] + 9;
                pes_sync = true;
        }
        
        if (! pes_sync)
                return;
        
        /* put mp2-data into the ringbuffer */
        data_len = length - header_len;
        rb_len = buffer->Put(data + header_len, data_len);
        
        if (data_len != rb_len) {
                buffer->ReportOverflow(data_len - rb_len);
                dsyslog("[audiorecorder]: buffer overflow (%s, %s())", __FILE__,
                        __func__);
                buffer->Clear();
        }
}


void cAudioReceiver::Activate(bool on)
{
        if (on) {
                if (! active) {
                        active = true;
                        Start();
                }
        }
        else if (active) {
                active = false;
                Cancel(3);
        }
}


void cAudioReceiver::Action(void)
{
        abuffer input_buf;
        
        dsyslog("[audiorecorder]: receiving from channel <%s> (%s, %s())",
                channel->Name(), __FILE__, __func__);
        
        buffer = new cRingBufferLinear(KB(100), KB(5), true, NULL);
        postdata = new cPostData(channel);
        rds = new cRds(postdata);
        
        while (active) {
                input_buf.data = buffer->Get(input_buf.length);
                input_buf.offset = 0;
                
                if (! input_buf.data) {
                        usleep(10000);
                        continue;
                }
                
                
                get_mpa_frame(&input_buf, &mpa_frame, channel->Name());
                
                while (active && mpa_frame.data) {
                        set_recstat_rds();
                        
                        if (outfile.is_open())
                                outfile.write((char *)mpa_frame.data,
                                        mpa_frame.length);
                        
                        input_buf.offset += mpa_frame.length;
                        get_mpa_frame(&input_buf, &mpa_frame, channel->Name());
                }
                
                buffer->Del(input_buf.offset);
        }
        
        if (outfile.is_open()) {
                outfile.close();
                
                if (! postdata->get_recpath().empty())
                        remove(postdata->get_recpath().c_str());
        }
        
        
	pes_sync = false;
        device_number = -1;
        recstat = recWait;
        
        DELETE(rds);
        DELETE(postdata);
        DELETE(buffer);
	
        dsyslog("[audiorecorder]: stopped receiving from channel <%s> "
                "(%s, %s())", channel->Name(), __FILE__, __func__);
}


bool cAudioReceiver::is_attached(int attached_device_number)
{
        if (device_number < 0)
                return false;
        
        if (attached_device_number != device_number &&
	    attached_device_number != -1)
		return false;
        
        return true;
}


bool cAudioReceiver::is_recording(void)
{
        if (recstat != recStart && recstat != recRun)
                return false;
        
        return true;
}


void cAudioReceiver::set_recstat_rds(void)
{
        rds->put_data(mpa_frame.data, mpa_frame.length);
        
        while(rds->set_next_frame()) {
                recstat = rds->decode_frame();
                
                control_track();
        }
}


void cAudioReceiver::control_track(void)
{
        switch (recstat) {
        case recStart:
                if (outfile.is_open())
                        outfile.close();
                
                postdata->start_track();
                outfile.open(postdata->get_recpath().c_str());
                
                dsyslog("[audiorecorder]: started recording track (%s) on <%s> "
                        "(%s, %s())", postdata->get_recpath().c_str(),
                        channel->Name(), __FILE__, __func__);
                break;
        case recStop:
                if (outfile.is_open())
                        outfile.close();
                
                dsyslog("[audiorecorder]: stopped recording track (%s) on <%s> "
                        "(%s, %s())", postdata->get_recpath().c_str(),
                        channel->Name(), __FILE__, __func__);
                
                postdata->stop_track(mpa_frame.bit_rate, mpa_frame.sample_rate,
                        mpa_frame.channels, mpa_frame.length);
                
                if (postdata->get_path().empty())
                        remove(postdata->get_recpath().c_str());
                else
                        cPostproc::add_track(postdata);
                
                postdata->clear();
                
                break;
        default:
                break;
        }
}
