PageRenderTime 45ms CodeModel.GetById 15ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Teto/Worker/ReadBuffer.pm

http://github.com/motemen/Teto
Perl | 102 lines | 83 code | 16 blank | 3 comment | 4 complexity | 561d74a29d10949fbf3d9ccb1274724f MD5 | raw file
  1package Teto::Worker::ReadBuffer;
  2use Mouse;
  3use Coro;
  4use Teto::Coro::MarkedChannel;
  5use Data::Interleave::IcecastMetadata;
  6
  7with 'Teto::Role::Log';
  8
  9has queue => (
 10    is  => 'rw',
 11    isa => 'Teto::Queue',
 12);
 13
 14has icemeta => (
 15    is  => 'rw',
 16    default => sub { Data::Interleave::IcecastMetadata->new },
 17);
 18
 19# TODO 複数人対応のときにこれ複数に・icemeta をこれに持たせる
 20has channel => (
 21    is  => 'rw',
 22    default => sub { Teto::Coro::MarkedChannel->new },
 23);
 24
 25__PACKAGE__->meta->make_immutable;
 26
 27no Mouse;
 28
 29sub spawn {
 30    my ($class, %args) = @_;
 31    my $self = $class->new(%args);
 32    $self->work_async;
 33    return $self;
 34}
 35
 36sub work_async {
 37    my $self = shift;
 38
 39    async {
 40        $Coro::current->{desc} = 'ReadBuffer';
 41        $self->read_one_track while 1;
 42    };
 43}
 44
 45sub read_one_track {
 46    my $self = shift;
 47
 48    $self->log(debug => 'read_one_track');
 49
 50    my $track = $self->queue->wait_for_track;
 51    $self->icemeta->metadata->{title} = $track->title if $self->icemeta;
 52
 53    $self->log(debug => 'track: ' . $track->url);
 54
 55    # ここ誰かに任せるべき
 56    foreach my $t ($track, $self->queue->next_tracks) {
 57        async { $t->play };
 58    }
 59
 60    open my $fh, '<', $track->buffer_ref or do {
 61        $self->log(error => $!);
 62        return;
 63    };
 64
 65    while (1) {
 66        # この辺を Worker::PlayTrack にする?
 67        my $bytes_to_read = length($track->buffer) - tell($fh);
 68        if ($bytes_to_read < 0) {
 69            $track->log(error => q(track buffer got GC'ed));
 70            $track->done;
 71
 72            close $fh;
 73            $self->queue->dequeue;
 74
 75            return;
 76        }
 77
 78        read $fh, my ($buf), $bytes_to_read;
 79
 80        if (length $buf == 0 || $bytes_to_read == 0) {
 81            if ($track->is_done) {
 82                close $fh;
 83                $self->queue->dequeue; # FIXME ここで queue の中身かわってる場合がある
 84
 85                $self->log(debug => 'track done');
 86
 87                $self->channel->put_mark if $self->channel->can('put_mark');
 88
 89                return;
 90            }
 91
 92            $track->buffer_signal->wait;
 93        } else {
 94            $buf = $self->icemeta->interleave($buf) if $self->icemeta;
 95            # $self->log(debug => 'put ' . length($buf) . ' bytes');
 96            $self->channel->put($buf);
 97            cede;
 98        }
 99    }
100}
101
1021;