From 052e32aa6c6ab8b10edd661196d7fadfece48308 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Sat, 15 Mar 2014 14:25:00 +0100 Subject: [PATCH] Unify CRecordDevice handling --- .../GstreamerSharp/CGstreamerSharpAudio.cs | 284 ---------- .../Lib/Sound/Playback/OpenAL/COpenALPlay.cs | 499 ------------------ .../Record/DirectSound/CDirectSoundRecord.cs | 5 +- Vocaluxe/Lib/Sound/Record/IRecord.cs | 20 +- .../Record/PortAudio/CPortAudioRecord.cs | 5 +- 5 files changed, 18 insertions(+), 795 deletions(-) diff --git a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs index 8696bdc2..8125038f 100644 --- a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs +++ b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudio.cs @@ -15,13 +15,9 @@ // along with Vocaluxe. If not, see . #endregion -using System; using System.Collections.Generic; using Gst; -using GLib; using System.Runtime.InteropServices; -using Vocaluxe.Base; -using VocaluxeLib; namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp { @@ -209,285 +205,5 @@ namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp foreach (int key in streamsToDelete) _Streams.Remove(key); } - - private class CGstreamerSharpAudioStream - { - private Element _Element; - private bool _Loop; - public volatile bool Closed = true; - public volatile bool Finished; - - private CFading _Fading; - private EStreamAction _AfterFadeAction; - private float _Volume = 1f; - - private float _MaxVolume = 1f; - - private volatile float _Duration = -1f; - private volatile float _Position; - private volatile bool _QueryingDuration; - - public CGstreamerSharpAudioStream(string media, bool prescan) - { - Element convert = ElementFactory.Make("audioconvert", "convert"); - Element audiosink = ElementFactory.Make("directsoundsink", "audiosink"); - var audioSinkBin = new Bin("Audiosink"); - - if (convert == null || audiosink == null) - { - CLog.LogError("Could not create pipeline"); - return; - } - - audioSinkBin.Add(convert); - audioSinkBin.Add(audiosink); - convert.Link(audiosink); - Pad pad = convert.GetStaticPad("sink"); - GhostPad ghostpad = new GhostPad("sink", pad); - - if (pad == null) - { - CLog.LogError("Could not create pads"); - return; - } - - if (!ghostpad.SetActive(true)) - { - CLog.LogError("Could not link pads"); - return; - } - if (!audioSinkBin.AddPad(ghostpad)) - { - CLog.LogError("Could not add pad"); - return; - } - - _Element = ElementFactory.Make("playbin", "playbin"); - if (_Element == null) - { - CLog.LogError("Could not create playbin"); - return; - } - _Element["audio-sink"] = audioSinkBin; - _Element["flags"] = 1 << 1; - _Element["uri"] = new Uri(media).AbsoluteUri; - _Element.SetState(State.Paused); - - Closed = false; //Enable stream - - // Passing CLOCK_TIME_NONE here causes the pipeline to block for a long time so with - // prescan enabled the pipeline will wait 500ms for stream to initialize and then continue - // if it takes more than 500ms, duration queries will be performed asynchronously - if (prescan) - { - Message msg = _Element.Bus.TimedPopFiltered(0xffffffffffffffff, MessageType.AsyncDone); - if (msg.Handle != IntPtr.Zero) - _UpdateDuration(); - } - } - - private void _OnMessage(Message msg) - { - if (msg.Handle == IntPtr.Zero) - return; - switch (msg.Type) - { - case MessageType.Eos: - if (_Loop) - Position = 0; - else - { - Finished = true; - Close(); - } - break; - case MessageType.Error: - GException error; - string debug; - msg.ParseError(out error, out debug); - CLog.LogError("Gstreamer error: message" + error.Message + ", code" + error.Code + " ,debug information" + debug); - break; - case MessageType.DurationChanged: - if (!_QueryingDuration) - _UpdateDuration(); - break; - } - msg.Unref(); - } - - public void Close() - { - if (!Closed) - { - Closed = true; - Finished = true; - var t = new System.Threading.Thread(_TerminateStream) {Name = "GSt Terminate"}; - t.Start(); - } - } - - private void _TerminateStream() - { - if (_Element != null) - { - _Element.SetState(State.Null); - _Element.Dispose(); - _Element = null; - } - } - - public void Play(bool loop = false) - { - if (_Element != null) - _Element.SetState(State.Playing); - _Loop = loop; - } - - public void Stop() - { - if (_Element != null) - _Element.SetState(State.Ready); - Position = 0; - } - - public void Fade(float targetVolume, float seconds) - { - _Fading = new CFading(_Volume, targetVolume, seconds); - _AfterFadeAction = EStreamAction.Nothing; - } - - public void FadeAndPause(float targetVolume, float seconds) - { - Fade(targetVolume, seconds); - _AfterFadeAction = EStreamAction.Pause; - } - - public void FadeAndClose(float targetVolume, float seconds) - { - Fade(targetVolume, seconds); - _AfterFadeAction = EStreamAction.Close; - } - - public void FadeAndStop(float targetVolume, float seconds) - { - Fade(targetVolume, seconds); - _AfterFadeAction = EStreamAction.Stop; - } - - public float Volume - { - get { return _Volume * 100f; } - set - { - _Volume = value / 100f; - if (_Element != null) - _Element["volume"] = (_Volume * _MaxVolume); - } - } - - public float MaxVolume - { - get { return _MaxVolume * 100f; } - set - { - _MaxVolume = value / 100f; - Volume = _Volume; - } - } - - public float Length - { - get - { - if (_Duration < 0 && !_QueryingDuration) - { - _QueryingDuration = true; // Set this to avoid race conditions - var t = new System.Threading.Thread(_UpdateDuration) {Name = "GSt Update Duration"}; - t.Start(); - } - return _Duration > 0 ? _Duration : -1; - } - } - - public float Position - { - get - { - long position; - if (!_Element.QueryPosition(Format.Time, out position)) - CLog.LogError("Could not query position"); - else - _Position = (float)(position / (double)Constants.SECOND); - return _Position; - } - set - { - if (_Element != null) - _Element.SeekSimple(Format.Time, SeekFlags.Accurate | SeekFlags.Flush, (long)(value * (double)Constants.SECOND)); - } - } - - public bool Paused - { - get { return _Element == null || _Element.TargetState == State.Paused; } - set - { - if (value && _Element != null) - _Element.SetState(State.Paused); - } - } - - public bool Playing - { - get { return _Element != null && (_Element.TargetState == State.Playing && !Finished); } - set - { - if (value && _Element != null) - _Element.SetState(State.Playing); - } - } - - public void Update() - { - while (_Element != null && _Element.Bus != null && _Element.Bus.HavePending()) - _OnMessage(_Element.Bus.Pop()); - - if (_Fading != null) - { - bool finished; - Volume = _Fading.GetValue(out finished); - if (finished) - { - switch (_AfterFadeAction) - { - case EStreamAction.Pause: - Paused = true; - break; - case EStreamAction.Stop: - Stop(); - break; - case EStreamAction.Close: - Close(); - break; - } - _Fading = null; - } - } - } - - private void _UpdateDuration() - { - _QueryingDuration = true; - long duration = -1; - while (duration < 0 && !Closed && !Finished && _Element != null) - { - if (_Element.QueryDuration(Format.Time, out duration)) - { - _Duration = duration / (float)Constants.SECOND; - _QueryingDuration = false; - } - } - } - } } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs index 5e9850e6..ac7b533b 100644 --- a/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs +++ b/Vocaluxe/Lib/Sound/Playback/OpenAL/COpenALPlay.cs @@ -19,12 +19,6 @@ using System.Linq; using OpenTK.Audio; using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Threading; -using Vocaluxe.Base; -using Vocaluxe.Lib.Sound.Playback.Decoder; -using VocaluxeLib; namespace Vocaluxe.Lib.Sound.Playback.OpenAL { @@ -352,497 +346,4 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL throw new NotImplementedException(); } } - - class COpenAlStream : IDisposable - { - private const int _BufferSize = 2048; - private const int _BufferCount = 5; - private const long _Bufsize = 50000L; - - private Object _CloseMutex; - - private int[] _Buffers; - private int _State; - private int _Source; - private SFormatInfo _Format; - - private bool _Initialized; - private int _ByteCount = 4; - private float _Volume = 1f; - private float _VolumeMax = 1f; - - private EStreamAction _AfterFadeAction; - private CFading _Fading; - - private readonly Stopwatch _Timer = new Stopwatch(); - - private Closeproc _Closeproc; - private int _StreamID; - private IAudioDecoder _Decoder; - private float _BytesPerSecond; - private bool _NoMoreData; - - private bool _FileOpened; - - private bool _Waiting; - private bool _Skip; - - private bool _Loop; - private float _Duration; - private float _CurrentTime; - private float _TimeCode; - - private bool _Paused; - - private CRingBuffer _Data; - private float _SetStart; - private float _Start; - private bool _SetLoop; - private bool _SetSkip; - private bool _Terminated; - - private readonly Thread _DecoderThread; - - private AutoResetEvent _EventDecode = new AutoResetEvent(false); - - private readonly Object _MutexData = new Object(); - private readonly Object _MutexSyncSignals = new Object(); - - public COpenAlStream() - { - _Initialized = false; - _DecoderThread = new Thread(_Execute) {Name = "OpenAL Decode"}; - } - - public void Free(Closeproc closeProc, int streamID, Object closeMutex) - { - _Closeproc = closeProc; - _StreamID = streamID; - _Terminated = true; - _CloseMutex = closeMutex; - } - - public float Length - { - get - { - if (_FileOpened) - return _Duration; - - return 0f; - } - } - - public bool Finished - { - get - { - lock (_MutexData) - { - return _NoMoreData && _Data.BytesNotRead == 0L; - } - } - } - - public float Volume - { - get { return _Volume * 100f; } - set - { - lock (_MutexData) - { - _Volume = value / 100f; - if (_Volume < 0f) - _Volume = 0f; - - if (_Volume > 1f) - _Volume = 1f; - } - } - } - - public float VolumeMax - { - get { return _VolumeMax * 100f; } - set - { - lock (_MutexData) - { - _VolumeMax = value / 100f; - if (_VolumeMax < 0f) - _VolumeMax = 0f; - - if (_VolumeMax > 1f) - _VolumeMax = 1f; - } - } - } - - public float Position - { - get - { - if (Finished) - _Timer.Stop(); - //TODO: Why not use Decoder.GetPosition()? - return _CurrentTime + _Timer.ElapsedMilliseconds / 1000f; - } - } - - public bool Paused - { - get { return _Paused; } - set - { - _Paused = value; - lock (_MutexSyncSignals) - { - if (_Paused) - { - _Timer.Stop(); - AL.SourceStop(_Source); - } - else - { - _Timer.Start(); - _EventDecode.Set(); - AL.SourcePlay(_Source); - } - } - } - } - - public void Fade(float targetVolume, float fadeTime) - { - _Fading = new CFading(_Volume, targetVolume, fadeTime); - _AfterFadeAction = EStreamAction.Nothing; - } - - public void FadeAndPause(float targetVolume, float fadeTime) - { - Fade(targetVolume, fadeTime); - _AfterFadeAction = EStreamAction.Pause; - } - - public void FadeAndStop(float targetVolume, float fadeTime, Closeproc closeProc, int streamID) - { - _Closeproc = closeProc; - _StreamID = streamID; - Fade(targetVolume, fadeTime); - _AfterFadeAction = EStreamAction.Stop; - } - - public void Play() - { - Paused = false; - _AfterFadeAction = EStreamAction.Nothing; - AL.SourcePlay(_Source); - } - - public void Stop() - { - AL.SourceStop(_Source); - Skip(0f); - } - - public bool Loop - { - get { return _SetLoop; } - set { _SetLoop = value; } - } - - public int Open(string fileName) - { - if (_FileOpened) - return -1; - - if (!File.Exists(fileName)) - return -1; - - _Decoder = new CAudioDecoderFFmpeg(); - _Decoder.Init(); - - try - { - _Source = AL.GenSource(); - _Buffers = new int[_BufferCount]; - for (int i = 0; i < _BufferCount; i++) - _Buffers[i] = AL.GenBuffer(); - - _State = 0; - //AL.SourceQueueBuffers(_source, _buffers.Length, _buffers); - } - catch (Exception) - { - _Initialized = false; - CLog.LogError("Error Init OpenAL Playback"); - return -1; - } - - _Decoder.Open(fileName); - _Duration = _Decoder.GetLength(); - - _Format = _Decoder.GetFormatInfo(); - _ByteCount = 2 * _Format.ChannelCount; - _BytesPerSecond = _Format.SamplesPerSecond * _ByteCount; - _CurrentTime = 0f; - _Timer.Reset(); - - var stream = new SAudioStreams(0) {Handle = _Buffers[0]}; - - if (stream.Handle != 0) - { - _FileOpened = true; - _Data = new CRingBuffer(_Bufsize); - _NoMoreData = false; - _DecoderThread.Priority = ThreadPriority.Normal; - _DecoderThread.Name = Path.GetFileName(fileName); - _DecoderThread.Start(); - - return stream.Handle; - } - _Initialized = true; - return -1; - } - - public bool Skip(float time) - { - lock (_MutexSyncSignals) - { - _SetStart = time; - _SetSkip = true; - } - _EventDecode.Set(); - - return true; - } - - #region Threading - private void _DoSkip() - { - _Decoder.SetPosition(_Start); - _CurrentTime = _Start; - _TimeCode = _Start; - _Timer.Reset(); - _Waiting = false; - - lock (_MutexData) - { - _Data = new CRingBuffer(_Bufsize); - _NoMoreData = false; - } - } - - private void _Execute() - { - while (!_Terminated) - { - _Waiting = false; - if (_EventDecode.WaitOne(1) || !_Waiting) - { - if (_Skip) - { - _DoSkip(); - _Skip = false; - } - - _DoDecode(); - } - if (!_Terminated) - { - lock (_MutexSyncSignals) - { - if (_SetSkip) - _Skip = true; - - _SetSkip = false; - - _Start = _SetStart; - _Loop = _SetLoop; - } - } - } - - _DoFree(); - } - - private void _DoDecode() - { - if (!_FileOpened) - return; - - if (_Paused) - return; - - if (_Terminated) - return; - - float timecode; - byte[] buffer; - - bool doIt = false; - lock (_MutexData) - { - if (_Bufsize - 10000L > _Data.BytesNotRead) - doIt = true; - } - - if (!doIt) - return; - - _Decoder.Decode(out buffer, out timecode); - - if (buffer == null) - { - if (_Loop) - { - lock (_MutexSyncSignals) - { - _CurrentTime = 0f; - _Start = 0f; - } - - _DoSkip(); - } - else - _NoMoreData = true; - return; - } - - lock (_MutexData) - { - _Data.Write(buffer); - _TimeCode = timecode; - } - } - - private void _DoFree() - { - if (_Initialized) - { - lock (_CloseMutex) - { - Stop(); - AL.DeleteSource(_Source); - AL.DeleteBuffers(_Buffers); - } - _Decoder.Close(); - } - - _Closeproc(_StreamID); - } - #endregion Threading - - private void _Update() - { - if (_Fading != null) - { - bool finished; - _Volume = _Fading.GetValue(out finished); - if (finished) - { - switch (_AfterFadeAction) - { - case EStreamAction.Close: - case EStreamAction.Stop: - _Terminated = true; - break; - case EStreamAction.Pause: - Paused = true; - break; - } - _Fading = null; - } - } - } - - public void UploadData() - { - _Update(); - - if (_Paused) - return; - - int queuedCount; - bool doit = true; - AL.GetSource(_Source, ALGetSourcei.BuffersQueued, out queuedCount); - - int processedCount = _BufferCount; - if (queuedCount > 0) - { - AL.GetSource(_Source, ALGetSourcei.BuffersProcessed, out processedCount); - doit = false; - Console.WriteLine("Buffers Processed on Stream " + _Source + " = " + processedCount); - if (processedCount < 1) - return; - } - - var buf = new byte[_BufferSize]; - - lock (_MutexData) - { - while (processedCount > 0) - { - if (_Data.BytesNotRead >= buf.Length) - { - _Data.Read(buf); - - - var b = new byte[2]; - for (int i = 0; i < buf.Length; i += _ByteCount) - { - b[0] = buf[i]; - b[1] = buf[i + 1]; - - b = BitConverter.GetBytes((Int16)(BitConverter.ToInt16(b, 0) * _Volume * _VolumeMax)); - buf[i] = b[0]; - buf[i + 1] = b[1]; - - if (_ByteCount == 4) - { - b[0] = buf[i + 2]; - b[1] = buf[i + 3]; - - b = BitConverter.GetBytes((Int16)(BitConverter.ToInt16(b, 0) * _Volume * _VolumeMax)); - buf[i + 2] = b[0]; - buf[i + 3] = b[1]; - } - } - - - int buffer; - if (!doit) - buffer = AL.SourceUnqueueBuffer(_Source); - else - { - buffer = _Buffers[queuedCount]; - queuedCount++; - } - - if (buffer != 0) - { - ALFormat alFormat = (_Format.ChannelCount == 2) ? ALFormat.Stereo16 : ALFormat.Mono16; - AL.BufferData(buffer, alFormat, buf, buf.Length, _Format.SamplesPerSecond); - Console.WriteLine("Write to Buffer: " + buffer); - AL.SourceQueueBuffer(_Source, buffer); - } - } - processedCount--; - } - AL.GetSource(_Source, ALGetSourcei.SourceState, out _State); - if ((ALSourceState)_State != ALSourceState.Playing) - AL.SourcePlay(_Source); - } - - _CurrentTime = _TimeCode - _Data.BytesNotRead / _BytesPerSecond - 0.1f; - _Timer.Reset(); - _Timer.Start(); - } - - public void Dispose() - { - _EventDecode.Close(); - _EventDecode = null; - } - } } \ No newline at end of file diff --git a/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs b/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs index e135211e..484b0d6b 100644 --- a/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/DirectSound/CDirectSoundRecord.cs @@ -53,10 +53,7 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound { using (var ds = new DirectSoundCapture(dev.DriverGuid)) { - var device = new CRecordDevice {Driver = dev.DriverGuid.ToString(), ID = id, Name = dev.Description, Channels = ds.Capabilities.Channels}; - - if (device.Channels > 2) - device.Channels = 2; //more are not supported in vocaluxe + var device = new CRecordDevice(id,dev.DriverGuid.ToString(), dev.Description, ds.Capabilities.Channels); _Devices.Add(device); diff --git a/Vocaluxe/Lib/Sound/Record/IRecord.cs b/Vocaluxe/Lib/Sound/Record/IRecord.cs index 1dfea755..6812e7c0 100644 --- a/Vocaluxe/Lib/Sound/Record/IRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/IRecord.cs @@ -22,13 +22,25 @@ namespace Vocaluxe.Lib.Sound.Record { class CRecordDevice { - public int ID; - public string Name; - public string Driver; + public readonly int ID; + public readonly string Name; + public readonly string Driver; - public int Channels; + public readonly int Channels; public int PlayerChannel1; public int PlayerChannel2; + + public CRecordDevice(int id, string name, string driver, int channels) + { + ID = id; + Name = name; + Driver = driver; + + if (channels > 2) + channels = 2; //more are not supported in vocaluxe + + Channels = channels; + } } struct SMicConfig diff --git a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs index 05b37330..98a3dd72 100644 --- a/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs +++ b/Vocaluxe/Lib/Sound/Record/PortAudio/CPortAudioRecord.cs @@ -71,10 +71,7 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio CPortAudio.SPaDeviceInfo info = CPortAudio.PaGetDeviceInfo(i); if (info.HostApi == hostAPI && info.MaxInputChannels > 0) { - var dev = new CRecordDevice {ID = i, Name = info.Name, Driver = info.Name + i, Channels = info.MaxInputChannels}; - - if (dev.Channels > 2) - dev.Channels = 2; //more are not supported in vocaluxe + var dev = new CRecordDevice( i, info.Name,info.Name + i, info.MaxInputChannels); _Devices.Add(dev); }