Browse Source

AudioNTR add reverse connection mode: receiver-as-client and transmitter-as-server

HOME 2 years ago
parent
commit
0ab510ed41
1 changed files with 174 additions and 62 deletions
  1. 174 62
      AudioNTR/Program.cs

+ 174 - 62
AudioNTR/Program.cs

@@ -1,7 +1,6 @@
 using NAudio.Wave;
 using System;
 using System.Collections.Concurrent;
-using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
 using System.Net;
@@ -40,6 +39,10 @@ namespace AudioNTR
                     Console.WriteLine("     <target-address> <port> Run as Transmitter Captures default audio output");
                     Console.WriteLine(" transmitter-sine-wave");
                     Console.WriteLine("     <target-address> <port> Run as Transmitter Sine wave");
+                    Console.WriteLine(" receiver-as-client");
+                    Console.WriteLine("     <target-address> <port>   Run receiver as client");
+                    Console.WriteLine(" transmitter-as-server");
+                    Console.WriteLine("     <target-address> <port> Run transmitter as server Captures default audio output");
                     break;
 
                 case "capture": TestRunCapture(argsToOp); break;
@@ -49,9 +52,177 @@ namespace AudioNTR
                 case "receiver": RunReceiver(argsToOp); break;
                 case "transmitter": RunTransmitter(argsToOp); break;
                 case "transmitter-sine-wave": RunTransmitterSineWave(argsToOp); break;
+                case "receiver-as-client": RunReceiverAsClient(argsToOp); break;
+                case "transmitter-as-server": RunTransmitterAsServer(argsToOp); break;
             }
         }
 
