TcpClient或HttpWebRequest到Apple TV在30秒后结束? [英] TcpClient or HttpWebRequest to Apple TV ending after 30 seconds?

查看:103
本文介绍了TcpClient或HttpWebRequest到Apple TV在30秒后结束?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用C#创建一个库,以使用Airplay协议将照片和视频发送到我的Apple TV(专门与第3代一起使用,但希望对此无关紧要).

I'm working on creating an Library in C# to use the Airplay protocol to send Photos and Video to my Apple TV (Specifically working with Generation 3 but hopefully that should not matter for this).

https://airlib.codeplex.com/

按照以下规范,所有用于Airplay的命令都是端口70上的HTTP: http://nto.github.com/AirPlay.html

All of the commands for Airplay are HTTP on port 70 as per this spec: http://nto.github.com/AirPlay.html

我已经成功地使照片和视频都可以在Apple TV上播放,但是无论我做什么,AppleTV只能播放30秒的视频.似乎我发出发出play命令的C#客户端在30秒时断开连接,这导致AppleTV结束了播放会话.

I have been successful at getting both photos and video to play on the Apple TV, but no matter what I do the AppleTV will only play 30 seconds worth of video. It appears as though my C# client that issues the play command is disconnecting right at 30 seconds, which causes the AppleTV to end the play session.

为什么我这么认为:

  • 完全终止客户端应用程序会产生与等待30秒相同的行为(本质上是强制关闭连接).
  • 手动关闭HttpWebRequest或TcpClient连接会产生相同的行为(播放会话中途).
  • 无论我将断点保持多长时间以防止GetResponse()调用,视频始终在WebRequest开始发送消息后30秒超时.
  • 为视频使用其他来源(IIS,外部网络服务器)不会改变行为.
  • 即使视频已缓存到AppleTV上并且不重新传输,超时仍然会发生.

我非常确定,在视频的整个播放"过程中,客户请求都需要保持连接状态,据我所知,我已经对此进行了编码.我真是机智.我已经尝试了所有我能想到的一切,包括将请求作为HttpWebRequest和原始TcpClient(它们都可以工作,但都超时),将Recieve/Send超时设置为疯狂的数字,并循环读取Tcp流确保存在活动".

I'm pretty sure that the client request needs to stay connected throughout the "play" of the video, and to the best of my knowledge I have coded it to do that. I really am at my wits end. I have tried everything that I can think of including doing the request both as a HttpWebRequest and as a raw TcpClient (which both work but both time out), setting the Recieve/Send timeouts to crazy numbers, and looping the read of the Tcp stream to ensure that there is "activity".

好像AppleTV希望我发送嘿,继续播放"消息,但是我还没有从网络上的任何来源看到类似的消息.我希望基于我对Http/Tcp的了解,这简直就是我没有做的愚蠢事情.

Its as though the AppleTV is expecting me to send a "hey, keep playing" message, but I have yet to see anything like that from any source on the web. I'm hoping that this is simply something stupid that I'm not doing based on my lack of Http/Tcp knowledge.

