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