+        private static void RunTransmitterAsServer(string[] argsToOp)
+        {
+            if (argsToOp.Length < 1) throw new ArgumentException("least 1 args for listen port");
+            if (false == int.TryParse(argsToOp[0], out var port)) throw new ArgumentException("invalid port");
+            IPAddress address = null;
+            if (argsToOp.Length > 1 && false == IPAddress.TryParse(argsToOp[1], out address)) throw new ArgumentException("invalid address");
+
+            Console.WriteLine("Creating TcpListener...");
+            var listener = new TcpListener(address ?? IPAddress.Any, port);
+            Console.WriteLine("Start Listening...");
+            listener.Start();
+            Console.WriteLine($"Listening on {listener.LocalEndpoint}");
+
+            var running = true;
+
+            var task = Task.Run(() =>
+            {
+                while (running)
+                {
+                    Console.WriteLine("Waiting connection...");
+                    var client = listener.AcceptTcpClient();
+                    client.NoDelay = true;
+                    Console.WriteLine($"Accept connection from {client.Client.RemoteEndPoint}...");
+                    var stream = client.GetStream();
+                    Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
+                    var provider = new WasapiLoopbackCapture();
+                    Console.WriteLine("Sending wave format ...");
+                    var writer = new BinaryWriter(stream, Encoding.UTF8, true);
+                    provider.WaveFormat.Serialize(writer);
+                    writer.Close();
+                    Console.WriteLine("Begin sending chunks...");
+                    long totalSent = 0;
+                    var up = DateTime.Now;
+                    var connectAlive = true;
+                    provider.DataAvailable += (sender, args) =>
+                    {
+                        Console.Title = $"Sent bytes: {totalSent:N0}, UP: {DateTime.Now - up}";
+                        try
+                        {
+                            stream.Write(args.Buffer, 0, args.BytesRecorded);
+                            stream.Flush();
+                        }
+                        catch (Exception e)
+                        {
+                            Console.WriteLine($"connection lost:{e.Message}");
+                            connectAlive = false;
+                            return;
+                        }
+
+                        totalSent += args.BytesRecorded;
+                    };
+                    provider.StartRecording();
+                    while (running && connectAlive) Thread.Sleep(100);
+                    provider.StopRecording();
+                }
+            });
+
+            Console.WriteLine("Press ENTER to Exit.");
+            Console.ReadLine();
+            running = false;
+            task.Wait();
+            Console.WriteLine("Finished.");
+        }
+
+        private static void RunReceiverAsClient(string[] argsToOp)
+        {
+            const int bufferMs = 500;
+            
+            if (argsToOp.Length != 2) throw new ArgumentException("required 2 args for address and port");
+            if (false == IPAddress.TryParse(argsToOp[0], out var address)) throw new ArgumentException("invalid address");
+            if (false == int.TryParse(argsToOp[1], out var port)) throw new ArgumentException("invalid port");
+
+            var running = true;
+
+            var task = Task.Run(() =>
+            {
+                do
+                {
+                    TcpClient client = null;
+                    try
+                    {
+                        Console.WriteLine("Creating TcpClient ...");
+                        client = new TcpClient { NoDelay = true };
+                        var ipEndPoint = new IPEndPoint(address, port);
+                        Console.WriteLine($"Connecting to {ipEndPoint} ...");
+                        client.Connect(ipEndPoint);
+                        var stream = client.GetStream();
+                        Console.WriteLine("Parsing wave format and create BufferedWaveProvider...");
+                        var reader = new BinaryReader(stream, Encoding.UTF8, true);
+                        var provider = new BufferedWaveProvider(new WaveFormat(reader))
+                        {
+                            BufferDuration = TimeSpan.FromMilliseconds(bufferMs),
+                            DiscardOnBufferOverflow = true,
+                        };
+                        reader.Dispose();
+                        Console.WriteLine($"Encoding: {provider.WaveFormat.Encoding}");
+                        Console.WriteLine($"Channels: {provider.WaveFormat.Channels}");
+                        Console.WriteLine($"SampleRate: {provider.WaveFormat.SampleRate}");
+                        Console.WriteLine($"BitsPerSample: {provider.WaveFormat.BitsPerSample}");
+
+                        Console.WriteLine($"Buffer Duration set to {provider.BufferDuration}");
+
+                        Console.WriteLine("Creating WasapiOut Instance...");
+                        var output = new WasapiOut();
+                        Console.WriteLine("Setup...");
+                        output.Init(provider);
+
+                        const int fillSleep = bufferMs * 11 / 20;
+                        Console.WriteLine($"Filling buffer, sleep {fillSleep}ms");
+                        Thread.Sleep(fillSleep);
+
+                        Console.WriteLine("Starting play...");
+                        output.Play();
+
+                        try
+                        {
+                            var buf = new byte[1024 * 1024];//1MB
+                            int readCount;
+
+                            Console.WriteLine("Begin read chunks...");
+                            do
+                            {
+                                Console.Title = $"Buffered bytes: {provider.BufferedBytes:N0}";
+                                readCount = stream.Read(buf, 0, buf.Length);
+                                provider.AddSamples(buf, 0, readCount);
+                            } while (readCount > 0 && running);
+                        }
+                        catch (Exception e)
+                        {
+                            Console.WriteLine(e);
+                        }
+
+                        Console.WriteLine("Closing connection...");
+                        client.Close();
+                        provider.ClearBuffer();
+                        Console.WriteLine("Stopping Playing...");
+                        output.Stop();
+                        Console.WriteLine("Free resources");
+                        client.Dispose();
+                    }
+                    catch (Exception e)
+                    {
+                        Console.WriteLine(e);
+
+                        if (running)
+                        {
+                            Console.WriteLine("Wait 10 Seconds to re connection");
+                            Thread.Sleep(10 * 1000);
+                        }
+                    }
+                    finally
+                    {
+                        Console.WriteLine("Free resources");
+                        client?.Close();
+                        client?.Dispose();
+                    }
+                } while (running);
+            });
+
+            Console.WriteLine("Press ENTER to exit");
+            Console.ReadLine();
+            running = false;
+            task.Wait();
+            Console.WriteLine("Finished.");
+        }
+
         private static void TestRunCapture(string[] argsToOp)
         {
             Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
@@ -190,7 +361,7 @@ namespace AudioNTR
                     Console.WriteLine("Setup...");
                     output.Init(provider);
 
-                    const int fillSleep = bufferMs*11/20;
+                    const int fillSleep = bufferMs * 11 / 20;
                     Console.WriteLine($"Filling buffer, sleep {fillSleep}ms");
                     Thread.Sleep(fillSleep);
 
@@ -270,7 +441,6 @@ namespace AudioNTR
                             provider.Read(buffer, 0, buffer.Length);
                             stream.Write(buffer, 0, buffer.Length);
                         }
