发送至 Apple TV 的 TcpClient 或 HttpWebRequest 在 30 秒后结束?

2023-11-27

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

https://airlib.codeplex.com/

根据此规范,Airplay 的所有命令都是端口 70 上的 HTTP:http://nto.github.com/AirPlay.html

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

我这么认为的原因:

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

我非常确定客户端请求需要在视频的整个“播放”过程中保持连接,并且据我所知,我已经对其进行了编码来做到这一点。我实在是束手无策了。我已经尝试了所有我能想到的方法,包括将请求作为 HttpWebRequest 和原始 TcpClient 进行请求(两者都有效,但都超时),将接收/发送超时设置为疯狂的数字,以及循环读取 Tcp 流确保有“活动”。

就好像 AppleTV 期望我发送一条“嘿,继续玩”消息,但我还没有从网络上的任何来源看到类似的消息。我希望这只是一些愚蠢的事情,因为我缺乏 Http/Tcp 知识,所以我没有这样做。

这是我的代码:

    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 并粘贴此命令来播放整个视频:

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 Webserver,但这也适用于 IIS。这进一步证明 .Net 堆栈在 30 秒内做了一些导致断开连接的事情。


我终于明白了。终止连接的不是 .Net 代码,而是 Apple TV 本身。使用wireshark,我能够看到正确的Ack 和Fin 消息,这些消息是在该连接上30 秒没有收到任何新消息后来自AppleTV 的。为了解决这个问题,我通过使用 Telnet 发现 AppleTV 似乎并不关心你发送的内容,只要你定期向它发送一些东西,这似乎可以保持连接处于活动状态。

对于 HttpWebRequest,发送/接收部分是相当固定的。它是为标准 Http 请求和响应而设计的,如果您需要做任何其他事情,您只需启动一个新的 HttpWebRequest 而不是使用现有的。尝试在同一个 HttpWebRequest 上发送第二条消息会出错。

所以我不得不使用TcpClient,并且不得不重新处理最后的事情。

    /// <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 硬件发送的是什么来代替“ok”,请添加注释。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

发送至 Apple TV 的 TcpClient 或 HttpWebRequest 在 30 秒后结束? 的相关文章

随机推荐

  • 在 Windows 上为 Mac OS X 开发?

    嗯 简单的情况 我碰巧是一名软件工程师 主要使用 Delphi 和 C 进行软件开发 Delphi 非常适合桌面应用程序 而 C 则非常适合与 ASP NET 结合用于 Web 应用程序 不过 我正在考虑自学更多有关 Mac 软件开发的知识
  • 在 Internet Explorer 中查看 HttpOnly 会话 cookie

    使用 Internet 选项 我可以看到所有持久 cookie 使用开发人员工具 我可以看到所有 JS 可访问的会话 cookie 似乎没有办法查看 HTTPOnly 会话 cookie 在 Firefox 中 有许多选项 内置选项和 Fi
  • 如何从android代码中知道路由器的IP地址?

    如何从代码中找到路由器的IP地址 网关地址 WifiInfo getIpAddress 返回设备的 IP 地址 在 shell 命令中 ipconfig 不返回任何值 这是我的解决方案 但如果有更好的方法 请告诉我 WifiManager
  • Matplotlib 按分类因素散布颜色

    我有一个基本的散点图 其中 x 和 y 是浮动的 但我想根据第三个分类变量更改标记的颜色 分类变量是字符串形式 这似乎引起了一个问题 要使用 iris 数据集 这是我想我会使用的代码 Scatter of Petal x df Petal
  • 去模板名称

    In the html template and text template 包 template New有以下签名 func New name string Template 到底是什么name用于 我已经扫描了文档 以及一些源代码 但无
  • 是否可以在主机上运行部分作业,在从机上运行另一部分?

    我是詹金斯的新手 我有一个要求 我需要在主节点上运行部分作业 而在从属节点上运行其余部分 我尝试在论坛上搜索 但找不到与此相关的任何内容 是否有可能做到这一点 如果没有 我将不得不将其分成两个单独的工作 EDIT 基本上我的工作是从 svn
  • MAC地址在C代码中的表示

    我经常在 C 代码中看到这样的 MAC 地址表示 struct mac addr unsigned char bytes 6 为什么需要将数组放入结构体中 为什么不直接使用数组呢 这有什么好处 Thanks 您不能在 C 中分配数组 但可以
  • 警告:缺少参数 1

    我的 php 代码遇到一些问题 所有信息都返回 但我无法弄清楚为什么会收到错误 对于我的索引页 我只包含了实际使用该类的代码行 除了一些包含之外 实际上没有其他代码 我确信这就是我构建 contstruct 的方式 但我不确定这样做的适当方
  • 向左而不是向右溢出

    我有一个 divoverflow hidden 其中我在用户键入时显示电话号码 div 内的文本向右对齐 并且当文本向左增长时 传入字符将添加到右侧 但是 一旦文本太大而无法放入 div 中 数字的最后一个字符将被自动裁剪 用户将无法看到她
  • Paypal 嵌入式流程不使用 returnUrl 或 cancelUrl

    我正在使用 Paypals 自适应支付和嵌入式流程功能通过迷你浏览器提供结账服务 在沙箱环境中 一切似乎都工作正常 除了付款成功完成后 用户永远不会重定向到我在 PAY API 请求中设置的 returnUrl 我的cancelUrl 也是
  • React Apollo 客户端不发送 cookie

    我尝试按照 Apollo 客户端上的说明与 graphql 请求一起发送 cookie 但是 Express 服务器没有收到任何 cookie 并且当我检查请求时 它显示没有随响应一起发送 cookie 关注此页面 https www ap
  • 使用 util 模式自动装配列表会出现 NoSuchBeanDefinitionException

    我有一个 bean 我想使用 Spring util 命名空间注入一个命名列表
  • 如何使用 Sprite Kit 在 iOS 中创建 alpha 遮罩

    我想要达到的效果是在黑暗区域中有一个光圈 其效果类似于口袋妖怪游戏中的效果 当你处于黑暗的洞穴中并且周围的视野有限时 根据我的尝试和阅读 我无法在具有 alpha 级别的精灵套件中的节点上创建遮罩 我设法创建的蒙版都有硬边 而且基本上只是裁
  • ANTLR4:如何读取字符串中的双引号转义双引号?

    在ANTLR v4中 我们如何像VBA中那样解析这种带有双引号转义双引号的字符串 对于文本 some string with john doe in it 目标是识别字符串 some string with john doe in it 是
  • 我收到这个错误! [函数外的“return”语句]

    我正在为客户创建一个表单验证器并遇到这个奇怪的错误only在 Internet Explorer 资源管理器 7 8 中 函数外部的 return 第 1 行 字符 1 当然 第一行没有任何代码 这是一个简单的注释语句 无论如何 这并没有什
  • Java Hashmap:如何从值中获取键?

    如果我有这个价值 foo and a HashMap
  • Matlab GUI 应用程序中的软件工程和模式? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我被要求使用 Matlab 和 GUIDE 开发一个简单的 GUI 应用程序 它将与单独的后端引擎 也是 Matlab 交互 我有 Java 和 Net 背景 Matlab 文档
  • 将 google 时区转换为 .net 时区

    我正在使用这个 string url string Format https maps googleapis com maps api timezone json location 0 1 timestamp 1374868635 sens
  • 修改std::map的键

    有没有办法修改a的keystd map or 这个例子展示了如何通过重新平衡树来做到这一点 但是如果我提供一些保证密钥不需要重新平衡呢 include
  • 发送至 Apple TV 的 TcpClient 或 HttpWebRequest 在 30 秒后结束?

    我正在努力用 C 创建一个库 以使用 Airplay 协议将照片和视频发送到我的 Apple TV 特别是与第 3 代一起使用 但希望这对此无关紧要 https airlib codeplex com 根据此规范 Airplay 的所有命令