jjzjj

c# - 尝试通过 TCP 传输 2 路音频?

coder 2023-09-18 原文

我正在尝试制作一个视频 session 应用程序(用 C# 编写),它允许 2 个用户使用 TCP 进行视频 session 。此外,用户还可以单独进行文字聊天。现在,我有一个可用的视频流,但还没有音频。我不确定如何访问麦克风,使用 TCP 对其进行流式传输,然后在其他用户的扬声器上播放它,因为我对 c# 比较陌生,对使用媒体也是全新的。

如果有人可以向我指出示例代码,帮助我了解如何访问麦克风,或者您认为对我有帮助的任何其他事情,那就太好了。

我附上我的代码以供引用。

网络摄像头.cs

using System;
using System.IO;
using System.Linq;
using System.Text;
using WebCam_Capture;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
using System.Net;
using System.Net.Sockets;
using System.Windows; 

namespace DuckTalk
{

class WebCam
{       
    const int TEXT_VIDEO_NUM = 45674;
    private System.Windows.Controls.TextBox _hostIpAddressBox;


    private WebCamCapture webcam;
    private int FrameNumber = 30;





    public void InitializeWebCam(ref System.Windows.Controls.TextBox hostIpAddressBox)
    {

        webcam = new WebCamCapture();
        webcam.FrameNumber = ((ulong)(0ul));
        webcam.TimeToCapture_milliseconds = FrameNumber;
        webcam.ImageCaptured += new WebCamCapture.WebCamEventHandler(webcam_ImageCaptured);


        _hostIpAddressBox = hostIpAddressBox;            
    }



    void webcam_ImageCaptured(object source, WebcamEventArgs e)
    {
        TcpClient connection = null;
        NetworkStream stream = null;
        byte[] imgBytes;

        try
        {
            //Set up IPAddress
            IPAddress ipAddress = IPAddress.Parse(_hostIpAddressBox.Text);
            IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, TEXT_VIDEO_NUM);

            //Connect to TCP
            connection = new TcpClient();
            connection.Connect(ipLocalEndPoint);

            // Get a client stream for reading and writing. 
            stream = connection.GetStream();

            //Send image as bytes
            imgBytes = ImageByteConverter.ImageToBytes((System.Drawing.Bitmap)e.WebCamImage);
            stream.Write(imgBytes, 0, imgBytes.Length);
        }
        catch (Exception error)
        {
            MessageBox.Show("ERROR: " + error.Message);
        }
        finally
        {
            // Close everything.
            if (connection != null)
                connection.Close();

            if (stream != null)
                stream.Close();
        }            
    }


    public void Start()
    {
        webcam.TimeToCapture_milliseconds = FrameNumber;
        webcam.Start(0);
    }


    public void Stop()
    {
        webcam.Stop();
    }

}
}

ImageByteConverter.cs

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections.Generic;
using System.Windows.Media.Imaging;


namespace DuckTalk
{
class ImageByteConverter
{               
    public static byte[] ImageToBytes(System.Drawing.Bitmap bitmap)
    {
        byte[] byteArray;

        using (MemoryStream stream = new MemoryStream())
        {
            bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
            stream.Close();

            byteArray = stream.ToArray();
        }

        return byteArray;
    }

    public static BitmapImage BytesToImage(byte[] imgBytes)
    {
        var image = new BitmapImage();

        image.BeginInit();
        image.StreamSource = new System.IO.MemoryStream(imgBytes);
        image.EndInit();

        return image;
    }
}
}

Window1.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;

