diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fa3399d39..2680d6417 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -35,6 +35,39 @@ jobs:
- name: Get Path to Tests
run: echo "TEST_PATH=$(dotnet msbuild SIL.Core.Tests/ --getProperty:OutputPath -p:TargetFramework=${{ matrix.framework }} -p:Configuration=Release)" >> $GITHUB_ENV
+ # Several steps to set up FFmpeg and Scream and start Audio Service so that audio tests can run
+ - name: Install FFmpeg
+ uses: FedericoCarboni/setup-ffmpeg@v3
+ id: setup-ffmpeg
+ with:
+ ffmpeg-version: release
+ - run: echo ffmpeg path ${{ steps.setup-ffmpeg.outputs.ffmpeg-path }}
+
+ - name: Install Scream on Windows
+ shell: powershell
+ run: |
+ Invoke-WebRequest https://github.com/duncanthrax/scream/releases/download/4.0/Scream4.0.zip -OutFile Scream4.0.zip
+ Expand-Archive -Path Scream4.0.zip -DestinationPath Scream
+ openssl req -batch -verbose -x509 -newkey rsa -keyout ScreamCertificate.pvk -out ScreamCertificate.cer -nodes -extensions v3_req
+ openssl pkcs12 -export -nodes -in ScreamCertificate.cer -inkey ScreamCertificate.pvk -out ScreamCertificate.pfx -passout pass:
+
+ - name: Setup MSVC Dev Cmd
+ uses: ilammy/msvc-dev-cmd@v1
+
+ - name: Sign and Install Scream Driver on Windows
+ if: matrix.os == 'windows-latest'
+ shell: powershell
+ run: |
+ signtool sign /v /fd SHA256 /f ScreamCertificate.pfx Scream\Install\driver\x64\Scream.cat
+ Import-Certificate -FilePath ScreamCertificate.cer -CertStoreLocation Cert:\LocalMachine\root
+ Import-Certificate -FilePath ScreamCertificate.cer -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
+ Scream\Install\helpers\devcon-x64.exe install Scream\Install\driver\x64\Scream.inf *Scream
+ timeout-minutes: 5
+
+ - name: Start Windows Audio Service
+ run: net start audiosrv
+ shell: powershell
+
# there are cases where this will fail and we want to know about it
# so we don't use continue-on-error, but we still want to publish the results
- name: Test project
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50855f1f1..d48d36e7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [SIL.Archiving] Added public property isValid to IMDIPackage.
- [SIL.Archiving] Added public event InitializationFailed to IMDIArchivingDlgViewModel.
- [SIL.Archiving] Added the following properties to ArchivingDlgViewModel as an alternative way to customize the initial summary displayed: GetOverriddenPreArchivingMessages, InitialFileGroupDisplayMessageType, OverrideGetFileGroupDisplayMessage
+- [SIL.Media] Added FFmpegRunner.FfmpegMinimumVersion property.
### Changed
@@ -78,6 +79,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [SIL.Archiving] Changed the name of the third parameter in ArchivingDlgViewModel.AddFileGroup from progressMessage to addingToArchiveProgressMessage.
- [SIL.Windows.Forms.Archiving] Changed Cancel Button to say Close instead in IMDIArchivingDlg.
- [SIL.Core.Desktop] Renamed GetFromRegistryProgramThatOpensFileType to GetDefaultProgramForFileType.
+- [SIL.Media] Made FFmpegRunner able to use version of FFmpeg found on the path.
+- [SIL.Media] Upgraded irrKlang to v. 1.6.
### Fixed
- [SIL.Archiving] Fixed typo in RampArchivingDlgViewModel for Ethnomusicology performance collection.
diff --git a/Palaso.sln.DotSettings b/Palaso.sln.DotSettings
index 6bfe95d19..e644a8af1 100644
--- a/Palaso.sln.DotSettings
+++ b/Palaso.sln.DotSettings
@@ -23,6 +23,7 @@
True
True
True
+ True
True
True
True
@@ -34,6 +35,7 @@
True
True
True
+ True
True
True
True
@@ -118,6 +120,7 @@
True
True
True
+ True
True
True
True
diff --git a/SIL.Media.Tests/AudioFactoryTests.cs b/SIL.Media.Tests/AudioFactoryTests.cs
index b3ba3ee9a..fb2665c82 100644
--- a/SIL.Media.Tests/AudioFactoryTests.cs
+++ b/SIL.Media.Tests/AudioFactoryTests.cs
@@ -6,7 +6,6 @@ namespace SIL.Media.Tests
{
// These will not work if a speaker is not available.
[TestFixture]
- [Category("SkipOnTeamCity")]
[Category("AudioTests")]
public class AudioFactoryTests
{
diff --git a/SIL.Media.Tests/AudioPlayerTests.cs b/SIL.Media.Tests/AudioPlayerTests.cs
index 87a40a40c..13e33ec96 100644
--- a/SIL.Media.Tests/AudioPlayerTests.cs
+++ b/SIL.Media.Tests/AudioPlayerTests.cs
@@ -10,13 +10,12 @@
namespace SIL.Media.Tests
{
///
- /// All these tests are skipped on TeamCity (even if you remove this category) because SIL.Media.Tests compiles to an exe,
- /// and the project that builds libpalaso on TeamCity (build/Palaso.proj, task Test) invokes RunNUnitTC which
- /// selects the test assemblies using Include="$(RootDir)/output/$(Configuration)/*.Tests.dll" which excludes exes.
- /// I have not tried to verify that all of these tests would actually have problems on TeamCity, but it seemed
- /// helpful to document in the usual way that they are not, in fact, run there.
+ /// Tests for the AudioPlayer class.
///
- [Category("SkipOnTeamCity")]
+ /// This fixture used to be skipped during the CI build, perhaps because of the test
+ /// that actually tries to do playback (since that would require an audio output device).
+ /// However, that test is now ignored and the only non-ignored test works fine without an
+ /// actual playback device.
[TestFixture]
public class AudioPlayerTests
{
@@ -33,7 +32,7 @@ public void LoadFile_ThenDispose_FileCanBeDeleted()
}
///
- /// This test shows what caused hearthis to abandon the naudio; previous to a change to this class in 2/2012, it is believed that all was ok.
+ /// This test shows what caused HearThis to abandon NAudio; previous to a change to this class in 2/2012, it is believed that all was ok.
///
[Test, Ignore("Known to Fail (hangs forever")]
public void PlayFile_ThenDispose_FileCanBeDeleted()
diff --git a/SIL.Media.Tests/AudioRecorderTests.cs b/SIL.Media.Tests/AudioRecorderTests.cs
index b6cf4f997..a783c0e94 100644
--- a/SIL.Media.Tests/AudioRecorderTests.cs
+++ b/SIL.Media.Tests/AudioRecorderTests.cs
@@ -11,7 +11,6 @@ namespace SIL.Media.Tests
// Some of these tests require a speaker. Others require a microphone.
// None of them will work if neither a speaker nor a microphone is available.
[TestFixture]
- [Category("SkipOnTeamCity")]
[Category("AudioTests")]
public class AudioRecorderTests
{
diff --git a/SIL.Media.Tests/AudioSessionTests.cs b/SIL.Media.Tests/AudioSessionTests.cs
index ea557bbff..450301b43 100644
--- a/SIL.Media.Tests/AudioSessionTests.cs
+++ b/SIL.Media.Tests/AudioSessionTests.cs
@@ -15,7 +15,6 @@ namespace SIL.Media.Tests
// Some of these tests require a speaker. Others require a microphone.
// None of them will work if neither a speaker nor a microphone is available.
[TestFixture]
- [NUnit.Framework.Category("SkipOnTeamCity")]
[NUnit.Framework.Category("AudioTests")]
public class AudioSessionTests
{
@@ -265,10 +264,7 @@ public RecordingSession(int millisecondsToRecordBeforeStopping)
_recorder.StopRecordingAndSaveAsWav();
}
- public ISimpleAudioSession Recorder
- {
- get { return _recorder; }
- }
+ public ISimpleAudioSession Recorder => _recorder;
public void Dispose()
{
@@ -451,8 +447,8 @@ public void Record_LongRecording()
{
using (var folder = new TemporaryFolder("Record_LongRecording"))
{
- string fpath = Path.Combine(folder.Path, "long.wav");
- using (var x = AudioFactory.CreateAudioSession(fpath))
+ string fPath = Path.Combine(folder.Path, "long.wav");
+ using (var x = AudioFactory.CreateAudioSession(fPath))
{
SystemSounds.Beep.Play();
Assert.DoesNotThrow(() => x.StartRecording());
diff --git a/SIL.Media.Tests/FFmpegRunnerTests.cs b/SIL.Media.Tests/FFmpegRunnerTests.cs
index 1430daf64..dcae847aa 100644
--- a/SIL.Media.Tests/FFmpegRunnerTests.cs
+++ b/SIL.Media.Tests/FFmpegRunnerTests.cs
@@ -1,4 +1,6 @@
+using System;
using System.IO;
+using FFMpegCore;
using NUnit.Framework;
using SIL.IO;
using SIL.Media.Tests.Properties;
@@ -6,14 +8,7 @@
namespace SIL.Media.Tests
{
- ///
- /// All these tests are skipped on TeamCity (even if you remove this category) because SIL.Media.Tests compiles to an exe,
- /// and the project that builds libpalaso on TeamCity (build/Palaso.proj, task Test) invokes RunNUnitTC which
- /// selects the test assemblies using Include="$(RootDir)/output/$(Configuration)/*.Tests.dll" which excludes exes.
- /// I have not tried to verify that all of these tests would actually have problems on TeamCity, but it seemed
- /// helpful to document in the usual way that they are not, in fact, run there.
- ///
- [Category("SkipOnTeamCity")]
+ [Category("RequiresFfmpeg")]
[TestFixture]
public class FFmpegRunnerTests
{
@@ -21,18 +16,52 @@ public class FFmpegRunnerTests
public void CheckRequirements()
{
if (!FFmpegRunner.HaveNecessaryComponents)
- Assert.Ignore("These tests require ffmpeg to be installed.");
+ {
+ if (Environment.GetEnvironmentVariable("CI") == null)
+ Assert.Ignore("These tests require ffmpeg to be installed.");
+ else
+ Assert.Fail("On CI build using GHA, FFMpeg should have been installed before running tests.");
+ }
}
[Test]
- [Category("RequiresFfmpeg")]
- public void HaveNecessaryComponents_ReturnsTrue()
+ public void HaveNecessaryComponents_NoExplicitMinVersion_ReturnsTrue()
+ {
+ Assert.IsTrue(FFmpegRunner.HaveNecessaryComponents);
+ }
+
+ [TestCase(5, 1)]
+ [TestCase(4, 9)]
+ public void HaveNecessaryComponents_TwoDigitMinVersion_ReturnsTrue(int major, int minor)
{
+ FFmpegRunner.FfmpegMinimumVersion = new Version(major, minor);
Assert.IsTrue(FFmpegRunner.HaveNecessaryComponents);
}
+ [TestCase(5, 1, 1)]
+ [TestCase(5, 0, 0)]
+ public void HaveNecessaryComponents_ThreeDigitMinVersion_ReturnsTrue(int major, int minor, int build)
+ {
+ FFmpegRunner.FfmpegMinimumVersion = new Version(major, minor, build);
+ Assert.IsTrue(FFmpegRunner.HaveNecessaryComponents);
+ }
+
+ [TestCase(5, 1, 1, 0)]
+ [TestCase(5, 0, 0, 9)]
+ public void HaveNecessaryComponents_FourDigitMinVersion_ReturnsTrue(int major, int minor, int build, int revision)
+ {
+ FFmpegRunner.FfmpegMinimumVersion = new Version(major, minor, build, revision);
+ Assert.IsTrue(FFmpegRunner.HaveNecessaryComponents);
+ }
+
+ [Test]
+ public void HaveNecessaryComponents_ReallyHighVersionThatDoesNotExist_ReturnsFalse()
+ {
+ FFmpegRunner.FfmpegMinimumVersion = new Version(int.MaxValue, int.MaxValue);
+ Assert.IsFalse(FFmpegRunner.HaveNecessaryComponents);
+ }
+
[Test]
- [Category("RequiresFfmpeg")]
public void ExtractMp3Audio_CreatesFile()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -44,7 +73,6 @@ public void ExtractMp3Audio_CreatesFile()
}
[Test]
- [Category("RequiresFfmpeg")]
public void ExtractOggAudio_CreatesFile()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -56,7 +84,6 @@ public void ExtractOggAudio_CreatesFile()
}
[Test]
- [Category("RequiresFfmpeg")]
public void ChangeNumberOfAudioChannels_CreatesFile()
{
using (var file = TempFile.FromResource(Resources._2Channel, ".wav"))
@@ -68,7 +95,6 @@ public void ChangeNumberOfAudioChannels_CreatesFile()
}
[Test]
- [Category("RequiresFfmpeg")]
public void MakeLowQualityCompressedAudio_CreatesFile()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -79,12 +105,29 @@ public void MakeLowQualityCompressedAudio_CreatesFile()
var outputPath = originalAudioPath.Replace("mp3", "low.mp3");
FFmpegRunner.MakeLowQualityCompressedAudio(originalAudioPath, outputPath, new ConsoleProgress());
Assert.IsTrue(File.Exists(outputPath));
- System.Diagnostics.Process.Start(outputPath);
+
+ var mediaInfoOrig = FFProbe.Analyse(file.Path);
+ var mediaInfo = FFProbe.Analyse(outputPath);
+
+ // Validate resolution and bit rate
+ Assert.That(mediaInfo.PrimaryVideoStream, Is.Null);
+ Assert.That(mediaInfo.PrimaryAudioStream, Is.Not.Null);
+ Assert.That(mediaInfo.AudioStreams.Count, Is.EqualTo(1));
+ Assert.That(mediaInfo.PrimaryAudioStream.Channels, Is.EqualTo(1));
+ Assert.That(mediaInfo.Format.BitRate, Is.LessThan(mediaInfoOrig.Format.BitRate));
+ Assert.That(mediaInfo.PrimaryAudioStream.SampleRateHz, Is.EqualTo(8000));
+ try
+ {
+ RobustFile.Delete(outputPath);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
}
}
[Test]
- [Category("RequiresFfmpeg")]
public void MakeLowQualitySmallVideo_CreatesFile()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -92,7 +135,28 @@ public void MakeLowQualitySmallVideo_CreatesFile()
var outputPath = file.Path.Replace("wmv", "low.wmv");
FFmpegRunner.MakeLowQualitySmallVideo(file.Path, outputPath, 0, new ConsoleProgress());
Assert.IsTrue(File.Exists(outputPath));
- System.Diagnostics.Process.Start(outputPath);
+
+ var mediaInfoOrig = FFProbe.Analyse(file.Path);
+ var mediaInfo = FFProbe.Analyse(outputPath);
+
+ // Validate resolution and bit rate
+ Assert.That(mediaInfo.PrimaryVideoStream, Is.Not.Null);
+ Assert.That(mediaInfo.VideoStreams.Count, Is.EqualTo(1));
+ Assert.That(mediaInfo.PrimaryAudioStream, Is.Not.Null);
+ Assert.That(mediaInfo.AudioStreams.Count, Is.EqualTo(1));
+ Assert.That(mediaInfo.PrimaryVideoStream.Width, Is.EqualTo(160));
+ Assert.That(mediaInfo.PrimaryVideoStream.Height, Is.EqualTo(120));
+ Assert.That(mediaInfo.Format.BitRate, Is.LessThan(mediaInfoOrig.Format.BitRate));
+ try
+ {
+ // When running the by-hand test, the default media player might leave this
+ // locked, so this cleanup will fail.
+ RobustFile.Delete(outputPath);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
}
}
}
diff --git a/SIL.Media.Tests/MediaInfoTests.cs b/SIL.Media.Tests/MediaInfoTests.cs
index a9f8a608b..0b4710e38 100644
--- a/SIL.Media.Tests/MediaInfoTests.cs
+++ b/SIL.Media.Tests/MediaInfoTests.cs
@@ -1,17 +1,11 @@
+using System;
using NUnit.Framework;
using SIL.IO;
using SIL.Media.Tests.Properties;
namespace SIL.Media.Tests
{
- ///
- /// All these tests are skipped on TeamCity (even if you remove this category) because SIL.Media.Tests compiles to an exe,
- /// and the project that builds libpalaso on TeamCity (build/Palaso.proj, task Test) invokes RunNUnitTC which
- /// selects the test assemblies using Include="$(RootDir)/output/$(Configuration)/*.Tests.dll" which excludes exes.
- /// I have not tried to verify that all of these tests would actually have problems on TeamCity, but it seemed
- /// helpful to document in the usual way that they are not, in fact, run there.
- ///
- [Category("SkipOnTeamCity")]
+ [Category("RequiresFFprobe")]
[TestFixture]
public class MediaInfoTests
{
@@ -19,18 +13,21 @@ public class MediaInfoTests
public void CheckRequirements()
{
if (!MediaInfo.HaveNecessaryComponents)
- Assert.Ignore(MediaInfo.MissingComponentMessage);
+ {
+ if (Environment.GetEnvironmentVariable("CI") == null)
+ Assert.Ignore(MediaInfo.MissingComponentMessage);
+ else
+ Assert.Fail("On CI build using GHA, FFMpeg should have been installed before running tests.");
+ }
}
[Test]
- [Category("RequiresFFprobe")]
public void HaveNecessaryComponents_ReturnsTrue()
{
Assert.IsTrue(MediaInfo.HaveNecessaryComponents);
}
[Test]
- [Category("RequiresFFprobe")]
public void VideoInfo_Duration_Correct()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -43,7 +40,6 @@ public void VideoInfo_Duration_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void VideoInfo_Encoding_Correct()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -54,7 +50,6 @@ public void VideoInfo_Encoding_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void VideoInfo_Resolution_Correct()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -65,7 +60,6 @@ public void VideoInfo_Resolution_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void VideoInfo_FramesPerSecond_Correct()
{
using (var file = TempFile.FromResource(Resources.tiny, ".wmv"))
@@ -77,7 +71,6 @@ public void VideoInfo_FramesPerSecond_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void AudioInfo_Duration_Correct()
{
using (var file = TempFile.FromResource(Resources.finished, ".wav"))
@@ -89,7 +82,6 @@ public void AudioInfo_Duration_Correct()
[Test]
- [Category("RequiresFFprobe")]
public void AudioInfo_SampleFrequency_Correct()
{
using (var file = TempFile.FromResource(Resources.finished, ".wav"))
@@ -100,7 +92,6 @@ public void AudioInfo_SampleFrequency_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void AudioInfo_Channels_Correct()
{
using (var file = TempFile.FromResource(Resources.finished, ".wav"))
@@ -111,7 +102,6 @@ public void AudioInfo_Channels_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void AudioInfo_BitDepth_Correct()
{
using (var file = TempFile.FromResource(Resources.finished, ".wav"))
@@ -122,7 +112,6 @@ public void AudioInfo_BitDepth_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void AudioInfo_H4N24BitStereoBitDepth_Correct()
{
using (var file = TempFile.FromResource(Resources._24bitH4NSample, ".wav"))
@@ -133,14 +122,12 @@ public void AudioInfo_H4N24BitStereoBitDepth_Correct()
}
[Test]
- [Category("RequiresFFprobe")]
public void GetMediaInfo_AudioFile_VideoInfoAndImageInfoAreNull()
{
using (var file = TempFile.FromResource(Resources.finished,".wav"))
{
var info =MediaInfo.GetInfo(file.Path);
Assert.IsNull(info.Video);
- //Assert.IsNull(info.Image);
}
}
diff --git a/SIL.Media/FFmpegRunner.cs b/SIL.Media/FFmpegRunner.cs
index f29b25c38..5db9de7a7 100644
--- a/SIL.Media/FFmpegRunner.cs
+++ b/SIL.Media/FFmpegRunner.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Text.RegularExpressions;
using JetBrains.Annotations;
using SIL.CommandLineProcessing;
using SIL.IO;
@@ -27,6 +28,16 @@ public class FFmpegRunner
/// If your app knows where FFmpeg lives, you can tell us before making any calls.
///
public static string FFmpegLocation;
+ ///
+ /// If your app has a known minimum version of FFMpeg that it will work with, you can set
+ /// this to prevent this library from attempting to use a version that is not going to meet
+ /// your requirements. This will be ignored if you set FFmpegLocation, if the ffmpeg
+ /// installation is based on a Linux package dependency or if FFmpeg is colocated with the
+ /// applications, since it seems safe to assume that you are not specifying or installing a
+ /// version that does not satisfy your needs.
+ ///
+ public static Version FfmpegMinimumVersion;
+ private static bool? _ffmpegOnPath;
///
/// Find the path to FFmpeg, and remember it (some apps (like SayMore) call FFmpeg a lot)
@@ -67,7 +78,11 @@ private static string LocateFFmpeg()
var fromChoco = MediaInfo.GetFFmpegFolderFromChocoInstall(kFFmpegExe);
if (fromChoco != null)
- return Path.Combine(fromChoco, kFFmpegExe);
+ {
+ var pathToFFmpeg = Path.Combine(fromChoco, kFFmpegExe);
+ if (MeetsMinimumVersionRequirement(pathToFFmpeg))
+ return pathToFFmpeg;
+ }
var progFileDirs = new List {
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@@ -93,10 +108,45 @@ private static string LocateFFmpeg()
foreach (var path in progFileDirs)
{
var exePath = (Path.Combine(path, "FFmpeg for Audacity", kFFmpegExe));
- if (File.Exists(exePath))
+ if (File.Exists(exePath) && MeetsMinimumVersionRequirement(exePath))
return exePath;
}
- return null;
+
+ string ffmpeg = null;
+
+ // Locate may be called multiple times, we don't want to run this command every time.
+ if (_ffmpegOnPath == null)
+ {
+ ffmpeg = Path.GetFileNameWithoutExtension(kFFmpegExe);
+ // Try to just run ffmpeg from the path, if it works then we can use that directly.
+ _ffmpegOnPath = MeetsMinimumVersionRequirement(ffmpeg);
+ if (!_ffmpegOnPath.Value)
+ ffmpeg = null;
+ }
+ return ffmpeg;
+ }
+
+ private static bool MeetsMinimumVersionRequirement(string ffmpeg)
+ {
+ try
+ {
+ var version = new Regex(@"ffmpeg version (?\d+\.\d+(\.\d+)?)");
+ var results = CommandLineRunner.Run(ffmpeg, "-version", ".", 5, new NullProgress());
+ var match = version.Match(results.StandardOutput);
+ if (!match.Success)
+ return false;
+ if (FfmpegMinimumVersion == null)
+ return true;
+ var actualVersion = Version.Parse(match.Groups["version"].Value);
+ actualVersion = new Version(actualVersion.Major, actualVersion.Minor,
+ actualVersion.Build >= 0 ? actualVersion.Build : 0,
+ actualVersion.Revision >= 0 ? actualVersion.Revision : 0);
+ return actualVersion >= FfmpegMinimumVersion;
+ }
+ catch
+ {
+ return false;
+ }
}
private static string GetPathToBundledFFmpeg()
@@ -168,7 +218,7 @@ public static ExecutionResult ExtractMp3Audio(string inputPath, string outputPat
var arguments = $"-i \"{inputPath}\" -vn {mp3LameCodecArg} -ac {channels} \"{outputPath}\"";
var result = RunFFmpeg(arguments, progress);
- //hide a meaningless error produced by some versions of liblame
+ // Hide a meaningless error produced by some versions of liblame
if (result.StandardError.Contains("lame: output buffer too small")
&& File.Exists(outputPath))
{
@@ -203,7 +253,7 @@ public static ExecutionResult ExtractOggAudio(string inputPath, string outputPat
var arguments = $"-i \"{inputPath}\" -vn -acodec vorbis -ac {channels} \"{outputPath}\"";
var result = RunFFmpeg(arguments, progress);
- //hide a meaningless error produced by some versions of liblame
+ // Hide a meaningless error produced by some versions of liblame
if (result.StandardError.Contains("lame: output buffer too small")
&& File.Exists(outputPath))
{
@@ -294,7 +344,7 @@ private static ExecutionResult ExtractAudio(string inputPath, string outputPath,
var result = RunFFmpeg(arguments, progress);
- //hide a meaningless error produced by some versions of liblame
+ // Hide a meaningless error produced by some versions of liblame
if (result.StandardError.Contains("lame: output buffer too small")
&& File.Exists(outputPath))
{
@@ -328,7 +378,7 @@ public static ExecutionResult ChangeNumberOfAudioChannels(string inputPath,
var result = RunFFmpeg(arguments, progress);
- //hide a meaningless error produced by some versions of liblame
+ // Hide a meaningless error produced by some versions of liblame
if (result.StandardError.Contains("lame: output buffer too small") && File.Exists(outputPath))
{
var doctoredResult = new ExecutionResult
@@ -361,7 +411,7 @@ public static ExecutionResult MakeLowQualityCompressedAudio(string inputPath, st
var result = RunFFmpeg(arguments, progress);
- //hide a meaningless error produced by some versions of liblame
+ // Hide a meaningless error produced by some versions of liblame
if (result.StandardError.Contains("lame: output buffer too small")
&& File.Exists(outputPath))
{
@@ -404,7 +454,7 @@ public static ExecutionResult MakeLowQualitySmallVideo(string inputPath, string
var result = RunFFmpeg(arguments, progress);
- //hide a meaningless error produced by some versions of liblame
+ // Hide a meaningless error produced by some versions of liblame
if (result.StandardError.Contains("lame: output buffer too small")
&& File.Exists(outputPath))
{
diff --git a/SIL.Media/Naudio/AudioPlayer.cs b/SIL.Media/Naudio/AudioPlayer.cs
index 46cdf41c1..c6d325b75 100644
--- a/SIL.Media/Naudio/AudioPlayer.cs
+++ b/SIL.Media/Naudio/AudioPlayer.cs
@@ -1,5 +1,6 @@
-using System;
+using System;
using System.Timers;
+using JetBrains.Annotations;
using NAudio.Wave;
namespace SIL.Media.Naudio
@@ -26,6 +27,7 @@ public AudioPlayer()
};
}
+ [PublicAPI]
public void LoadStream(WaveStream stream)
{
InternalLoad(stream as TrimWaveStream ?? new TrimWaveStream(stream));
@@ -82,22 +84,19 @@ public void Stop()
public TimeSpan StartPosition
{
- get { return _inStream.StartPosition; }
- set { _inStream.StartPosition = value; }
+ get => _inStream.StartPosition;
+ set => _inStream.StartPosition = value;
}
public TimeSpan EndPosition
{
- get { return _inStream.EndPosition; }
- set { _inStream.EndPosition = value; }
+ get => _inStream.EndPosition;
+ set => _inStream.EndPosition = value;
}
public TimeSpan CurrentPosition { get; set; }
- public PlaybackState PlaybackState
- {
- get { return _waveOut == null ? PlaybackState.Stopped : _waveOut.PlaybackState; }
- }
+ public PlaybackState PlaybackState => _waveOut?.PlaybackState ?? PlaybackState.Stopped;
public void Dispose()
{
diff --git a/SIL.Media/WindowsAudioSession.cs b/SIL.Media/WindowsAudioSession.cs
index b764f0238..50b390940 100644
--- a/SIL.Media/WindowsAudioSession.cs
+++ b/SIL.Media/WindowsAudioSession.cs
@@ -17,7 +17,7 @@ namespace SIL.Media
internal class WindowsAudioSession : ISimpleAudioSession, ISimpleAudioWithEvents
{
private readonly IrrKlang.IAudioRecorder _recorder;
- private readonly ISoundEngine _engine = new ISoundEngine();
+ private readonly ISoundEngine _engine = new ISoundEngine(SoundOutputDriver.AutoDetect, SoundEngineOptionFlag.PrintDebugInfoIntoDebugger);
private bool _thinkWeAreRecording;
private DateTime _startRecordingTime;
private DateTime _stopRecordingTime;
diff --git a/SIL.Media/lib/win-x64/ikpFlac.dll b/SIL.Media/lib/win-x64/ikpFlac.dll
index abfed4f1c..2271a3fae 100644
Binary files a/SIL.Media/lib/win-x64/ikpFlac.dll and b/SIL.Media/lib/win-x64/ikpFlac.dll differ
diff --git a/SIL.Media/lib/win-x64/ikpMP3.dll b/SIL.Media/lib/win-x64/ikpMP3.dll
index 2f46856ec..b9134000c 100644
Binary files a/SIL.Media/lib/win-x64/ikpMP3.dll and b/SIL.Media/lib/win-x64/ikpMP3.dll differ
diff --git a/SIL.Media/lib/win-x64/irrKlang.NET4.dll b/SIL.Media/lib/win-x64/irrKlang.NET4.dll
index e32b982d3..ef53ee589 100644
Binary files a/SIL.Media/lib/win-x64/irrKlang.NET4.dll and b/SIL.Media/lib/win-x64/irrKlang.NET4.dll differ
diff --git a/SIL.Media/lib/win-x86/ikpFlac.dll b/SIL.Media/lib/win-x86/ikpFlac.dll
index 335e8b06d..b3cdcc550 100644
Binary files a/SIL.Media/lib/win-x86/ikpFlac.dll and b/SIL.Media/lib/win-x86/ikpFlac.dll differ
diff --git a/SIL.Media/lib/win-x86/ikpMP3.dll b/SIL.Media/lib/win-x86/ikpMP3.dll
index 974b8929b..b2e3ec342 100644
Binary files a/SIL.Media/lib/win-x86/ikpMP3.dll and b/SIL.Media/lib/win-x86/ikpMP3.dll differ
diff --git a/SIL.Media/lib/win-x86/irrKlang.NET4.dll b/SIL.Media/lib/win-x86/irrKlang.NET4.dll
index ca182caef..97131be4d 100644
Binary files a/SIL.Media/lib/win-x86/irrKlang.NET4.dll and b/SIL.Media/lib/win-x86/irrKlang.NET4.dll differ