这是我的代码:

    Uri url = "http://somevideo.com/video.mov";
    float startPosition = 0;        
    TcpClient tcpClient = new TcpClient("192.168.1.20",7000);
    tcpClient.ReceiveTimeout = 100000;
    tcpClient.SendTimeout = 100000;

    //get the client stream to read data from.
    NetworkStream clientStream = tcpClient.GetStream();

     string body = 
    "Content-Location: " + url + "\n" +
    "Start-Position: " + startPosition + "\n";

    string request = "POST /play HTTP/1.1\n" + 
    "User-Agent: MediaControl/1.0\n" +
    "Content-Type: text/parameters\n" +
    "Content-Length: " + Encoding.ASCII.GetBytes(body).Length + "\n" +           
    "X-Apple-Session-ID:" + _sessionGuid.ToString() + "\n\n";

    sendMessage(clientStream, request);
    sendMessage(clientStream, body);

    byte[] myReadBuffer = new byte[1024];
    StringBuilder myCompleteMessage = new StringBuilder();
    int numberOfBytesRead = 0;

    //incoming message might be bigger than the buffer
    do
    {
        try
        {
            numberOfBytesRead = clientStream.Read(myReadBuffer, 0, myReadBuffer.Length);
            myCompleteMessage.Append(Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
            Thread.Sleep(10);//let the iOS device catch up sending data
        }
        catch (System.IO.IOException) { }
    } while (tcpClient.Connected); //check if it's connected before checking for data available, as maybe the program might get quit and the sockets closed halfway through a read

注意:使用telnet,我可以在端口7000上连接到AppleTV,并粘贴此命令来播放整个视频:

Note: using telnet I am able to connect to the AppleTV on port 7000 and paste in this command which plays the entire video:

POST /play HTTP/1.1
User-Agent: MediaControl/1.0
Content-Type: text/parameters
Content-Length: 89
X-Apple-Session-ID:fb6d816a-a5ad-4e8f-8830-9642b6e6eb35

Content-Location: http://192.168.1.11:82/2012/2012_03_11/IMG_1328.MOV
Start-Position: 0

我正在端口82上运行Cassini Web服务器,但这也适用于IIS.这提供了进一步的证据,表明.Net堆栈在30秒内在引擎盖下执行某些操作导致断开连接.

I'm running the Cassini Webserver on port 82, but this also works with IIS. This offers further evidence that the .Net stack is doing something under the hood at 30 seconds that causes a disconnect.

推荐答案

我终于明白了.不是.Net代码终止了连接,而是Apple TV本身.通过Wireshark,在30秒钟内未在该连接上收到任何新消息后,我可以看到来自AppleTV的正确的Ack和Fin消息.为了解决该问题,我通过使用Telnet进行了摸索,发现AppleTV似乎并不在乎您发送的内容,只要您定期发送某些内容即可,这似乎可以使连接保持活动状态.

I figured it out finally. It wasn't the .Net code killing the connection, it was the Apple TV itself. With wireshark I was able to see the proper Ack and Fin messages which were from the AppleTV after 30 seconds of not recieving any new messages on that connection. To solve the problem I figured out by playing around with Telnet that the AppleTV doesn't seem to care what you send it as long as you send it SOMETHING on a periodic basis, which seems to keep the connection alive.

使用HttpWebRequest时,发送/接收部分相当固定.它是为标准的Http请求和响应而设计的,如果您需要执行其他任何操作,则只需启动一个新的HttpWebRequest而不使用现有的HttpWebRequest即可.尝试在相同的HttpWebRequest错误上发送第二条消息.

With HttpWebRequest the send/recieve portion is pretty canned. Its designed for a standard Http request and response, and if you need to do anything else you simply start a new HttpWebRequest rather than use the existing one. Trying to send a 2nd message on the same HttpWebRequest errors out.

因此,我不得不使用TcpClient,并且必须重做结尾.

So I had to use a TcpClient, and had to rework the end.

    /// <summary>
    /// Starts a video.
    /// </summary>
    /// <param name="url">The URL of the video to play.</param>
    /// <param name="startPosition">The start position of the video. This value must be between 0 and 1</param>
    public void StartVideo(Uri url, float startPosition = 0)
    {
        if (startPosition > 1)
        {
            throw new ArgumentException("Start Position must be between 0 and 1");
        }

        TcpClient tcpClient = new TcpClient("192.168.1.20", 7000);
        tcpClient.ReceiveTimeout = 100000;
        tcpClient.SendTimeout = 100000;

        //get the client stream to read data from.
        NetworkStream clientStream = tcpClient.GetStream();

        string body =
       "Content-Location: " + url + "\n" +
       "Start-Position: " + startPosition + "\n";

        string request = "POST /play HTTP/1.1\n" +
        "User-Agent: MediaControl/1.0\n" +
        "Content-Type: text/parameters\n" +
        "Content-Length: " + Encoding.ASCII.GetBytes(body).Length + "\n" +
        "X-Apple-Session-ID:" + _sessionGuid.ToString() + "\n\n";

        //Send the headers
        sendMessage(clientStream, request);
        //Send the body
        sendMessage(clientStream, body);

        //Get the response
        byte[] myReadBuffer = new byte[1024];
        StringBuilder myCompleteMessage = new StringBuilder();
        int numberOfBytesRead = 0;
        numberOfBytesRead = clientStream.Read(myReadBuffer, 0, myReadBuffer.Length);
        myCompleteMessage.Append(Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

        //Now start doing a "keepalive"
        while (true)
        {
            //Simply send the characters "ok" every two seconds
            sendMessage(clientStream, "ok");
            Thread.Sleep(2000);
        }                      
    }

    /// <summary>
    /// Sends a message across the NetworkStream
    /// </summary>
    /// <param name="clientStream">The stream to send the message down</param>
    /// <param name="message">The message to send</param>
    public void sendMessage(NetworkStream clientStream, string message)
    {
        byte[] buffer = new ASCIIEncoding().GetBytes(message);
        try
        {
            clientStream.Write(buffer, 0, buffer.Length);
            clientStream.Flush();
        }
        catch (System.IO.IOException e)
        {
            Debug.WriteLine("IOException: " + e.Message);
        }
    }

显然,这不是最终的答案,但这是使它正常工作的最低要求.如果有人知道实际的Apple硬件代替确定"发送的是什么,请添加注释.

Obviously this is not the final answer, but this was the bare minimum to get it to work. If anybody figures out what the actual Apple hardware is sending in place of the "ok" please add a note.

这篇关于TcpClient或HttpWebRequest到Apple TV在30秒后结束?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