namespace DuckTalk
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class MainWindow : Window
{
    const int TEXT_PORT_NUM = 45673;
    const int TEXT_VIDEO_NUM = 45674;
    WebCam webcam;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void mainWindow_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
        webcam = new WebCam();
        webcam.InitializeWebCam(ref xaml_hostTextBox);

        var _backgroundIMWorker = new BackgroundWorker();
        var _backgroundVidWorker = new BackgroundWorker();

        _backgroundIMWorker.WorkerReportsProgress = true;
        _backgroundVidWorker.WorkerReportsProgress = true;

        // Set up the Background Worker Events
        _backgroundIMWorker.DoWork += new DoWorkEventHandler(keepListeningForInstantMessages);
        _backgroundVidWorker.DoWork += new DoWorkEventHandler(keepListeningForVideoMessages);

        // Run the Background Workers
        _backgroundIMWorker.RunWorkerAsync();
        _backgroundVidWorker.RunWorkerAsync(); 
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //
    //
    //  The next 2 functions take care of the instant messaging part of the program
    //
    //
    //
    ///////////////////////////////////////////////////////////////////////////////////////////////
    private void keepListeningForInstantMessages(object sender, DoWorkEventArgs e)
    {
        Action<string> displayIncomingMessage = (incomingMsg) =>
        {
            xaml_incomingTextBox.Text += "\n\nINCOMING MESSAGE:   " + incomingMsg;
            xaml_incomingTextScroll.ScrollToBottom();
        };

        Socket connection;
        Byte[] data;
        String msg;

        // create the socket
        Socket listenSocket = new Socket(AddressFamily.InterNetwork,
                                         SocketType.Stream,
                                         ProtocolType.Tcp);

        // bind the listening socket to the port
        IPEndPoint ep = new IPEndPoint(IPAddress.Any, TEXT_PORT_NUM);
        listenSocket.Bind(ep);

        while (true)
        {
            msg = "";
            data = new Byte[3000];

            // start listening
            listenSocket.Listen(1);

            //Received a connection
            connection = listenSocket.Accept();

            //Get Data
            connection.Receive(data);

            //Get the message in string format
            msg = System.Text.Encoding.Default.GetString(data);
            msg = msg.Substring(0,msg.IndexOf((char)0));

            //Send message to the UI
            xaml_incomingTextBox.Dispatcher.BeginInvoke(displayIncomingMessage, msg);

            connection.Close();
        }
    }//end of keepListeningForInstantMessages

    void SendInstantMsg(object sender, RoutedEventArgs e)
    {
        TcpClient connection = null;
        NetworkStream stream = null;
        byte[] data;

        xaml_incomingTextBox.Text += "\n\nOUTGOING MESSAGE:   " + xaml_outgoingTextBox.Text;

        try
        {
            //Set up IPAddress
            IPAddress ipAddress = IPAddress.Parse(xaml_hostTextBox.Text);
            IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, TEXT_PORT_NUM);

            //Connect to TCP
            connection = new TcpClient();
            connection.Connect(ipLocalEndPoint);

            //Convert text to bytes
            data = System.Text.Encoding.ASCII.GetBytes(xaml_outgoingTextBox.Text);                               

            // Get a client stream for reading and writing. 
            stream = connection.GetStream();

            // Send the message to the connected TcpServer. 
            stream.Write(data, 0, data.Count());

            xaml_outgoingTextBox.Text = "";
        }
        catch (Exception error)
        {
            MessageBox.Show("ERROR: " + error.Message);
        }
        finally
        {
            // Close everything.
            if (connection != null)
                connection.Close();

            if (stream != null)
                stream.Close();
        }
    }//end of SendInstantMsg

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //
    //
    //  The next 2 functions take care of the video part of the program
    //
    //
    //
    ///////////////////////////////////////////////////////////////////////////////////////////////
    private void keepListeningForVideoMessages(object sender, DoWorkEventArgs e)
    {
        Action<Byte[]> displayIncomingVideo = (incomingImgBytes) =>
        {
            xaml_incomingVideo.Source = ImageByteConverter.BytesToImage(incomingImgBytes);
        };

        Socket connection;
        Byte[] incomingBytes;
        Byte[] data;
        int offset;
        int numOfBytesRecieved;

        // create the socket
        Socket listenSocket = new Socket(AddressFamily.InterNetwork,
                                         SocketType.Stream,
                                         ProtocolType.Tcp);

        // bind the listening socket to the port
        IPEndPoint ep = new IPEndPoint(IPAddress.Any, TEXT_VIDEO_NUM);
        listenSocket.Bind(ep);

        while (true)
        {
            offset = 0;
            numOfBytesRecieved = -1;
            incomingBytes = new Byte[300000];

            // start listening
            listenSocket.Listen(1);

            //Received a connection
            connection = listenSocket.Accept();

            //Get all the data from the connection stream
            while (numOfBytesRecieved != 0)
            {
                numOfBytesRecieved = connection.Receive(incomingBytes, offset, 10000, SocketFlags.None);

                offset += numOfBytesRecieved;
            }

            data = new Byte[offset];
            Array.Copy(incomingBytes, data, offset);

            //Send image to the UI
            xaml_incomingTextBox.Dispatcher.BeginInvoke(displayIncomingVideo, data);

            connection.Close();
        }
    }//end of keepListeningForVideoMessages


    private void SendVideoMsg(object sender, RoutedEventArgs e)
    {
        xaml_incomingVideo.Visibility   = Visibility.Visible;
        xaml_StopVideoButton.Visibility = Visibility.Visible;
        xaml_SendTextButton.Visibility  = Visibility.Hidden;
        webcam.Start(); 
    }


    private void StopVideoMsg(object sender, RoutedEventArgs e)
    {
        xaml_incomingVideo.Visibility   = Visibility.Hidden;
        xaml_StopVideoButton.Visibility = Visibility.Hidden;
        xaml_SendTextButton.Visibility  = Visibility.Visible;
        webcam.Stop();
    }

}//end of Class
}//end of NameSpace

最佳答案

您应该尝试下载 NAudio,它是一个开源音频库。它附带了一个关于如何使用 UDP 将音频从一台电脑传输到另一台电脑的演示;它在名为“网络聊天”的 NAudioDemo 应用程序中。

http://naudio.codeplex.com/

您目前使用的 TCP 并不真正推荐用于音频。改用UDP

http://www.onsip.com/about-voip/sip/udp-versus-tcp-for-voip

或者,如果您不想重新发明轮子(我不确定您项目的最终目标是什么),您可以尝试下载我们的 iConf.NET 视频 session SDK,它可以为您完成大部分工作(但不是免费的)

http://avspeed.com/

关于c# - 尝试通过 TCP 传输 2 路音频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20457915/

有关c# - 尝试通过 TCP 传输 2 路音频?的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  5. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  6. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  7. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  8. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  9. 通过 MacPorts 的 RubyGems 是个好主意吗? - 2

    从MB升级到新的MBP后,Apple的迁移助手没有移动我的gem。我这次是通过macports安装ruby​​gems,希望在下次升级时避免这种情况。有什么我应该注意的陷阱吗? 最佳答案 如果你想把你的gems安装在你的主目录中(在传输过程中应该复制过来,作为一个附带的好处,会让你以你自己的身份运行geminstall,而不是root),将gemhome:键设置为您在~/.gemrc中的主目录中的路径. 关于通过MacPorts的RubyGems是个好主意吗?,我们在StackOverf

  10. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

随机推荐