-
                     }
                     catch (Exception e)
                     {
@@ -288,8 +458,6 @@ namespace AudioNTR
                         client?.Close();
                         client?.Dispose();
                     }
-
-
                 } while (running);
             });
 
@@ -337,7 +505,7 @@ namespace AudioNTR
                         var up = DateTime.Now;
                         provider.DataAvailable += (sender, args) =>
                         {
-                            Console.Title = $"Sent bytes: {totalSent:N0}, UP: {DateTime.Now-up}";
+                            Console.Title = $"Sent bytes: {totalSent:N0}, UP: {DateTime.Now - up}";
                             stream.Write(args.Buffer, 0, args.BytesRecorded);
                             stream.Flush();
                             totalSent += args.BytesRecorded;
@@ -345,7 +513,6 @@ namespace AudioNTR
                         provider.StartRecording();
                         while (running) Thread.Sleep(100);
                         provider.StopRecording();
-
                     }
                     catch (Exception e)
                     {
@@ -363,8 +530,6 @@ namespace AudioNTR
                         client?.Close();
                         client?.Dispose();
                     }
-
-
                 } while (running);
             });
 
@@ -376,59 +541,6 @@ namespace AudioNTR
         }
     }
 
-    //internal class BufferedWaveProvider : IWaveProvider, IDisposable
-    //{
-    //    private readonly BlockingCollection<byte> _buffer;
-    //    private readonly CancellationTokenSource _cancellationTokenSource = new();
-
-    //    public BufferedWaveProvider(WaveFormat waveFormat, int msBuffer = 1000)
-    //    {
-    //        WaveFormat = waveFormat;
-    //        _buffer = new BlockingCollection<byte>((int)Math.Ceiling(WaveFormat.SampleRate / 1000f * msBuffer * WaveFormat.Channels * (WaveFormat.BitsPerSample / 8f)));
-    //    }
-
-    //    public void Feed(byte[] buffer, int count)
-    //    {
-    //        if (_cancellationTokenSource.IsCancellationRequested) return;
-    //        for (var i = 0; i < count; i++) _buffer.Add(buffer[i], _cancellationTokenSource.Token);
-    //    }
-
-    //    public int Read(byte[] buffer, int offset, int count)
-    //    {
-    //        if (_cancellationTokenSource.IsCancellationRequested) return 0;
-
-    //        var readCount = 0;
-
-    //        var eof = offset + count;
-
-    //        do
-    //        {
-    //            try
-    //            {
-    //                buffer[offset] = _buffer.Take(_cancellationTokenSource.Token);
-    //            }
-    //            catch (OperationCanceledException)
-    //            {
-    //                return readCount;
-    //            }
-    //            readCount++;
-    //            offset++;
-    //        } while (_buffer.Count > 0 && offset < eof && _cancellationTokenSource.IsCancellationRequested == false);
-
-    //        return readCount;
-    //    }
-
-    //    public WaveFormat WaveFormat { get; }
-    //    public object BufferedBytes => _buffer.Count;
-
-    //    public void Dispose()
-    //    {
-    //        _cancellationTokenSource?.Cancel();
-    //        _buffer?.Dispose();
-    //        _cancellationTokenSource?.Dispose();
-    //    }
-    //}
-
     internal class WaveInProvider : IWaveProvider
     {
         private readonly IWaveIn _input;