Skip to content

putMedia Request using c#

0

Hi there, I have setup my dotnet core code as following. But I am getting exception on sending request ***Error while copying content to a stream. Inner Exception: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.. ***---code

using Amazon;
using Amazon.Kinesis;
using Amazon.Kinesis.Endpoints;
using Amazon.KinesisVideo;
using Amazon.KinesisVideo.Model;
using Amazon.Runtime;
using Amazon.Runtime.Internal;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

public class KinesisVideoUploader
{
    private static readonly string awsAccessKeyId = "ACCESS_KEY_HERE";
    private static readonly string awsSecretAccessKey = "SECRET_KEY_HERE"; 
    private static readonly RegionEndpoint region = RegionEndpoint.EUWest2; 
    private static readonly string streamName = "dev-video-stream"; 
    private static readonly string filePath = "2022-11-23-19-41-10.mkv";
    private static string streamARN; 
    
    public static async Task UploadVideoStreamAsync()
    {
        var credentials = new BasicAWSCredentials(awsAccessKeyId, awsSecretAccessKey);
        AmazonKinesisVideoConfig config = new AmazonKinesisVideoConfig
        {
            RegionEndpoint = region,
            LogMetrics = true 
        };
        var kinesisVideoClient = new AmazonKinesisVideoClient(credentials, config);

        try
        {
            // Checking if the stream is available
            if (!await IsStreamAvailableAsync(kinesisVideoClient, streamName))
            {
                Console.WriteLine("Stream is not available or not in ACTIVE state.");
                return;
            }
            var getDataEndpointRequest = new GetDataEndpointRequest
            {
                StreamName = streamName,
                APIName = APIName.PUT_MEDIA
            };

            var getDataEndpointResponse = await kinesisVideoClient.GetDataEndpointAsync(getDataEndpointRequest);
            var endpoint = getDataEndpointResponse.DataEndpoint;

            Console.WriteLine($"Data Endpoint for PUT_MEDIA: {endpoint}");

            // Construct the PUT_MEDIA URL
            var url = $"{endpoint}/putMedia";
            var httpClientHandler = new HttpClientHandler
            {
                // Bypass SSL certificate validation
                ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true
            };
            System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
            using (var httpClient = new HttpClient(httpClientHandler))
            {
                httpClient.Timeout = TimeSpan.FromMinutes(3); 
                httpClient.DefaultRequestVersion = HttpVersion.Version11; // Use HTTP/1.1 as documented

                using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                 // I even used defined buffer type
                    using (var bufferedStream = new BufferedStream(fileStream))
                    {
                        // Set up the request message
                        var request = new HttpRequestMessage(HttpMethod.Post, url);
                        request.Headers.Add("x-amzn-stream-name", streamName);
                        request.Headers.Add("x-amzn-fragment-timecode-type", "PRODUCER_TIMESTAMP");
                        request.Headers.Add("x-amzn-producer-start-timestamp", DateTime.UtcNow.ToString("o"));
                        request.Headers.Add("x-amzn-fragment-timecode-typ", "RELATIVE");
                        request.Headers.Add("x-amzn-stream-arn", streamARN);
                        var streamContent = new StreamContent(bufferedStream);
                        streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                        Console.WriteLine("streamContent-->" + streamContent.Headers.ContentLength);
                        request.Content = streamContent;

                        // Send the request
                        HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

                        // Handle response
                        if (response.IsSuccessStatusCode)
                        {
                            Console.WriteLine("Video uploaded successfully.");
                        }
                        else
                        {
                            Console.WriteLine($"Failed to upload video. Status Code: {response.StatusCode}, Reason: {response.ReasonPhrase}");
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
            if (ex.InnerException != null)
            {
                Console.WriteLine($"Inner Exception: {ex.InnerException.Message}");
            }
        }
    }

    private static async Task<bool> IsStreamAvailableAsync(AmazonKinesisVideoClient kinesisVideoClient, string streamName)
    {
        try
        {
            var describeStreamRequest = new DescribeStreamRequest
            {
                StreamName = streamName
            };

            var describeStreamResponse = await kinesisVideoClient.DescribeStreamAsync(describeStreamRequest);
            var status = describeStreamResponse.StreamInfo.Status;
            streamARN = describeStreamResponse.StreamInfo.StreamARN;
   
            Console.WriteLine($"Stream status: {status}");

            return status == "ACTIVE";
        }
        catch (ResourceNotFoundException)
        {
            Console.WriteLine("Stream does not exist.");
            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error checking stream availability: {ex.Message}");
            return false;
        }
    }
}

1 Answer
2

Hi,

This error is usually returned by the DotNet runtime when it cannot reach the service endpoint (the Kinesis stream here).

So, I'd suggest that you use the AWS CLI for Kinesis: see https://docs.aws.amazon.com/cli/latest/reference/kinesis-video-media/get-media.html

You can then use the verb get-media via the CLI to check if you can get a media "manually" in the stream. The best place to run this command is from the same machine where your DotNet code runs to check if a security group of your config is blocking access to Kinesis stream from this machine.

But, if it is hard (let's say your code is in a Lambda), you can at least run the CLI command from desktop to get a first check.

Best,

Didier

EXPERT
answered a year ago
EXPERT
reviewed a year ago
EXPERT
reviewed a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.