Release 1.22.2
[platform/upstream/gstreamer.git] / subprojects / gstreamer-sharp / samples / PlaybackTutorial3.cs
1 // Authors
2 //   Copyright (C) 2014 Stephan Sundermann <stephansundermann@gmail.com>
3
4 using System;
5 using Gst;
6 using System.Runtime.InteropServices;
7
8 namespace GstreamerSharp
9 {
10         class Playback
11         {
12                 const int ChunkSize = 1024;
13                 const int SampleRate = 44100;
14
15                 static Gst.App.AppSrc AppSource;
16                 static Element Pipeline;
17
18                 static long NumSamples;   // Number of samples generated so far (for timestamp generation)
19                 static float a, b, c, d;     // For waveform generation
20
21                 static uint Sourceid;        // To control the GSource
22
23                 static GLib.MainLoop MainLoop;  // GLib's Main Loop
24
25                 // This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
26                 // The idle handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
27                 // and is removed when appsrc has enough data (enough-data signal).
28
29                 static bool PushData () {
30                         var numSamples = ChunkSize / 2; // Because each sample is 16 bits
31                         MapInfo map;
32
33                         // Create a new empty buffer
34                         var buffer = new Gst.Buffer (null, ChunkSize, AllocationParams.Zero);
35
36                         // Set its timestamp and duration
37                         buffer.Pts = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
38                         buffer.Dts = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
39                         buffer.Duration = Util.Uint64Scale ((ulong)NumSamples, (ulong)Constants.SECOND, (ulong)SampleRate);
40
41                         // Generate some psychodelic waveforms
42                         buffer.Map (out map, MapFlags.Write);
43                         c += d;
44                         d -= c / 1000f;
45                         var freq = 1100f + 1000f * d;
46                         short[] data = new short[numSamples];
47                         for (int i = 0; i < numSamples; i++) {
48                                 a += b;
49                                 b -= a / freq;
50                                 data[i] = (short)(500f * a);
51                         }
52                         // convert the short[] to a byte[] by marshalling
53                         var native = Marshal.AllocHGlobal (data.Length * sizeof(short));
54                         Marshal.Copy (data, 0, native, data.Length);
55                         byte[] bytedata = new byte[2 * data.Length];
56                         Marshal.Copy (native, bytedata, 0, data.Length * sizeof(short));
57
58                         map.Data = bytedata;
59                         buffer.Unmap (map);
60                         NumSamples += numSamples;
61
62                         // Push the buffer into the appsrc
63                         var ret = AppSource.PushBuffer (buffer);
64
65                         // Free the buffer now that we are done with it
66                         buffer.Dispose ();
67
68                         if (ret != FlowReturn.Ok) {
69                                 // We got some error, stop sending data
70                                 return false;
71                         }
72                         return true;
73                 }
74
75                 // This signal callback triggers when appsrc needs  Here, we add an idle handler
76                 // to the mainloop to start pushing data into the appsrc
77                 static void StartFeed (object sender, Gst.App.NeedDataArgs args) {
78                         if (Sourceid == 0) {
79                                 Console.WriteLine ("Start feeding");
80                                 Sourceid = GLib.Idle.Add (PushData);
81                         }
82                 }
83
84                 // This callback triggers when appsrc has enough data and we can stop sending.
85                 // We remove the idle handler from the mainloop
86                 static void StopFeed (object sender, EventArgs args) {
87                         if (Sourceid != 0) {
88                                 Console.WriteLine ("Stop feeding");
89                                 GLib.Source.Remove (Sourceid);
90                                 Sourceid = 0;
91                         }
92                 }
93
94                 // This function is called when playbin has created the appsrc element, so we have a chance to configure it.
95                 static void SourceSetup (object sender, GLib.SignalArgs args) {
96                         var info = new Gst.Audio.AudioInfo ();
97                         var source = new Gst.App.AppSrc(((Element)args.Args [0]).Handle);
98                         Console.WriteLine ("Source has been created. Configuring.");
99                         AppSource = source;
100
101                         // Configure appsrc
102                         Gst.Audio.AudioChannelPosition[] position = {};
103                         info.SetFormat (Gst.Audio.AudioFormat.S16, SampleRate, 1, position);
104                         var audioCaps = info.ToCaps ();
105                         source ["caps"] = audioCaps;
106                         source ["format"] = Format.Time;
107                         source.NeedData += StartFeed;
108                         source.EnoughData += StopFeed;
109                 }
110
111                 // This function is called when an error message is posted on the bus
112                 static void HandleError (object sender, GLib.SignalArgs args) {
113                         GLib.GException err;
114                         string debug;
115                         var msg = (Message) args.Args[0];
116
117                         // Print error details on the screen
118                         msg.ParseError (out err, out debug);
119                         Console.WriteLine ("Error received from element {0}: {1}", msg.Src.Name, err.Message);
120                         Console.WriteLine ("Debugging information: {0}", debug != null ? debug : "none");
121
122                         MainLoop.Quit ();
123                 }
124
125                 public static void Main (string[] args)
126                 {
127                         b = 1;
128                         d = 1;
129
130                         // Initialize Gstreamer
131                         Gst.Application.Init(ref args);
132
133                         // Create the playbin element
134                         Pipeline = Parse.Launch ("playbin uri=appsrc://");
135                         Pipeline.Connect ("source-setup", SourceSetup);
136
137                         // Instruct the bus to emit signals for each received message, and connect to the interesting signals
138                         var bus = Pipeline.Bus;
139                         bus.AddSignalWatch ();
140                         bus.Connect ("message::error", HandleError);
141
142                         // Start playing the pipeline
143                         Pipeline.SetState (State.Playing);
144
145                         // Create a GLib Main Loop and set it to run
146                         MainLoop = new GLib.MainLoop ();
147                         MainLoop.Run ();
148
149                         // Free resources
150                         Pipeline.SetState (State.Null);
151                 }
152         }
153 }