Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEVX-6497 - Add Experience Composer to the OpenTok .NET Server SDK #210

Merged
merged 23 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c970f12
Create object and implement parsing for StartRender operation
Tr00d Oct 10, 2022
cd9aefd
Fix wrong allowed resolution
Tr00d Oct 11, 2022
173df32
Implement request creation with various values, including optional ones
Tr00d Oct 11, 2022
904a94e
Fix warning for http (test value)
Tr00d Oct 11, 2022
40d116f
Kill last mutants for threshold values
Tr00d Oct 11, 2022
cc54256
Implement POST call to start a rendering
Tr00d Oct 11, 2022
0a61c47
Make StartRenderResponse immutable
Tr00d Oct 11, 2022
51eacef
Implement StopRenderAsync
Tr00d Oct 11, 2022
06e5a8f
Implement ListRendersRequest parsing
Tr00d Oct 11, 2022
a987a01
Kill mutants for http headers
Tr00d Oct 11, 2022
207afdf
Fix type in ListRenders
Tr00d Oct 12, 2022
d1ebd59
Implement ListRendersAsync
Tr00d Oct 12, 2022
4bc7979
Implement GetRenderAsync
Tr00d Oct 13, 2022
761d2a4
Kill mutants on StartRenderRequest, make all responses as struct for …
Tr00d Oct 13, 2022
b9ec758
Fix request formatting issue - last test round
Tr00d Nov 10, 2022
e688ddf
Add missing Xml comments
Tr00d Nov 10, 2022
24fe82a
Amend TODO comments
Tr00d Nov 28, 2022
3e778c9
Experience Composer Render API docs edits
jeffswartz Jan 5, 2023
e1427a1
Make ScreenResolutionConverter private
Tr00d Jan 5, 2023
e257b45
Rename ScreenResolution into RenderResolution
Tr00d Jan 5, 2023
5716fc6
Remove StatusCallbackUrl
Tr00d Jan 5, 2023
b0a8f05
Make StreamName optional, expect a PublisherProperties when creating …
Tr00d Jan 5, 2023
d1cad77
Merge branch 'dev' into devx-6497-branchfix
Tr00d Jan 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions OpenTok/OpenTok.Render.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using OpenTokSDK.Render;

