diff --git a/src/Aurio.FFmpeg.UnitTest/Aurio.FFmpeg.UnitTest.csproj b/src/Aurio.FFmpeg.UnitTest/Aurio.FFmpeg.UnitTest.csproj
index 24ec5cd7..ced1c761 100644
--- a/src/Aurio.FFmpeg.UnitTest/Aurio.FFmpeg.UnitTest.csproj
+++ b/src/Aurio.FFmpeg.UnitTest/Aurio.FFmpeg.UnitTest.csproj
@@ -18,6 +18,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
+
diff --git a/src/Aurio.FFmpeg.UnitTest/FFmpegSourceStreamTests.cs b/src/Aurio.FFmpeg.UnitTest/FFmpegSourceStreamTests.cs
new file mode 100644
index 00000000..c0bee4d3
--- /dev/null
+++ b/src/Aurio.FFmpeg.UnitTest/FFmpegSourceStreamTests.cs
@@ -0,0 +1,82 @@
+using System;
+using System.IO;
+using Xunit;
+
+namespace Aurio.FFmpeg.UnitTest
+{
+ public class FFmpegSourceStreamTests
+ {
+ [Fact]
+ public void CreateWaveProxy_ProxyFileInfoIsNull()
+ {
+ FileInfo fileInfo = new("X:\\test.file");
+ FileInfo? proxyFileInfo = null;
+
+ void act() => FFmpegSourceStream.CreateWaveProxy(fileInfo, proxyFileInfo);
+
+ Assert.Throws(act);
+ }
+
+ [SkippableFact]
+ public void SuggestWaveProxyFileInfo_WithoutDirectory_Windows()
+ {
+ Skip.IfNot(OperatingSystem.IsWindows());
+
+ var fileInfo = new FileInfo("X:\\folder\\file.wav");
+
+ var proxyFileInfo = FFmpegSourceStream.SuggestWaveProxyFileInfo(fileInfo);
+
+ Assert.Equal("X:\\folder\\file.wav.ffproxy.wav", proxyFileInfo.FullName);
+ }
+
+ [SkippableFact]
+ public void SuggestWaveProxyFileInfo_WithoutDirectory_Unix()
+ {
+ Skip.If(OperatingSystem.IsWindows());
+
+ var fileInfo = new FileInfo("/folder/file.wav");
+
+ var proxyFileInfo = FFmpegSourceStream.SuggestWaveProxyFileInfo(fileInfo);
+
+ Assert.Equal("/folder/file.wav.ffproxy.wav", proxyFileInfo.FullName);
+ }
+
+ [SkippableFact]
+ public void SuggestWaveProxyFileInfo_WithDirectory_Windows()
+ {
+ Skip.IfNot(OperatingSystem.IsWindows());
+
+ var fileInfo = new FileInfo("X:\\folder\\file.wav");
+ var directoryInfo = new DirectoryInfo("Y:\\temp\\dir");
+
+ var proxyFileInfo = FFmpegSourceStream.SuggestWaveProxyFileInfo(
+ fileInfo,
+ directoryInfo
+ );
+
+ Assert.Equal(
+ "Y:\\temp\\dir\\87c18cf1c8d8e07552df4ecc1ef629995fca9c59ad47ccf7eb4816de33590af7.ffproxy.wav",
+ proxyFileInfo.FullName
+ );
+ }
+
+ [SkippableFact]
+ public void SuggestWaveProxyFileInfo_WithDirectory_Unix()
+ {
+ Skip.If(OperatingSystem.IsWindows());
+
+ var fileInfo = new FileInfo("/folder/file.wav");
+ var directoryInfo = new DirectoryInfo("/temp/dir");
+
+ var proxyFileInfo = FFmpegSourceStream.SuggestWaveProxyFileInfo(
+ fileInfo,
+ directoryInfo
+ );
+
+ Assert.Equal(
+ "/temp/dir/e2c5b9282d156c5bdbf95639ca2ce2516b096e4828b7aa16620cb317cc90b3d9.ffproxy.wav",
+ proxyFileInfo.FullName
+ );
+ }
+ }
+}
diff --git a/src/Aurio.FFmpeg/FFmpegAudioStreamFactory.cs b/src/Aurio.FFmpeg/FFmpegAudioStreamFactory.cs
index e063ce1d..54df6276 100644
--- a/src/Aurio.FFmpeg/FFmpegAudioStreamFactory.cs
+++ b/src/Aurio.FFmpeg/FFmpegAudioStreamFactory.cs
@@ -31,6 +31,8 @@ public FFmpegAudioStreamFactory()
public IAudioStream OpenFile(FileInfo fileInfo, FileInfo proxyFileInfo = null)
{
+ proxyFileInfo ??= FFmpegSourceStream.SuggestWaveProxyFileInfo(fileInfo);
+
if (FFmpegSourceStream.WaveProxySuggested(fileInfo))
{
Console.WriteLine("File format with known seek problems, creating proxy file...");
diff --git a/src/Aurio.FFmpeg/FFmpegSourceStream.cs b/src/Aurio.FFmpeg/FFmpegSourceStream.cs
index b0e84c06..67a817cd 100644
--- a/src/Aurio.FFmpeg/FFmpegSourceStream.cs
+++ b/src/Aurio.FFmpeg/FFmpegSourceStream.cs
@@ -27,6 +27,8 @@ namespace Aurio.FFmpeg
{
public class FFmpegSourceStream : IAudioStream
{
+ public const string ProxyFileExtension = ".ffproxy.wav";
+
private Stream sourceStream;
private FFmpegReader reader;
private AudioProperties properties;
@@ -287,6 +289,11 @@ public void Dispose()
public static FileInfo CreateWaveProxy(FileInfo fileInfo, FileInfo proxyFileInfo)
{
+ if (proxyFileInfo == null)
+ {
+ throw new ArgumentNullException(nameof(proxyFileInfo));
+ }
+
if (proxyFileInfo.Exists)
{
Console.WriteLine("Proxy already existing, using " + proxyFileInfo.Name);
@@ -339,39 +346,16 @@ out Type type
}
///
- /// Creates a Wave format proxy file in the same directory and with the same name as the specified file,
- /// if no storage directory is specified (i.e. if it is null). If a storage directory is specified, the proxy
- /// file will be stored in the specified directory with a hashed file name to avoid name collisions and
- /// file overwrites. The story directory option is convenient for the usage of temporary or working directories.
+ /// Creates a Wave format proxy file for the given file and optional directory according
+ /// to .
///
/// the file for which a proxy file should be created
/// optional directory where the proxy file will be stored, can be null
/// the FileInfo of the proxy file
public static FileInfo CreateWaveProxy(FileInfo fileInfo, DirectoryInfo storageDirectory)
{
- if (storageDirectory == null)
- {
- // Without a storage directory, store the proxy file beside the original file
- var proxyFileInfo = new FileInfo(fileInfo.FullName + ".ffproxy.wav");
- return CreateWaveProxy(fileInfo, proxyFileInfo);
- }
- else
- {
- // With a storage directory specified, store the proxy file with a hashed name
- // (to avoid name collision / overwrites) in the target directory (e.g. a temp or working directory)
- using (var sha256 = SHA256.Create())
- {
- byte[] hash = sha256.ComputeHash(Encoding.Unicode.GetBytes(fileInfo.FullName));
- string hashString = BitConverter
- .ToString(hash)
- .Replace("-", "")
- .ToLowerInvariant();
- var proxyFileInfo = new FileInfo(
- Path.Combine(storageDirectory.FullName, hashString + ".ffproxy.wav")
- );
- return CreateWaveProxy(fileInfo, proxyFileInfo);
- }
- }
+ var proxyFileInfo = SuggestWaveProxyFileInfo(fileInfo, storageDirectory);
+ return CreateWaveProxy(fileInfo, proxyFileInfo);
}
///
@@ -399,6 +383,42 @@ public static bool WaveProxySuggested(FileInfo fileInfo)
);
}
+ ///
+ /// Creates a proxy file info for the provided file with the .
+ ///
+ /// If a storage directory is specified, the proxy file will be located in the specified directory
+ /// with a hashed file name to avoid name collisions. This option is is convenient when using
+ /// temporary or working directories.
+ ///
+ /// If no storage diretory is specified, the proxy file will be located in the same directory and
+ /// with the same name as the specified file.
+ ///
+ /// the file for which a proxy file should be created
+ /// optional directory where the proxy file will be stored (can be null)
+ /// the FileInfo of the suggested proxy file
+ public static FileInfo SuggestWaveProxyFileInfo(
+ FileInfo fileInfo,
+ DirectoryInfo storageDirectory = null
+ )
+ {
+ if (storageDirectory == null)
+ {
+ // Without a storage directory, store the proxy file beside the original file
+ return new FileInfo(fileInfo.FullName + ProxyFileExtension);
+ }
+ else
+ {
+ // With a storage directory specified, store the proxy file with a hashed name
+ // (to avoid name collision / overwrites) in the target directory (e.g. a temp or working directory)
+ using var sha256 = SHA256.Create();
+ byte[] hash = sha256.ComputeHash(Encoding.Unicode.GetBytes(fileInfo.FullName));
+ string hashString = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
+ return new FileInfo(
+ Path.Combine(storageDirectory.FullName, hashString + ProxyFileExtension)
+ );
+ }
+ }
+
public class FileNotSeekableException : Exception
{
public FileNotSeekableException()