ToolsHelper.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace WechatBakTool.Helpers
  10. {
  11. public class ToolsHelper
  12. {
  13. private static TaskFactory factory = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(10));
  14. public static string DecodeVoice(string source,string pcm,string to)
  15. {
  16. string ffmpeg = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tools", "ffmpeg.exe");
  17. string silk_decoder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tools", "silk_v3_decoder.exe");
  18. Task task = factory.StartNew(() =>
  19. {
  20. Process silk = new Process();
  21. silk.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  22. silk.StartInfo.UseShellExecute = false;
  23. silk.StartInfo.CreateNoWindow = true;
  24. silk.StartInfo.FileName = silk_decoder;
  25. silk.StartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", source, pcm);
  26. silk.Start();
  27. silk.WaitForExit();
  28. if (File.Exists(pcm))
  29. {
  30. Process ff = new Process();
  31. ff.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  32. ff.StartInfo.UseShellExecute= false;
  33. ff.StartInfo.CreateNoWindow = true;
  34. ff.StartInfo.FileName = ffmpeg;
  35. ff.StartInfo.Arguments = string.Format(" -y -f s16le -ar 24000 -ac 1 -i \"{0}\" -ar 24000 -b:a 320k \"{1}\"", pcm, to);
  36. ff.Start();
  37. ff.WaitForExit();
  38. }
  39. });
  40. return "";
  41. }
  42. }
  43. partial class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
  44. {
  45. // Indicates whether the current thread is processing work items.
  46. [ThreadStatic]
  47. private static bool _currentThreadIsProcessingItems;
  48. // The list of tasks to be executed
  49. private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
  50. // The maximum concurrency level allowed by this scheduler.
  51. private readonly int _maxDegreeOfParallelism;
  52. // Indicates whether the scheduler is currently processing work items.
  53. private int _delegatesQueuedOrRunning = 0;
  54. // Creates a new instance with the specified degree of parallelism.
  55. public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
  56. {
  57. if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
  58. _maxDegreeOfParallelism = maxDegreeOfParallelism;
  59. }
  60. // Queues a task to the scheduler.
  61. protected sealed override void QueueTask(Task task)
  62. {
  63. // Add the task to the list of tasks to be processed. If there aren't enough
  64. // delegates currently queued or running to process tasks, schedule another.
  65. lock (_tasks)
  66. {
  67. _tasks.AddLast(task);
  68. if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
  69. {
  70. ++_delegatesQueuedOrRunning;
  71. NotifyThreadPoolOfPendingWork();
  72. }
  73. }
  74. }
  75. // Inform the ThreadPool that there's work to be executed for this scheduler.
  76. private void NotifyThreadPoolOfPendingWork()
  77. {
  78. ThreadPool.UnsafeQueueUserWorkItem(_ =>
  79. {
  80. // Note that the current thread is now processing work items.
  81. // This is necessary to enable inlining of tasks into this thread.
  82. _currentThreadIsProcessingItems = true;
  83. try
  84. {
  85. // Process all available items in the queue.
  86. while (true)
  87. {
  88. Task item;
  89. lock (_tasks)
  90. {
  91. // When there are no more items to be processed,
  92. // note that we're done processing, and get out.
  93. if (_tasks.Count == 0)
  94. {
  95. --_delegatesQueuedOrRunning;
  96. break;
  97. }
  98. // Get the next item from the queue
  99. item = _tasks.First.Value;
  100. _tasks.RemoveFirst();
  101. }
  102. // Execute the task we pulled out of the queue
  103. base.TryExecuteTask(item);
  104. }
  105. }
  106. // We're done processing items on the current thread
  107. finally { _currentThreadIsProcessingItems = false; }
  108. }, null);
  109. }
  110. // Attempts to execute the specified task on the current thread.
  111. protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
  112. {
  113. // If this thread isn't already processing a task, we don't support inlining
  114. if (!_currentThreadIsProcessingItems) return false;
  115. // If the task was previously queued, remove it from the queue
  116. if (taskWasPreviouslyQueued)
  117. // Try to run the task.
  118. if (TryDequeue(task))
  119. return base.TryExecuteTask(task);
  120. else
  121. return false;
  122. else
  123. return base.TryExecuteTask(task);
  124. }
  125. // Attempt to remove a previously scheduled task from the scheduler.
  126. protected sealed override bool TryDequeue(Task task)
  127. {
  128. lock (_tasks) return _tasks.Remove(task);
  129. }
  130. // Gets the maximum concurrency level supported by this scheduler.
  131. public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
  132. // Gets an enumerable of the tasks currently scheduled on this scheduler.
  133. protected sealed override IEnumerable<Task> GetScheduledTasks()
  134. {
  135. bool lockTaken = false;
  136. try
  137. {
  138. Monitor.TryEnter(_tasks, ref lockTaken);
  139. if (lockTaken) return _tasks;
  140. else throw new NotSupportedException();
  141. }
  142. finally
  143. {
  144. if (lockTaken) Monitor.Exit(_tasks);
  145. }
  146. }
  147. }
  148. }