1 /*
2  * gstreamer_helloworld is placed in the
3  * public domain.
4  */
5 
6 module gstreamer_helloworld;
7 
8 
9 //Phobos imports:
10 //import std.stdio;
11 
12 //Tango imports
13 import tango.util.log.Trace;//Thread safe console output.
14 import Util = tango.text.Util;
15 import Integer = tango.text.convert.Integer;
16 import Stringz = tango.stdc.stringz;
17 
18 
19 //gtkD imports:
20 
21 import gtk.Main;
22 
23 //gstreamerD imports:
24 
25 import gstreamer.gstreamer;
26 
27 import gobject.ObjectG;
28 import glib.ErrorG;
29 import gstreamer.Element;
30 import gstreamer.Pipeline;
31 import gstreamer.ElementFactory;
32 import gstreamer.Pad;
33 import gstreamer.Message;
34 import gstreamer.Bus;
35 
36 import gstreamerc.gstreamertypes;
37 import gstreamerc.gstreamer;
38 
39 import gtkc.glib;
40 
41 
42 class GstHello
43 {
44 public:
45 
46 	bool busCall( Message msg )
47 	{
48 		debug(gstreamer) Trace.formatln("GstHello.busCall(msg) START.");
49 		debug(gstreamer) scope(exit) Trace.formatln("GstHello.busCall(msg) END.");
50 
51 		switch( msg.type )
52 		{
53 			case GstMessageType.UNKNOWN:
54 				Trace.formatln("Unknown message type.");
55 			break;
56 			case GstMessageType.EOS:
57 				Trace.formatln("End-of-stream.");
58 				Main.quit();
59 			break;
60 
61 			case GstMessageType.ERROR:
62 			{
63 				string dbug;
64 				ErrorG err;
65 				msg.parseError(err, dbug);
66 				//g_free (dbug);
67 				Trace.formatln("Error: {} dbug: {}", Stringz.fromStringz(err.getErrorGStruct().message), dbug );
68 				Main.quit();
69 			break;
70 			}
71 			default:
72 			break;
73 		}
74 
75 		return true;
76 	}
77 
78 	this(char[] file)
79 	{
80 
81 		// create elements
82 		
83 		pipeline = new Pipeline("audio-player");
84 
85 		source = ElementFactory.make("filesrc", "file-source");
86 		parser = ElementFactory.make("oggdemux", "ogg-parser");
87 		decoder = ElementFactory.make("vorbisdec", "vorbis-decoder");
88 		conv = ElementFactory.make("audioconvert", "converter");
89 		sink = ElementFactory.make("alsasink", "alsa-output");
90 
91 		if( pipeline is null || source is null || parser is null || decoder is null || conv is null || sink is null )
92 		{
93 			Trace.formatln("One or more element could not be created");
94 			if( pipeline is null ) Trace.formatln(" : no pipeline.");
95 			if( source is null ) Trace.formatln(" : no source.");
96 			if( parser is null ) Trace.formatln(" : no parser.");
97 			if( decoder is null ) Trace.formatln(" : no decoder.");
98 			if( conv is null ) Trace.formatln(" : no conv.");
99 			if( sink is null ) Trace.formatln(" : no sink.");
100 
101 			throw new Exception("One or more gstreamerD elements could not be created.");
102 		}
103 		
104 		// set filename property on the file source. Also add a message handler.
105 
106 		source.location( file ); //You can also use this like a D property: source.location = file;
107 		//Or you can also do: source.setProperty("location", file);
108 
109 		pipeline.getBus().addWatch( &busCall );
110 
111 		// put all elements in a bin
112 
113 		//shouldbe, but doesn't work yet:
114 		//pipeline.addMany( source, parser, decoder, conv, sink );
115 		//TODO, add variable number of arguments (...) support to GtkWrapper
116 		pipeline.add( source );
117 		pipeline.add( parser );
118 		pipeline.add( decoder );
119 		pipeline.add( conv );
120 		pipeline.add( sink );
121 
122 		// link together - note that we cannot link the parser and
123 		// decoder yet, because the parser uses dynamic pads. For that,
124 		// we set a pad-added signal handler.
125 		source.link( parser );
126 
127 		//shouldbe, but doesn't work yet:
128 		//decoder.linkMany( conv, sink );
129 		decoder.link( conv );
130 		conv.link( sink );
131 		//Here's where we set the pad-added signal handler. It will
132 		//connect the dynamic pads when they become available.
133 		parser.addOnPadAdded(&newPad);
134 
135 		// Now set to playing and iterate.
136 		Trace.formatln("Setting to PLAYING.");
137 		pipeline.setState( GstState.PLAYING );
138 		Trace.formatln("Running.");
139 	}
140 
141 	~this()
142 	{
143 		pipeline.setState( GstState.NULL );
144 	}
145 
146 	void newPad( Pad pad, Element element )
147 	{
148 		Trace.formatln("newPad callback called. START.");
149 		Pad sinkpad;
150 
151 		// We can now link this pad with the audio decoder
152 		Trace.formatln("Dynamic pad created, linking parser/decoder");
153 
154 		sinkpad = decoder.getPad("sink");
155 		Trace.formatln("doing a gst_pad_link.");
156 		pad.link( sinkpad );
157 		Trace.formatln("Done. That was ok.");
158 
159 	}
160 
161 protected:
162 
163 	Pipeline pipeline;
164 	Element source, parser, decoder, conv, sink;
165 }
166 
167 
168 int main(char[][] args)
169 {
170 	Trace.formatln("gstreamerD Hello World!");
171 
172 	uint major, minor, micro, nano;
173 
174 	Trace.formatln("Trying to init...");
175 
176 	//Main.init(args);
177 	GStreamer.init(args);
178 
179 	// check input arguments
180 	if (args.length != 2)
181 	{
182 		Trace.formatln("Usage: {} <Ogg/Vorbis filename>", args[0]);
183 		return -1;
184 	}
185 
186 	Trace.formatln("Checking version of GStreamer...");
187 	GStreamer.versio(major, minor, micro, nano);
188 	Trace.formatln("The installed version of GStreamer is {}.{}.{}", major, minor, micro );
189 
190 	Trace.formatln( "The file is: {}", args[1] );
191 	GstHello gstHello = new GstHello( args[1] );
192 
193 	//We must use the gtkD mainloop to run gstreamerD apps.
194 	Main.run();
195 
196 	return 0;
197 }
198 
199