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