/usr/local/CPAN/Video-PlaybackMachine/Video/PlaybackMachine/TimeManager.pm
package Video::PlaybackMachine::TimeManager;
####
#### Video::PlaybackMachine::TimeManager
####
#### $Revision: 405 $
####
#### Tells us what FillSegment to play next in a particular break.
#### Keeps track of what has been played.
####
use strict;
use warnings;
use Carp;
use Log::Log4perl;
# TODO: I'm not sure that the implemented algorithm is correct. To get
# the effects I'm looking for, basically the TimeManager should go
# through in priority order and assign time slots to the Fill
# Producers based on minimum and preferred time, stopping when we're
# full. Actual playback then follows sequence order. Preassignment
# may be against some of the PM philosophy of constantly reacting to
# the current situation, but is essential for getting some of the
# effects that we want (such as "play fills before and after a short
# movie, and ALWAYS do station identification")
#
# Later update: The algorithm actually works as well, if not better,
# than the above. It gets the amount of time remaining, and the amount
# of time required, and the amount of time required by items of a
# higher priority, and computes the remainder.
#
############################# Class Constants #############################
############################## Class Methods ##############################
##
## new()
##
## Arguments:
## SEGMENTS: list -- All available fill segments
##
## We assume that segments have unique sequential sequence numbers.
##
sub new {
my $type = shift;
my (@segments) = @_;
my $self = { };
$self->{seq_order} = [ sort { $a->get_sequence() <=> $b->get_sequence() } @segments ];
$self->{current_seq} = 0;
$self->{'logger'} = Log::Log4perl->get_logger('Video::PlaybackMachine::Filler::TimeManager');
bless $self, $type;
}
############################# Object Methods ##############################
##
## get_segment()
##
## Arguments:
## TIME_LEFT: int -- Amount of time before next scheduled content
##
## Returns: (list)
## FillSegment -- Next FillSegment to use
## int -- unreserved time remaining in seconds
##
## Returns the FillSegment to use to fill up time right now. Returns
## undef if no more fill can be played.
##
# TODO: Can be simplified to a rotating index. We never play out of
# sequence.
sub get_segment {
my $self = shift;
my ($time_left) = @_;
# For each segment starting from current in display order
foreach my $segment ( $self->_segments_left() ) {
$self->{'logger'}->debug("Considering segment ", $segment->get_name());
# Move to next segment if we don't have time to play it
my $time_remaining = $self->_seconds_remaining($segment, $time_left);
$segment->is_available($time_remaining) or do {
$self->{'logger'}->debug("Skipping segment ", $segment->get_name());
next;
};
# Update whatever we should play next
$self->{current_seq} = ($self->{current_seq} + 1) % ($#{ $self->{seq_order} } + 1);
# Return the segment and time remaining
return ($segment, $time_remaining);
} # End for each unfinished segment
# All's finished or no time; return undef
return;
}
##
## Returns the segments still to play, in sequence order.
##
sub _segments_left {
my $self = shift;
return @{$self->{seq_order}}[ $self->{current_seq} ... $#{ $self->{seq_order} } ];
}
##
## _seconds_remaining()
##
## Arguments:
## CURRENT_SEGMENT: FillSegment
## TIME_LEFT: int -- seconds
##
## Returns the amount of time in seconds remaining after
## time has been reserved for all of the segments with
## higher priorities than this.
##
# TODO Slideshow expects the time remaining to be the expected preferred time
sub _seconds_remaining {
my $self = shift;
my ($current_segment, $time_left_in_break) = @_;
my $time_remaining = $time_left_in_break;
foreach my $segment (
sort {$a->get_priority() <=> $b->get_priority()}
grep { $_->get_priority() < $current_segment->get_priority() }
$self->_segments_left()
)
{
$time_remaining > 0 or return 0;
$segment->is_available($time_remaining) or next;
$time_remaining -= $segment->get_producer()->get_time_layout()->preferred_time($time_remaining);
}
return $time_remaining;
}
1;