-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
358 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using System; | ||
using System.IO; | ||
using System.Collections.Generic; | ||
|
||
namespace Cavern.Format.Utilities { | ||
/// <summary> | ||
/// A thread-safe FIFO <see cref="MemoryStream"/>. | ||
/// </summary> | ||
public class QueueStream : Stream { | ||
/// <summary> | ||
/// The underlying FIFO. | ||
/// </summary> | ||
Queue<byte> queue = new Queue<byte>(); | ||
|
||
/// <inheritdoc/> | ||
public override bool CanRead { | ||
get { | ||
lock (queue) { | ||
return queue.Count != 0; | ||
} | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override bool CanSeek => false; | ||
|
||
/// <inheritdoc/> | ||
public override bool CanWrite => true; | ||
|
||
/// <inheritdoc/> | ||
public override long Length { | ||
get { | ||
lock (queue) { | ||
return queue.Count; | ||
} | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override long Position { | ||
get => throw new NotSupportedException(); | ||
set => throw new NotSupportedException(); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override void Flush() { } | ||
|
||
/// <inheritdoc/> | ||
public override int Read(byte[] buffer, int offset, int count) { | ||
int read = 0; | ||
while (read < count) { | ||
lock (queue) { | ||
int readUntil = Math.Min(read + queue.Count, count); | ||
for (; read < readUntil; read++) { | ||
buffer[offset + read] = queue.Dequeue(); | ||
} | ||
} | ||
} | ||
return count; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override void Write(byte[] buffer, int offset, int count) { | ||
lock (queue) { | ||
for (int i = 0; i < count; i++) { | ||
queue.Enqueue(buffer[offset + i]); | ||
} | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); | ||
|
||
/// <inheritdoc/> | ||
public override void SetLength(long value) => throw new NotSupportedException(); | ||
|
||
/// <inheritdoc/> | ||
protected override void Dispose(bool disposing) { | ||
queue = null; | ||
base.Dispose(disposing); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>disable</Nullable> | ||
<Authors>VoidX</Authors> | ||
<Product>CavernPipe Client</Product> | ||
<Description>Reference implementation of the CavernPipe protocol with rendering content according to Cavern settings on the network.</Description> | ||
<Copyright>Copyright © Bence Sgánetz 2016-2025</Copyright> | ||
<PackageProjectUrl>https://cavern.sbence.hu/</PackageProjectUrl> | ||
<RepositoryUrl>https://github.com/VoidXH/Cavern/</RepositoryUrl> | ||
<RepositoryType>git</RepositoryType> | ||
<NeutralLanguage>en</NeutralLanguage> | ||
<ApplicationIcon>..\Icon.ico</ApplicationIcon> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\..\Cavern.Format\Cavern.Format.csproj" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
using System.IO.Pipes; | ||
|
||
using Cavern; | ||
using Cavern.Format; | ||
using Cavern.Format.Utilities; | ||
|
||
if (args.Length < 2) { | ||
Console.WriteLine("Usage: CavernPipeClient.exe <input file name> <output file name>"); | ||
return; | ||
} | ||
|
||
Listener listener = new(); | ||
AudioReader source = AudioReader.Open(args[0]); | ||
source.ReadHeader(); | ||
using AudioWriter target = AudioWriter.Create(args[1], Listener.Channels.Length, source.Length, source.SampleRate, BitDepth.Float32); | ||
source.Dispose(); | ||
target.WriteHeader(); | ||
|
||
// Connection | ||
using NamedPipeClientStream pipe = new("CavernPipe"); | ||
pipe.Connect(); | ||
byte[] pipeHeader = new byte[8]; // Assembled CavernPipe control header | ||
pipeHeader[0] = (byte)target.Bits; | ||
pipeHeader[1] = 6; // Mandatory frames | ||
BitConverter.GetBytes((ushort)target.ChannelCount).CopyTo(pipeHeader, 2); | ||
BitConverter.GetBytes(listener.UpdateRate).CopyTo(pipeHeader, 4); | ||
pipe.Write(pipeHeader, 0, pipeHeader.Length); | ||
|
||
// Sending the file or part to the pipe | ||
using FileStream reader = File.OpenRead(args[0]); | ||
long sent = 0; | ||
float[] writeBuffer = []; | ||
byte[] sendBuffer = new byte[1024 * 1024], | ||
receiveBuffer = []; | ||
while (sent < reader.Length) { | ||
int toSend = reader.Read(sendBuffer, 0, sendBuffer.Length); | ||
pipe.Write(BitConverter.GetBytes(toSend)); | ||
pipe.Write(sendBuffer, 0, toSend); | ||
sent += toSend; | ||
|
||
// If there is incoming data, write it to file | ||
int toReceive = pipe.ReadInt32(); | ||
if (receiveBuffer.Length < toReceive) { | ||
receiveBuffer = new byte[toReceive]; | ||
writeBuffer = new float[toReceive / sizeof(float)]; | ||
} | ||
pipe.ReadAll(receiveBuffer, 0, toReceive); | ||
Buffer.BlockCopy(receiveBuffer, 0, writeBuffer, 0, toReceive); | ||
target.WriteBlock(writeBuffer, 0, toReceive / sizeof(float)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System.IO; | ||
|
||
using Cavern.Format; | ||
using Cavern.Format.Common; | ||
using Cavern.Format.Utilities; | ||
|
||
namespace CavernPipeServer { | ||
/// <summary> | ||
/// Reads CavernPipe control messages. | ||
/// </summary> | ||
public class CavernPipeProtocol { | ||
/// <summary> | ||
/// The PCM format in which the connected client expects the data. | ||
/// </summary> | ||
public BitDepth OutputFormat { get; } | ||
|
||
/// <summary> | ||
/// Calculated from byte 2 (number of frames to always render before sending a reply), this is the number of bytes in those frames. | ||
/// If this many bytes are not available, the client must wait for data. | ||
/// </summary> | ||
public int MandatoryBytesToSend { get; } | ||
|
||
/// <summary> | ||
/// Number of output channels of the client. If Cavern renders less according to user settings, additional channels are filled with silence. | ||
/// If Cavern renders more, excess channels will be cut off and a warning shall be shown. | ||
/// </summary> | ||
public int OutputChannels { get; } | ||
|
||
/// <summary> | ||
/// Number of samples expected in a reply PCM stream. | ||
/// </summary> | ||
public int UpdateRate { get; } | ||
|
||
/// <summary> | ||
/// Reads CavernPipe control messages. | ||
/// </summary> | ||
public CavernPipeProtocol(Stream source) { | ||
OutputFormat = (BitDepth)source.ReadByte(); | ||
int mandatoryFrames = source.ReadByte(); | ||
OutputChannels = source.ReadUInt16(); | ||
UpdateRate = source.ReadInt32(); | ||
if (UpdateRate <= 0) { | ||
throw new SyncException(); // Extension point for later | ||
} | ||
MandatoryBytesToSend = mandatoryFrames * OutputChannels * UpdateRate * ((int)OutputFormat / 8); | ||
} | ||
} | ||
} |
Oops, something went wrong.