namespace OpenTokSDK
{
public partial class OpenTok
{
private const string RenderEndpoint = "/render";

/// <summary>
/// Starts a new Experience Composer renderer for an OpenTok session.
/// </summary>
/// <para>
/// For more information, see the .
/// <a href="https://tokbox.com/developer/guides/experience-composer/">Experience Composer developer guide</a>.
/// </para>
/// <param name="request">The rendering request.</param>
/// <returns>The generated rendering.</returns>
public async Task<RenderItem> StartRenderAsync(StartRenderRequest request)
{
var response = await this.Client.PostAsync(
this.BuildUrl(RenderEndpoint),
GetHeaderDictionary("application/json"),
request.ToDataDictionary());
return JsonConvert.DeserializeObject<RenderItem>(response);
}

/// <summary>
/// Stops an Experience Composer renderer.
/// </summary>
/// <param name="renderId">The Id of the rendering.</param>
public async Task StopRenderAsync(string renderId) =>
await this.Client.DeleteAsync(
this.BuildUrlWithRouteParameter(RenderEndpoint, renderId),
new Dictionary<string, string>());

/// <summary>
/// Retrieves all Experience Composer renderers matching the provided request.
/// </summary>
/// <param name="request">The request containing filtering options.</param>
/// <returns>The list of rendering.</returns>
public async Task<ListRendersResponse> ListRendersAsync(ListRendersRequest request)
{
var url = this.BuildUrlWithQueryParameter(RenderEndpoint, request.ToQueryParameters());
var response = await this.Client.GetAsync(url);
return JsonConvert.DeserializeObject<ListRendersResponse>(response);
}

/// <summary>
/// Retrieves an Experience Composer renderer.
/// </summary>
/// <param name="renderId">The Id of the rendering.</param>
public async Task<RenderItem> GetRenderAsync(string renderId)
{
var url = this.BuildUrlWithRouteParameter(RenderEndpoint, renderId);
var response = await this.Client.GetAsync(url);
return JsonConvert.DeserializeObject<RenderItem>(response);
}

private string BuildUrl(string endpoint) => $"v2/project/{this.ApiKey}{endpoint}";

private string BuildUrlWithRouteParameter(string endpoint, string routeParameter) =>
$"{this.BuildUrl(endpoint)}/{routeParameter}";

private string BuildUrlWithQueryParameter(string endpoint, string queryParameter) =>
$"{this.BuildUrl(endpoint)}?{queryParameter}";

private static Dictionary<string, string> GetHeaderDictionary(string contentType) =>
new Dictionary<string, string> {{"Content-Type", contentType}};
}
}
2 changes: 1 addition & 1 deletion OpenTok/OpenTok.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace OpenTokSDK
/// (only on your web server) to create OpenTok sessions.
/// </para>
/// </summary>
public class OpenTok
public partial class OpenTok
{
/// <summary>
/// The OpenTok API key passed into the OpenTok() constructor.
Expand Down
1 change: 1 addition & 0 deletions OpenTok/OpenTok.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Enums.NET" Version="4.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
Expand Down
115 changes: 115 additions & 0 deletions OpenTok/Render/ListRendersRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using OpenTokSDK.Exception;

namespace OpenTokSDK.Render
{
/// <summary>
/// Represents a request for retrieving Experience Composer renderers.
/// (<see cref="OpenTok.ListRendersAsync"/>).
/// </summary>
public class ListRendersRequest
{
private const int DefaultCount = 50;
private const int MaximumCount = 1000;
private const int MinimumCount = 0;
private const int MinimumOffset = 0;

/// <summary>
/// Indicates the maximum count has been exceeded.
/// </summary>
public const string CountExceeded = "Count cannot be higher than 1000.";

/// <summary>
/// Indicates the provided count is negative.
/// </summary>
public const string NegativeCount = "Count cannot be negative.";

/// <summary>
/// Indicates the provided offset is negative.
/// </summary>
public const string NegativeOffset = "Offset cannot be negative.";

/// <summary>
/// Initializes a ListRendersRequest with default values. The Count is set to 50.
/// </summary>
public ListRendersRequest()
{
this.Count = DefaultCount;
}

/// <summary>
/// Initializes a ListRendersRequest.
/// </summary>
/// <param name="count">
/// The number of Renders to retrieve starting at the offset. The default is 50, and the maximum is 1000.
/// </param>
public ListRendersRequest(int count)
: this()
{
ValidateCount(count);
this.Count = count;
}

/// <summary>
/// Initializes a ListRendersRequest.
/// </summary>
/// <param name="offset">
/// The start offset in the list of existing Renders.
/// </param>
/// <param name="count">
/// The number of Renders to retrieve, starting at offset. The default is 50, and the maximum is 1000.
/// </param>
public ListRendersRequest(int offset, int count)
: this(count)
{
ValidateOffset(offset);
this.Offset = offset;
this.Count = count;
}

/// <summary>
/// The start offset in the list of existing Renders.
/// </summary>
public int? Offset { get; }

/// <summary>
/// The number of Renders to retrieve, starting at offset.
/// </summary>
public int Count { get; }

private static void ValidateCount(int count)
{
if (count > MaximumCount)
{
throw new OpenTokException(CountExceeded);
}

if (count < MinimumCount)
{
throw new OpenTokException(NegativeCount);
}
}

private static void ValidateOffset(int offset)
{
if (offset < MinimumOffset)
{
throw new OpenTokException(NegativeOffset);
}
}

/// <summary>
/// Converts the request to query parameters.
/// </summary>
/// <returns>The query parameters equivalent.</returns>
public string ToQueryParameters()
{
var parameters = $"count={this.Count}";
if (this.Offset.HasValue)
{
parameters += $"&offset={this.Offset}";
}

return parameters;
}
}
}
32 changes: 32 additions & 0 deletions OpenTok/Render/ListRendersResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Collections.Generic;

namespace OpenTokSDK.Render
{
/// <summary>
/// Represents a response from a ListRenders
/// <see cref="OpenTok.ListRendersAsync"/> request.
/// </summary>
public struct ListRendersResponse
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="count">The total number of Renders.</param>
/// <param name="items">The list of renderings items.</param>
public ListRendersResponse(int count, IEnumerable<RenderItem> items)
{
this.Count = count;
this.Items = items;
}

/// <summary>
/// Number of rendering items.
/// </summary>
public int Count { get; set; }

/// <summary>
/// Rendering items contained in the response.
/// </summary>
public IEnumerable<RenderItem> Items { get; set; }
}
}
92 changes: 92 additions & 0 deletions OpenTok/Render/RenderItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using Newtonsoft.Json;

