1
votes

I am creating a Silverlight application that utilizes an H.264 MediaStreamSource implementation in order to stream live video from a server. I have a Multipart streamer that I wrote that reads the samples frame by frame.

When I connect to a server running on my local machine, it takes 12 seconds to read the second byte from the response stream in the ReadHeaders() function. So basically it connects to the host instantly, reads one byte successfully, the subsequent ReadByte() blocks (if you look at where the call stack is it is in another thread at: System.Windows.dll!MS.Internal.InternalNetworkStream.ReadOperation(object state)). Every time I test this it consistently takes the 12 seconds. Once this time has passed, all subsequent reads are immediate and the application runs great. If I use this same code in just a simple .NET console application, there is no 12 second delay.

Any idea what could be causing this?

        byte[] imgBuf = new byte[ChunkSize * ChunkSize];
        HttpWebRequest req = (HttpWebRequest)res.AsyncState;
        int contentLength = 0;
        try
        {
            HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(res);
            // notify delegate of main headers

            // get the response stream and start reading
            BinaryReader reader = new BinaryReader(resp.GetResponseStream());
            Dictionary<string, string> headers;
            while (m_Running)
            {
                // read multipart response headers and notify delegate
                headers = ReadHeaders(reader);

                // check if end of stream
                if (headers.ContainsKey(CustomHeaders.EndOfStreamHeader) 
                    && headers[CustomHeaders.EndOfStreamHeader] != null
                    && String.Compare(headers[CustomHeaders.EndOfStreamHeader], "yes") == 0)
                {
                    // notify delegate if end of stream has been reached
                }
                // determine length of data to read
                string cl = headers["Content-Length"];
                if (cl != null)
                {
                    contentLength = Int32.Parse(cl);
                }
                byte[] data = reader.ReadBytes(contentLength);

                if (data.Length > 0)
                {
                    // notify delegate of multipart data
                }
                // Yield to other threads waiting to be executed
                System.Threading.Thread.Sleep(1);
            }
            reader.Close();
            resp.Close();
            req.Abort();
        }
        catch (Exception ex)
        {
            // notify delegate of any errors that occurred
        }

The ReadHeaders() function:

    private Dictionary<string, string> ReadHeaders(BinaryReader reader)
    {
        List<byte> buffer = new List<byte>();
        while (m_Running)
        {
            buffer.Add(reader.ReadByte());
            if (buffer.EndsWith(EndOfHeaderBytes))
            {
                break;
            }
            // Yield to other threads waiting to be executed
            System.Threading.Thread.Sleep(1);
        }
        return buffer.ToHeadersDictionary();
    }

Edit: Here is the call stack of the two threads.

Worker Thread Worker Thread GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders Normal [In a sleep, wait, or join]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x21 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x21 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x1f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0x10 bytes
System.Windows.dll!MS.Internal.InternalNetworkStream.EndRead(System.IAsyncResult asyncResult) + 0x40 bytes
System.Windows.dll!MS.Internal.InternalNetworkStream.Read(byte[] buffer, int offset, int count) + 0x38 bytes
mscorlib.dll!System.IO.Stream.ReadByte() + 0x28 bytes
mscorlib.dll!System.IO.BinaryReader.ReadByte() + 0x1d bytes
GenIIIWebClient!GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders(System.IO.BinaryReader reader) Line 201 + 0x19 bytes
GenIIIWebClient!GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.OnGetResponse(System.IAsyncResult res) Line 126 + 0xf bytes
System.Windows.dll!System.Net.Browser.ClientHttpWebRequest.InvokeGetResponseCallback.AnonymousMethod__18(object state2) + 0x11 bytes
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state) + 0x3e bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x97 bytes
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x5a bytes
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x1b3 bytes
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x5 bytes
[Native to Managed Transition]
[Appdomain Transition]
[Native to Managed Transition]

Unflagged 5096 5 Worker Thread Worker Thread [In a sleep, wait, or join] Normal [In a sleep, wait, or join]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x21 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x21 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x1f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0x10 bytes
System.Windows.dll!MS.Internal.InternalNetworkStream.ReadOperation(object state) + 0x8a bytes
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state) + 0x3e bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x97 bytes
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x5a bytes
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x1b3 bytes
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x5 bytes
[Native to Managed Transition]
[Appdomain Transition]
[Native to Managed Transition]

1

1 Answers

1
votes

It is hard to see the real cause from here but it can be something related to thread management. The first suspect I see here is m_Running. Focus on that. Maybe some threading stuffs vary for the types of projects.

Have you tried using a waitHandle instead of giving a Sleep(1),

ManualResetEvent waitHandle = new ManualResetEvent(false);

while(true)
{
  waitHandle.Wait();
  waitHandle.Reset();

  while(ThereIsAJobToExecute)
 {
    // Process the jobs
    // You should waitHandle.Set() in a callback or when you read it
 }
}

My second offer for the line below is giving an initial list size

List < byte > buffer = new List < byte >();

Initial size for the type List<> DOES NOT mean a limit such an Array size. If you do not give a predefined size List resizes itself. So giving an expected number is a plus.

List<byte> buffer = new List<byte>(1024...etc);