package LinuxIsdn::Call::Recorder;
use strict;
use warnings;
use Event;

use base qw(LinuxIsdn::Call::Audio);
use fields qw(fh lines writer);
use fields::accessor qw(lines @);

sub new {
    my ($class, $fh, $debug) = @_;
    $class = ref($class) || $class;
    my LinuxIsdn::Call::Recorder $record = $class->anew();
    $record->{debug}      = $debug || 0;
    $record->{fh}	  = $fh;
    $record->{class}	  = "recorder";
    return bless $record, $class;
}

sub out {
    my LinuxIsdn::Call::Recorder $record = shift;
    if ($record->{debug} & 0x04) {
        my $length = length($_[0]);
        print STDERR "Recorded $length bytes\n";
    }
    return if !defined($record->{fh}) || $_[0] eq "";
    # Explicitely not weakened !
    if ($record->{writer}) {
        $record->{writer}->cb([$record, 'do_out']);
        $record->{writer}->again();
    } else {
        $record->{writer} = Event->io(fd => $record->{fh},
                                      poll => "w",
                                      cb => [$record, 'do_out']);
    }
    if (@{$record->{lines}} && length($record->{lines}[-1]) < 8000) {
        $record->{lines}[-1] .= $_[0];
    } else {
        push(@{$record->{lines}}, $_[0]);
    }
}

sub out_error {
    my LinuxIsdn::Call::Recorder $record = shift;
    $record->{lines} = [];
    print STDERR join("", @_);
}

sub do_out {
    my LinuxIsdn::Call::Recorder $record = shift;
    my $rc = syswrite($record->{fh}, $record->{lines}[0]);
    unless ($rc) {
        $record->{writer}->cancel();
        $record->{writer} = undef;
        $record->{fh} = undef;
        $record->out_error(defined($rc) ? "Unexpected EOF on writing file descriptor" : "Error writing file descriptor: $!");
        return;
    }
    substr($record->{lines}[0], 0, $rc) = "";
    return if $record->{lines}[0] ne "";
    shift(@{$record->{lines}});
    return if @{$record->{lines}};
    $record->{writer}->cb(sub {});
    $record->{writer}->stop();
    return if $record->{started};
    # Ok, queue is empty and recording has ended
    $record->written();
    # $record->{writer}->cancel();
    # $record->{writer} = undef;
}

sub written {
    my LinuxIsdn::Call::Recorder $record = shift;
    return unless $record->{debug};
    print STDERR "All recorded audio written to file\n";
}

sub quiet {
    my LinuxIsdn::Call::Recorder $record = shift;
    return unless $record->{debug};
    print STDERR "Quiet, silence detected after non-silence\n";
}

sub silence {
    my LinuxIsdn::Call::Recorder $record = shift;
    return unless $record->{debug};
    print STDERR "Silence detected from the start of recording\n";
}

sub abort {
    my LinuxIsdn::Call::Recorder $record = shift;
    my LinuxIsdn::Call $call = $record->{call};
    return if !$call || !$record->{generation} || $record->{aborted};
    my $generation = shift;
    return if $generation && $generation != $record->{generation};
    $call->_abort_recording(@_);
    return $record;
}

sub DESTROY {
    my LinuxIsdn::Call::Recorder $record = shift;
    print STDERR "Cleaning up $record\n" if $record->{debug} & 0x08;
    if ($record->{writer}) {
        $record->{writer}->cancel();
        $record->{writer} = undef;
    }
}

1;

__END__

=head1 DESCRIPTION

Helper library for L<LinuxIsdn::Call|LinuxIsdn::Call>. Managing audio mode recordings.

=head1 SYNOPSIS

 use LinuxIsdn::Call::Recorder;

 $call    = LinuxIsdn::Call::Recorder->new(?$debug?);

=head1 METHODS

=over 4

=back

=head1 BUGS

None known

=head1 AUTHOR

Ton Hospel (LinuxIsdn-Call-Recorder@ton.iguana.be)

=head1 SEE ALSO

L<LinuxIsdn::Call::Transmitter>,
L<LinuxIsdn::Call>,
L<LinuxIsdn>,
L<IsdnDaemon>,
L<ITU Q.931>

=cut