namespace OpenTokSDK.Render
{
/// <summary>
/// Represents a rendering.
/// </summary>
public struct RenderItem
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="id">The ID of the rendering.</param>
/// <param name="sessionId">The session ID.</param>
/// <param name="projectId">The project ID.</param>
/// <param name="createdAt">The creation date.</param>
/// <param name="updatedAt">The last update date.</param>
/// <param name="url">The URL.</param>
/// <param name="resolution">The screen resolution.</param>
/// <param name="status">The status.</param>
/// <param name="streamId">The stream ID.</param>
/// <param name="reason">The reason.</param>
public RenderItem(string id, string sessionId, string projectId, int createdAt, int updatedAt, Uri url,
RenderResolution resolution, string status, string streamId, string reason)
{
this.Id = id;
this.SessionId = sessionId;
this.ProjectId = projectId;
this.CreatedAt = createdAt;
this.UpdatedAt = updatedAt;
this.Url = url;
this.Resolution = resolution;
this.Status = status;
this.StreamId = streamId;
this.Reason = reason;
}

/// <summary>
/// The ID of the rendering.
/// </summary>
public string Id { get; set; }

/// <summary>
/// The session ID.
/// </summary>
public string SessionId { get; set; }

/// <summary>
/// The project ID.
/// </summary>
public string ProjectId { get; set; }

/// <summary>
/// The creation date.
/// </summary>
public double CreatedAt { get; set; }

/// <summary>
/// The last update date.
/// </summary>
public double UpdatedAt { get; set; }

/// <summary>
/// The URL.
/// </summary>
public Uri Url { get; set; }

/// <summary>
/// The Experience Composer renderer resolution.
/// </summary>
[JsonConverter(typeof(RenderResolutionConverter))]
public RenderResolution Resolution { get; set; }

/// <summary>
/// The status.
/// </summary>
public string Status { get; set; }

/// <summary>
/// The stream ID.
/// </summary>
public string StreamId { get; set; }

/// <summary>
/// The reason, when the status is either "stopped" or "failed". If the status is "stopped",
/// the reason field will contain either "Max Duration Exceeded" or "Stop Requested."
/// If the status is "failed", the reason will contain a more specific error message.
/// </summary>
public string Reason { get; set; }
}
}
40 changes: 40 additions & 0 deletions OpenTok/Render/RenderResolution.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.ComponentModel;

namespace OpenTokSDK.Render
{
/// <summary>
/// Enum for representing resolutions with orientation.
/// </summary>
public enum RenderResolution
{
/// <summary>
/// Standard definition (SD) resolution with landscape orientation (640x480)
/// </summary>
[Description("640x480")] StandardDefinitionLandscape,

/// <summary>
/// Standard definition (SD) resolution with portrait orientation (480x640)
/// </summary>
[Description("480x640")] StandardDefinitionPortrait,

/// <summary>
/// High definition (HD) resolution with landscape orientation (1280x780)
/// </summary>
[Description("1280x720")] HighDefinitionLandscape,

/// <summary>
/// High definition (HD) resolution with portrait orientation (780x1280)
/// </summary>
[Description("720x1280")] HighDefinitionPortrait,

/// <summary>
/// Full high definition (FHD) resolution with landscape orientation (1920x1080)
/// </summary>
[Description("1920x1080")] FullHighDefinitionLandscape,

/// <summary>
/// Full high definition (FHD) resolution with portrait orientation (1080x1920)
/// </summary>
[Description("1080x1920")] FullHighDefinitionPortrait,
}
}
Loading