--- /dev/null
+/* Demo Recorder for MAEMO 5
+* Copyright (C) 2010 Dru Moore <usr@dru-id.co.uk>
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2,
+* or (at your option) any later version, as published by the Free
+* Software Foundation
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details
+*
+* You should have received a copy of the GNU General Public
+* License along with this program; if not, write to the
+* Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+namespace IdWorks {
+
+public class TrackPipeline : GLib.Object {
+
+ Gst.Bin bin;
+ Gst.Element src;
+ Gst.Element decoder;
+ Gst.Element converter;
+ Gst.Element equalizer;
+ Gst.Element panorama;
+ Gst.Element volume;
+ Gst.Element sink;
+ string track_title;
+ Gst.Query duration_query;
+ Gst.Query position_query;
+ int64 position;
+ int64 duration;
+
+ public void set_sink(Gst.Element sink) {
+ this.sink = sink;
+ }
+
+ public void link_track(Gst.Element adder) {
+ volume.link(adder);
+ }
+
+ //define a delegate function to handle tags
+ private static Gst.TagForeachFunc handle_tags_delegate;
+
+ public signal void position_duration(int64 position, int64 duration);
+ public signal void tag_parsed(string tag, string val);
+ public signal void end_of_stream();
+ public signal void stream_error(string msg);
+
+ public TrackPipeline(string name) {
+ //set the tag handling delegate
+ this.handle_tags_delegate = this.handle_tags;
+ //set some default values
+ this.position=0;
+ this.duration=0;
+ this.construct_bin(name);
+ //define the queries
+ duration_query = new Gst.Query.duration(Gst.Format.TIME);
+ position_query = new Gst.Query.position(Gst.Format.TIME);
+ }
+
+ private void construct_bin(string name) {
+ bin = new Gst.Bin(name);
+ src = Gst.ElementFactory.make("fakesrc", "source");
+ bin.add(src);
+ decoder = Gst.ElementFactory.make("decodebin", "decoder");
+ decoder.connect ("swapped-object-signal::new-decoded-pad", new_decoded_pad, this);
+ bin.add(decoder);
+ converter = Gst.ElementFactory.make("audioconvert", "converter");
+ bin.add(converter);
+ panorama = Gst.ElementFactory.make("audiopanorama", "panorama");
+ bin.add(panorama);
+ //echo = ElementFactory.make("audioecho", "echo");
+ //echo.set_property("delay", 500000000);
+ //echo.set_property("feedback", 0.4);
+ //echo.set_property("intensity", 0.5);
+ //echo.set_property("max-delay", 500000000);
+ //pipeline.add(echo);
+ //converter2 = ElementFactory.make("audioconvert", "converter2");
+ //pipeline.add(converter2);
+ equalizer = Gst.ElementFactory.make("equalizer-10bands", "eq");
+ bin.add(equalizer);
+ volume = Gst.ElementFactory.make("volume", "vol");
+ bin.add(volume);
+ sink = Gst.ElementFactory.make("autoaudiosink", "audio-output");
+ /* TODO How does bin handle this */ //pipeline.add(sink);
+ converter.link(equalizer);
+ equalizer.link(panorama);
+ panorama.link(volume);
+ /* TODO How does bin handle this */ //volume.link(sink);
+ //we need to receive signals from the pipelines bus
+ Gst.Bus bus = this.bin.get_bus( );
+ //make sure we are watching the signals on the bus
+ bus.add_signal_watch();
+ //what do we do when a tag is part of the bus signal?
+ bus.message.connect(
+ (bus,message)=> {
+ this.bus_message(message);
+ }
+ );
+ }
+
+
+ public void foreach_tag (Gst.TagList list, string tag) {
+ stdout.printf("foreach_tag called\n");
+ stdout.flush();
+ switch (tag) {
+ case "title":
+ list.get_string (tag, out track_title);
+ stdout.printf ("%s\n", track_title);
+ stdout.flush();
+ //info_label.set_markup("<b>" + track_title + "</b><br>" + track_uri);
+ break;
+ default:
+ break;
+ }
+ }
+
+ public void handle_tags(Gst.TagList list, string tag) {
+ if (tag != null) {
+ switch (tag) {
+ case "artist":
+ case "title":
+ case "album":
+ case "channel-mode":
+ case "comment":
+ case "audio-codec":
+ string val="Unknown";
+ list.get_string(tag,out val);
+ tag_parsed(tag, val);
+ break;
+ case "track-number":
+ case "bitrate":
+ uint val;
+ list.get_uint(tag,out val);
+ //tag_parsed(tag,(string)val);
+ break;
+ default:
+ //stdout.printf("%s\n",tag);
+ //stdout.flush();
+ break;
+ }
+ }
+ }
+
+
+ public void bus_message(Gst.Message message) {
+ Gst.TagList tag_list;
+ switch(message.type) {
+ case Gst.MessageType.ERROR:
+ GLib.Error err;
+ string debug;
+ message.parse_error (out err, out debug);
+ stream_error(err.message);
+ break;
+ case Gst.MessageType.TAG:
+ message.parse_tag(out tag_list);
+ //we need to get the key and value from the tag
+ tag_list.foreach( this.handle_tags_delegate );
+ break;
+ case Gst.MessageType.STATE_CHANGED:
+ //stdout.printf("state changed\n");
+ Gst.State oldstate;
+ Gst.State newstate;
+ Gst.State pending;
+ message.parse_state_changed (out oldstate, out newstate, out pending);
+ //stdout.printf ("%s->%s:%s\n", oldstate.to_string(), newstate.to_string(), pending.to_string());
+ //stdout.flush();
+ break;
+ case Gst.MessageType.EOS:
+ end_of_stream();
+ break;
+ default:
+ break;
+ }
+ }
+
+ public bool bus_callback (Gst.Bus bus, Gst.Message message) {
+ stdout.printf("state changed\n");
+ stdout.flush();
+ switch (message.type) {
+ case Gst.MessageType.ERROR:
+ GLib.Error err;
+ string debug;
+ message.parse_error (out err, out debug);
+ stdout.printf("%s\n", err.message);
+ stdout.flush();
+ break;
+ case Gst.MessageType.EOS:
+ stdout.printf ("end of stream\n");
+ stdout.flush();
+ break;
+ case Gst.MessageType.STATE_CHANGED:
+ Gst.State oldstate;
+ Gst.State newstate;
+ Gst.State pending;
+ message.parse_state_changed (out oldstate, out newstate, out pending);
+ stdout.printf ("%s->%s:%s\n", oldstate.to_string(), newstate.to_string(), pending.to_string());
+ stdout.flush();
+ break;
+ case Gst.MessageType.TAG:
+ Gst.TagList tag_list;
+ message.parse_tag (out tag_list);
+ tag_list.foreach (foreach_tag);
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ public void get_duration_info() {
+ bool duration_result,position_result;
+ Gst.Format format = Gst.Format.TIME;
+ duration_result = this.bin.query(this.duration_query);
+ position_result = this.bin.query(this.position_query);
+ if ( duration_result && position_result ) {
+ this.duration_query.parse_duration(out format, out this.duration);
+ this.position_query.parse_position(out format, out this.position);
+ this.position_duration(this.position,this.duration);
+ }
+ }
+
+ public void play() {
+ bin.set_state(Gst.State.PLAYING);
+ }
+
+ public void pause() {
+ bin.set_state(Gst.State.PAUSED);
+ }
+
+ public void stop() {
+ bin.set_state(Gst.State.READY);
+ }
+
+ public void move_to(int64 newloc) {
+ if (0 > newloc) newloc = 0;
+ this.converter.seek_simple(Gst.Format.TIME, Gst.SeekFlags.KEY_UNIT | Gst.SeekFlags.FLUSH, newloc);
+ this.play();
+ }
+
+ public void seek(int percent) {
+ move_to((int64) this.position + (this.duration * percent / 100));
+ }
+
+ public void seek_forward(int percent) {
+ seek(percent);
+ }
+
+ public void seek_backward(int percent) {
+ seek(-percent);
+ }
+
+ public void set_uri(string uri) {
+ this.bin.set_state(Gst.State.NULL);
+ try {
+ //is there a src pipeline?
+ this.bin.remove(this.src);
+ } finally {
+ //do nothing, the src doesn't exist
+ }
+ this.src = Gst.Element.make_from_uri(Gst.URIType.SRC, uri, "my_src");
+ Gst.Bus bus = this.src.get_bus();
+ bus.add_watch (bus_callback);
+ this.bin.add(this.src);
+ this.src.link(this.decoder);
+ }
+
+ public void set_volume(double val)
+ requires (val >= 0.0 && val <= 10.0) {
+ volume.set_property("volume",val);
+ }
+
+ public double get_volume() {
+ GLib.Value ret = 0.0;
+ volume.get_property("volume", ref ret);
+ return ret.get_double();
+ }
+
+ public void set_panorama(double val)
+ requires (val >= -1.0 && val <= 1.0) {
+ panorama.set_property("panorama", val);
+ }
+
+ public double get_panorama() {
+ GLib.Value ret = 0.0;
+ panorama.get_property("panorama", ref ret);
+ return ret.get_double();
+ }
+
+ public void set_eq(int band, double val)
+ requires (band > -1 && band < 10)
+ requires (val >= -24 && val <= 12) {
+ equalizer.set_property("band" + band.to_string(), val);
+ }
+
+ public double get_eq(int band) {
+ GLib.Value ret = 0.0;
+ equalizer.get_property("band" + band.to_string(), ref ret);
+ return ret.get_double();
+ }
+
+ public bool new_decoded_pad(Gst.Pad decodebin, bool arg1, void* data) {
+ //link the pad to the audioconverter
+ decodebin.link( converter.get_static_pad("sink") );
+ return true;
+ }
+
+}
+
+}