// -*- tab-width: 4 -*- /* valac --pkg gtk+-2.0 --pkg gio-2.0 --pkg gstreamer-0.10 --pkg unique-1.0 sccplayer.vala sccplayer http://yp.shoutcast.com/sbin/tunein-station.pls?id=6687 */ using Gtk; using Gst; using Unique; public class SccPlayer : Gtk.Object { enum Command { COMMAND_0, COMMAND_PLAYURI } private Gtk.Window main_window; private Gtk.Label channel_label; private Gtk.Label track_label; private Gtk.Statusbar status_bar; public dynamic Gst.Element play_src; private const string uistring = """ 320 SccPlayer media-playback-start True vertical True 6 vertical True 0 label True True end 0 True 0 label True True end 1 0 True 2 False 1 """; [CCode (instance_pos = -1)] public void /******************************************************************************/ on_main_window_destroy () { play_src.set_state (State.PAUSED); play_src.set_state (State.NULL); Gtk.main_quit(); } static bool /******************************************************************************/ command_line_ok (string[] args) { if (args.length <= 1) { stdout.printf ("Usage: %s \n", args[0]); return false; } return true; } static void /******************************************************************************/ handle_fail_or_user_cancel () { stdout.printf ("TODO: handle libunique cancel/fail...\n"); } public bool /******************************************************************************/ do_command_playuri (Unique.MessageData message) { status_bar.push (1, "Waiting..."); this.play (message.get_text()); return true; } public Unique.Response /******************************************************************************/ message_received_cb ( int command, Unique.MessageData message, uint time){ Unique.Response res; switch (command) { case Unique.Command.ACTIVATE: res = Unique.Response.OK; break; case Command.COMMAND_PLAYURI: if (do_command_playuri (message)) res = Unique.Response.OK; else res = Unique.Response.FAIL; break; default: res = Unique.Response.OK; break; } return res; } public void /******************************************************************************/ foreach_tag (Gst.TagList list, string tag) { string tag_string; switch (tag) { case "title": list.get_string (tag, out tag_string); main_window.title = tag_string.strip(); tag_string = tag_string.replace ("&", "&"); track_label.label = "" + tag_string.strip() + ""; while (events_pending()) main_iteration(); break; default: break; } } public bool /******************************************************************************/ bus_callback (Gst.Bus bus, Gst.Message message) { GLib.Error err; string debug; Gst.State oldstate; Gst.State newstate; Gst.State pendstate; Gst.TagList tag_list; switch (message.type) { case Gst.MessageType.ERROR: play_src.set_state (State.NULL); message.parse_error (out err, out debug); stdout.printf ("Error: %s\n", err.message); break; case Gst.MessageType.EOS: stdout.printf ("eos\n"); break; case Gst.MessageType.STATE_CHANGED: string blah; message.parse_state_changed (out oldstate, out newstate, out pendstate); if (newstate == Gst.State.PLAYING) { blah = "Playing..."; } else if (oldstate == Gst.State.READY && newstate == Gst.State.NULL && pendstate == Gst.State.VOID_PENDING) { blah = "Buffering..."; } else if (newstate == Gst.State.READY) { blah = "Waiting..."; } else if (newstate == Gst.State.PAUSED) { blah = "Paused..."; } else { blah = "%s > %s | %s".printf ( oldstate.to_string(), newstate.to_string() ,pendstate.to_string()); } status_bar.push (1, blah); break; case Gst.MessageType.TAG: message.parse_tag (out tag_list); tag_list.foreach (foreach_tag); break; default: break; } return true; } public string /******************************************************************************/ get_channel (string playlist_uri) { //TODO: should we do "balancing" or at least check if stream full ? var file = File.new_for_commandline_arg (playlist_uri); string outval = ""; try { var in_stream = new DataInputStream (file.read (null)); string line; string[] keyval; while ((line = in_stream.read_line (null, null)) != null) { keyval = line.split ("=", 2); if (keyval[0] == "Title1") { string[] tt = keyval[1].split (")", 2); tt[1] = tt[1].replace ("&", "&"); channel_label.label = tt[1].strip(); while (events_pending()) main_iteration(); } if (keyval[0] == "File1") { outval = keyval[1]; } } } catch (IOError e) { error ("%s", e.message); } return outval; } public void /******************************************************************************/ play (string playlist_uri) { main_window.set_title ("::Waiting for Title::"); channel_label.set_markup ("::Fetching Channel Name::"); track_label.set_markup ("::Waiting for Title::"); play_src.set_state (State.PAUSED); play_src.set_state (State.NULL); while (events_pending()) main_iteration(); string foo = get_channel (playlist_uri); play_src.uri = foo; play_src.set_state (State.PLAYING); } public /******************************************************************************/ SccPlayer () { try { var builder = new Builder (); // builder.add_from_file ("sccplayer.ui"); builder.add_from_string (uistring, uistring.len()); builder.connect_signals (null); main_window = builder.get_object ("main_window") as Gtk.Window; channel_label = builder.get_object ("channel_label") as Gtk.Label; track_label = builder.get_object ("track_label") as Gtk.Label; status_bar = builder.get_object ("status_bar") as Gtk.Statusbar; main_window.show_all (); } catch (Error e) { stderr.printf ("Could not load UI: %s\n", e.message); } Bus bus; play_src = ElementFactory.make ("playbin", "play_src"); bus = play_src.get_bus (); bus.add_watch (bus_callback); play_src.set_state (State.NULL); } public static int /******************************************************************************/ main (string[] args) { if (!command_line_ok (args)) return 1; Unique.App app; Gtk.init (ref args); Gst.init (ref args); app = new Unique.App.with_commands ( "de.osku.sccplayer", null, "playuri", Command.COMMAND_PLAYURI, null); if (app.is_running) { Unique.Command command; Unique.Response response; Unique.MessageData message; message = new MessageData (); command = (Unique.Command) Command.COMMAND_PLAYURI; message.set_text (args[1], args[1].len()); response = app.send_message (command, message); if (response == Unique.Response.OK) return 0; else handle_fail_or_user_cancel (); } else { var player = new SccPlayer (); player.play (args[1]); app.watch_window (player.main_window); app.message_received += player.message_received_cb; Gtk.main (); } return 0; } } // class // vim:tabstop=4: