TcpClient or HttpWebRequest for Apple TV ending in 30 seconds?

I am working on creating a library in C # to use the Airplay protocol to send photos and videos to Apple TV (in particular, working with generation 3, but I hope this does not matter for this).

https://airlib.codeplex.com/

All commands for Airplay are HTTP on port 70 according to this specification: http://nto.github.com/AirPlay.html

I managed to get both photos and videos on Apple TV, but no matter what I do, AppleTV will only play 30 seconds of video. It seems that my C # client, which issues a playback command, disconnects immediately for 30 seconds, which causes AppleTV to end the playback session.

Reasons why I think so:

  • Termination of the client application completely leads to the same behavior as expected 30 seconds (essentially, to close the connection).
  • Manually closing the HttpWebRequest or TcpClient connection results in the same behavior (halfway through the playback session).
  • No matter how long I hold the breakpoint to prevent GetResponse () from being called, the video always plays out 30 seconds after the start of sending the WebRequest message.
  • Using a different source (IIS, an external web server) for the video does not change the behavior.
  • Even after the video is cached on AppleTV and does not restart the timeout, everything still happens.

, "" , , , . . , , 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 connected before checking for data available, as maybe the program might get quit and the sockets closed halfway through a read

: telnet, AppleTV 7000 , :

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

- Cassini 82, IIS. , .Net - 30 , .

+5
1

, . .Net, , Apple TV. wirehark Ack Fin, AppleTV 30 , . , , Telnet, Apple TV, , , , SOMETHING , , , .

HttpWebRequest / . Http, - , HttpWebRequest, . 2- 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", .

+5

All Articles