The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl
use strict;
use warnings;
use Glib qw(TRUE FALSE filename_to_unicode);
use GStreamer;

# $Id$

# Global objects are usually a bad thing. For the purpose of this
# example, we will use them, however.

my ($pipeline, $source, $parser, $decoder, $conv, $sink);

sub bus_call {
  my ($bus, $message, $loop) = @_;

  if ($message -> type & "eos") {
    print "End of stream\n";
    $loop -> quit();
  }

  elsif ($message -> type & "error") {
    warn $message -> error;
    $loop -> quit();
  }

  # remove message from the queue
  return TRUE;
}

sub new_pad {
  my ($element, $pad, $data) = @_;

  # We can now link this pad with the audio decoder.
  print "Dynamic pad created, linking parser/decoder\n";
  $pad -> link($decoder -> get_pad("sink"));
}

GStreamer -> init();
my $loop = Glib::MainLoop -> new(undef, FALSE);

# check input arguments
if ($#ARGV != 0) {
  print "Usage: $0 <Ogg/Vorbis filename>\n";
  exit -1;
}

# create elements
$pipeline = GStreamer::Pipeline -> new("audio-player");
($source, $parser, $decoder, $conv, $sink) =
  GStreamer::ElementFactory -> make(filesrc => "file-source",
                                    oggdemux => "ogg-parser",
                                    vorbisdec => "vorbis-decoder",
                                    audioconvert => "audio-converter",
                                    alsasink => "alsa-output");

# set filename property on the file source. Also add a message handler.
$source -> set(location => filename_to_unicode $ARGV[0]);
$pipeline -> get_bus() -> add_watch(\&bus_call, $loop);

# put all elements in a bin
$pipeline -> add($source, $parser, $decoder, $conv, $sink);

# link together - note that we cannot link the parser and
# decoder yet, becuse the parser uses dynamic pads. For that,
# we set a pad-added signal handler.
$source -> link($parser);
$decoder -> link($conv, $sink);
$parser -> signal_connect(pad_added => \&new_pad);

# Now set to playing and iterate.
print "Setting to PLAYING\n";
$pipeline -> set_state("playing");
print "Running\n";
$loop -> run();

# clean up nicely
print "Returned, stopping playback\n";
$pipeline -> set_state("null");