|
@@ -0,0 +1,166 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Diagnostics;
|
|
|
+using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading;
|
|
|
+using System.Threading.Tasks;
|
|
|
+
|
|
|
+namespace WechatPCMsgBakTool.Helpers
|
|
|
+{
|
|
|
+ public class ToolsHelper
|
|
|
+ {
|
|
|
+ public static TaskFactory factory = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(10));
|
|
|
+ public static string DecodeVoice(string source,string pcm,string to)
|
|
|
+ {
|
|
|
+ string ffmpeg = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tools", "ffmpeg.exe");
|
|
|
+ string silk_decoder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tools", "silk_v3_decoder.exe");
|
|
|
+
|
|
|
+ Task task = factory.StartNew(() =>
|
|
|
+ {
|
|
|
+ Process silk = new Process();
|
|
|
+ silk.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
|
|
+ silk.StartInfo.UseShellExecute = false;
|
|
|
+ silk.StartInfo.CreateNoWindow = true;
|
|
|
+ silk.StartInfo.FileName = silk_decoder;
|
|
|
+ silk.StartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", source, pcm);
|
|
|
+ silk.Start();
|
|
|
+ silk.WaitForExit();
|
|
|
+
|
|
|
+ if (File.Exists(pcm))
|
|
|
+ {
|
|
|
+ Process ff = new Process();
|
|
|
+ ff.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
|
|
+ ff.StartInfo.UseShellExecute= false;
|
|
|
+ ff.StartInfo.CreateNoWindow = true;
|
|
|
+ ff.StartInfo.FileName = ffmpeg;
|
|
|
+ ff.StartInfo.Arguments = string.Format(" -y -f s16le -ar 24000 -ac 1 -i \"{0}\" -ar 24000 -b:a 320k \"{1}\"", pcm, to);
|
|
|
+ ff.Start();
|
|
|
+ ff.WaitForExit();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
|
|
|
+ {
|
|
|
+ // Indicates whether the current thread is processing work items.
|
|
|
+ [ThreadStatic]
|
|
|
+ private static bool _currentThreadIsProcessingItems;
|
|
|
+
|
|
|
+ // The list of tasks to be executed
|
|
|
+ private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
|
|
|
+
|
|
|
+ // The maximum concurrency level allowed by this scheduler.
|
|
|
+ private readonly int _maxDegreeOfParallelism;
|
|
|
+
|
|
|
+ // Indicates whether the scheduler is currently processing work items.
|
|
|
+ private int _delegatesQueuedOrRunning = 0;
|
|
|
+
|
|
|
+ // Creates a new instance with the specified degree of parallelism.
|
|
|
+ public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
|
|
|
+ {
|
|
|
+ if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
|
|
|
+ _maxDegreeOfParallelism = maxDegreeOfParallelism;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Queues a task to the scheduler.
|
|
|
+ protected sealed override void QueueTask(Task task)
|
|
|
+ {
|
|
|
+ // Add the task to the list of tasks to be processed. If there aren't enough
|
|
|
+ // delegates currently queued or running to process tasks, schedule another.
|
|
|
+ lock (_tasks)
|
|
|
+ {
|
|
|
+ _tasks.AddLast(task);
|
|
|
+ if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
|
|
|
+ {
|
|
|
+ ++_delegatesQueuedOrRunning;
|
|
|
+ NotifyThreadPoolOfPendingWork();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Inform the ThreadPool that there's work to be executed for this scheduler.
|
|
|
+ private void NotifyThreadPoolOfPendingWork()
|
|
|
+ {
|
|
|
+ ThreadPool.UnsafeQueueUserWorkItem(_ =>
|
|
|
+ {
|
|
|
+ // Note that the current thread is now processing work items.
|
|
|
+ // This is necessary to enable inlining of tasks into this thread.
|
|
|
+ _currentThreadIsProcessingItems = true;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // Process all available items in the queue.
|
|
|
+ while (true)
|
|
|
+ {
|
|
|
+ Task item;
|
|
|
+ lock (_tasks)
|
|
|
+ {
|
|
|
+ // When there are no more items to be processed,
|
|
|
+ // note that we're done processing, and get out.
|
|
|
+ if (_tasks.Count == 0)
|
|
|
+ {
|
|
|
+ --_delegatesQueuedOrRunning;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get the next item from the queue
|
|
|
+ item = _tasks.First.Value;
|
|
|
+ _tasks.RemoveFirst();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Execute the task we pulled out of the queue
|
|
|
+ base.TryExecuteTask(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // We're done processing items on the current thread
|
|
|
+ finally { _currentThreadIsProcessingItems = false; }
|
|
|
+ }, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Attempts to execute the specified task on the current thread.
|
|
|
+ protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
|
|
|
+ {
|
|
|
+ // If this thread isn't already processing a task, we don't support inlining
|
|
|
+ if (!_currentThreadIsProcessingItems) return false;
|
|
|
+
|
|
|
+ // If the task was previously queued, remove it from the queue
|
|
|
+ if (taskWasPreviouslyQueued)
|
|
|
+ // Try to run the task.
|
|
|
+ if (TryDequeue(task))
|
|
|
+ return base.TryExecuteTask(task);
|
|
|
+ else
|
|
|
+ return false;
|
|
|
+ else
|
|
|
+ return base.TryExecuteTask(task);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Attempt to remove a previously scheduled task from the scheduler.
|
|
|
+ protected sealed override bool TryDequeue(Task task)
|
|
|
+ {
|
|
|
+ lock (_tasks) return _tasks.Remove(task);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Gets the maximum concurrency level supported by this scheduler.
|
|
|
+ public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
|
|
|
+
|
|
|
+ // Gets an enumerable of the tasks currently scheduled on this scheduler.
|
|
|
+ protected sealed override IEnumerable<Task> GetScheduledTasks()
|
|
|
+ {
|
|
|
+ bool lockTaken = false;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Monitor.TryEnter(_tasks, ref lockTaken);
|
|
|
+ if (lockTaken) return _tasks;
|
|
|
+ else throw new NotSupportedException();
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ if (lockTaken) Monitor.Exit(_tasks);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|