/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

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