Improved gstreamer-sharp audio backend

Should be fully functional now, I still need to check the difference between stopping and closing a stream. I think close will free all resources and finalize the stream, whilst stop is supposed to set the position to 0 so that the stream can be recovered. But in this case FadeAndStop should be renamed to FadeAndClose because currently in all cases where FadeAndStop is called the stream should be closed instead of being stopped.
This commit is contained in:
Stephan Sundermann committed 2013-12-22 04:01:56 +01:00
1 parent 25cccfdeaf
commit ec0308cac2
1 file changed
+259 -48
+259 -48
View File
@@ -5,33 +5,39 @@ using System.Text;
using Gst;
using GLib;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Vocaluxe.Lib.Sound
{
public class CGstreamerSharpAudio : IPlayback
{
private Dictionary<int, Element> Streams = new Dictionary<int, Element>();
private Dictionary<int, CGstreamerSharpAudioStream> Streams = new Dictionary<int, CGstreamerSharpAudioStream>();
private static int idCount;
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);
public bool Init()
{
string path;
#if ARCH_X86
SetDllDirectory(".\\x86\\gstreamer");
path = ".\\x86\\gstreamer";
#endif
#if ARCH_X64
SetDllDirectory(".\\x64\\gstreamer");
path = ".\\x64\\gstreamer";
#endif
SetDllDirectory(path);
Application.Init();
Registry reg = Registry.Get();
reg.ScanPath(path);
return Application.IsInitialized;
}
public void SetGlobalVolume(float volume)
{
foreach (Element e in Streams.Values)
foreach (CGstreamerSharpAudioStream stream in Streams.Values)
{
e["volume"] = (double)volume;
stream.Volume = volume;
}
}
@@ -42,9 +48,9 @@ namespace Vocaluxe.Lib.Sound
public void CloseAll()
{
foreach (Element e in Streams.Values)
foreach (CGstreamerSharpAudioStream stream in Streams.Values)
{
e.SetState(State.Null);
stream.Close();
}
}
@@ -55,116 +61,321 @@ namespace Vocaluxe.Lib.Sound
public int Load(string media, bool prescan)
{
Registry reg = Registry.Get();
#if ARCH_X86
reg.ScanPath(".\\x86\\gstreamer");
#endif
#if ARCH_X64
reg.ScanPath(".\\x64\\gstreamer");
#endif
Element element = ElementFactory.Make("playbin", "playbin");
element["audio-sink"] = ElementFactory.Make("directsoundsink", "audiosink");
element["uri"] = new Uri(media).AbsoluteUri;
element.SetState(State.Paused);
Streams[(int)element.Handle.ToInt64()] = element;
if (prescan)
element.Bus.TimedPopFiltered(0xffffffffffffffff, MessageType.AsyncDone);
return (int)element.Handle.ToInt64();
var stream = new CGstreamerSharpAudioStream (media, prescan);
Streams[idCount] = stream;
return idCount++;
}
public void Close(int stream)
{
Streams[stream].SetState(State.Null);
Streams.Remove(stream);
if (stream < 0)
return;
Streams[stream].Close();
}
public void Play(int stream)
{
Streams[stream].SetState(State.Playing);
if (stream < 0)
return;
Streams[stream].Playing = true;
}
public void Play(int stream, bool loop)
{
if (stream < 0)
return;
Play(stream);
}
public void Pause(int stream)
{
Streams[stream].SetState(State.Playing);
if (stream < 0)
return;
Streams[stream].Paused = true;
}
public void Stop(int stream)
{
Streams[stream].SetState(State.Null);
if (stream < 0)
return;
Streams[stream].Stop();
}
public void Fade(int stream, float targetVolume, float seconds)
{
SetStreamVolume(stream, targetVolume);
if (stream < 0)
return;
Streams[stream].Fade(targetVolume, seconds);
}
public void FadeAndPause(int stream, float targetVolume, float seconds)
{
SetStreamVolume(stream, targetVolume);
Pause(stream);
if (stream < 0)
return;
Streams[stream].FadeAndPause(targetVolume, seconds);
}
public void FadeAndStop(int stream, float targetVolume, float seconds)
{
SetStreamVolume(stream, targetVolume);
Stop(stream);
if (stream < 0)
return;
Streams[stream].FadeAndStop(targetVolume, seconds);
}
public void SetStreamVolume(int stream, float volume)
{
Streams[stream]["volume"] = (double)volume/100d;
if (stream < 0)
return;
Streams[stream].Volume = volume;
}
public void SetStreamVolumeMax(int stream, float volume)
{
if (stream < 0)
return;
Streams[stream].MaxVolume = volume;
}
public float GetLength(int stream)
{
long duration;
Streams[stream].QueryDuration(Format.Time, out duration);
return duration > 0 ? (duration / (long)Constants.SECOND) : 100;
if (stream < 0)
return -1;
return Streams[stream].Length;
}
public float GetPosition(int stream)
{
long position;
Streams[stream].QueryPosition(Format.Time, out position);
return (position / (long)Constants.SECOND);
if (stream < 0)
return -1f;
return Streams[stream].Position;
}
public bool IsPlaying(int stream)
{
return true;
if (stream < 0)
return false;
return Streams[stream].Playing;
}
public bool IsPaused(int stream)
{
return false;
if (stream < 0)
return true;
return Streams[stream].Paused;
}
public bool IsFinished(int stream)
{
return false;
if (stream < 0)
return true;
return Streams[stream]._Finished;
}
public void SetPosition(int stream, float position)
{
Streams[stream].SeekSimple(Format.Time, SeekFlags.Accurate, (long)(position * (double)Constants.SECOND));
if (stream < 0)
return;
Streams[stream].Position = position;
}
public void Update()
{
foreach (KeyValuePair<int,CGstreamerSharpAudioStream> stream in Streams)
{
//if (stream.Value._Closed)
// Streams.Remove(stream.Key);
stream.Value.Update();
}
}
private class CGstreamerSharpAudioStream
{
private Element _Element;
private bool _Loop;
public bool _Closed;
public bool _Finished;
private bool _Fading;
private bool _StopStreamAfterFade;
private bool _PauseStreamAfterFade;
private Stopwatch _FadeTimer = new Stopwatch();
private float _FadeTime;
private float _FadeVolume;
public float _MaxVolume = 100f;
public CGstreamerSharpAudioStream(string media, bool prescan)
{
var convert = ElementFactory.Make("audioconvert", "convert");
var audiosink = ElementFactory.Make("directsoundsink", "audiosink");
var audioSinkBin = new Bin("Audiosink");
audioSinkBin.Add(convert);
audioSinkBin.Add(audiosink);
convert.Link(audiosink);
Pad pad = convert.GetStaticPad("sink");
GhostPad ghostpad = new GhostPad("sink", pad);
ghostpad.SetActive(true);
audioSinkBin.AddPad(ghostpad);
_Element = ElementFactory.Make("playbin", "playbin");
_Element["audio-sink"] = audioSinkBin;
_Element["flags"] = 1 << 1;
_Element["uri"] = new Uri(media).AbsoluteUri;
_Element.SetState(State.Paused);
if (prescan)
_Element.Bus.TimedPopFiltered(0xffffffffffffffff, MessageType.AsyncDone);
_Element.Bus.Message += OnMessage;
}
private void OnMessage(object o, MessageArgs args)
{
switch (args.Message.Type)
{
case MessageType.Eos:
if (_Loop)
Position = 0;
else
Close();
break;
}
}
public void Close()
{
_Element.SetState(State.Null);
_Closed = true;
_Finished = true;
}
public void Play(bool loop = false)
{
_Element.SetState(State.Playing);
this._Loop = loop;
}
public void Stop()
{
_Element.SetState(State.Null);
}
public void Fade(float targetVolume, float seconds)
{
_Fading = true;
_FadeTimer.Restart();
_FadeTime = seconds;
_FadeVolume = targetVolume;
}
public void FadeAndPause(float targetVolume, float seconds)
{
Fade(targetVolume, seconds);
_PauseStreamAfterFade = true;
}
public void FadeAndStop(float targetVolume, float seconds)
{
Fade(targetVolume, seconds);
_StopStreamAfterFade = true;
}
public float Volume
{
get
{
return (float)(double)_Element["volume"];
}
set
{
_Element["volume"] = (double) (value / 100d * (_MaxVolume / 100d));
System.Console.WriteLine(value);
}
}
public float MaxVolume
{
get
{
return _MaxVolume;
}
set
{
_MaxVolume = value;
Volume = Volume * (MaxVolume / 100f);
}
}
public float Length
{
get
{
long duration;
_Element.QueryDuration(Format.Time, out duration);
return duration > 0 ? (duration / (long)Constants.SECOND) : 100;
}
}
public float Position
{
get
{
long position;
_Element.QueryPosition(Format.Time, out position);
return (float)(position / (double)Constants.SECOND);
}
set
{
_Element.SeekSimple(Format.Time, SeekFlags.Accurate | SeekFlags.Flush, (long)(value * (double)Constants.SECOND));
}
}
public bool Paused
{
get
{
return _Element.CurrentState == State.Paused;
}
set
{
if (value)
_Element.SetState(State.Paused);
}
}
public bool Playing
{
get
{
return _Element.CurrentState == State.Playing;
}
set
{
if(value)
_Element.SetState(State.Playing);
}
}
public void Update()
{
if (_Fading)
{
if (_FadeTimer.ElapsedMilliseconds < _FadeTime * 1000f)
Volume = (_FadeTimer.ElapsedMilliseconds / 10f) / _FadeTime;
else
{
if (_StopStreamAfterFade)
Stop();
if (_PauseStreamAfterFade)
Paused = true;
_StopStreamAfterFade = false;
_PauseStreamAfterFade = false;
_Fading = false;
_FadeTimer.Reset();
}
}
}
}
}
}