diff --git a/OpenTok/Archive.cs b/OpenTok/Archive.cs
index 249a80c1..909b027a 100644
--- a/OpenTok/Archive.cs
+++ b/OpenTok/Archive.cs
@@ -109,6 +109,7 @@ internal void CopyArchive(Archive archive)
OutputMode = archive.OutputMode;
Resolution = archive.Resolution;
StreamMode = archive.StreamMode;
+ MultiArchiveTag = archive.MultiArchiveTag;
}
///
@@ -201,6 +202,11 @@ internal void CopyArchive(Archive archive)
///
public StreamMode StreamMode { get; set; }
+ ///
+ /// The unique tag for simultaneous archives (if one was set).
+ ///
+ public string MultiArchiveTag { get; set; }
+
///
/// Stops the OpenTok archive if it is being recorded.
///
diff --git a/OpenTok/Broadcast.cs b/OpenTok/Broadcast.cs
index 075623cb..6637c0d0 100644
--- a/OpenTok/Broadcast.cs
+++ b/OpenTok/Broadcast.cs
@@ -91,6 +91,7 @@ internal void CopyBroadcast(Broadcast broadcast)
BroadcastUrls = broadcast.BroadcastUrls;
StreamMode = broadcast.StreamMode;
Settings = broadcast.Settings;
+ MultiBroadcastTag = broadcast.MultiBroadcastTag;
if (BroadcastUrls == null)
return;
@@ -193,6 +194,12 @@ internal void CopyBroadcast(Broadcast broadcast)
///
[JsonProperty("settings")]
public BroadcastSettings Settings { get; set; }
+
+ ///
+ /// The unique tag for simultaneous broadcasts (if one was set).
+ ///
+ [JsonProperty("multiBroadcastTag")]
+ public string MultiBroadcastTag { get; set; }
///
/// Stops the live broadcasting if it is started.
diff --git a/OpenTok/OpenTok.cs b/OpenTok/OpenTok.cs
index e98dbe3e..e8f2064c 100644
--- a/OpenTok/OpenTok.cs
+++ b/OpenTok/OpenTok.cs
@@ -394,10 +394,18 @@ public string GenerateToken(string sessionId, Role role = Role.PUBLISHER, double
/// and
/// methods).
///
+ ///
+ /// Set this to support recording multiple archives for the same session simultaneously.
+ /// Set this to a unique string for each simultaneous archive of an ongoing session.
+ /// You must also set this option when manually starting an archive in a session that
+ /// is automatically archived. If you do not specify a unique multiArchiveTag, you can
+ /// only record one archive at a time for a given session. See
+ /// Simultaneous archives.
+ ///
///
/// The Archive object. This object includes properties defining the archive, including the archive ID.
///
- public Archive StartArchive(string sessionId, string name = "", bool hasVideo = true, bool hasAudio = true, OutputMode outputMode = OutputMode.COMPOSED, string resolution = null, ArchiveLayout layout = null, StreamMode? streamMode = null)
+ public Archive StartArchive(string sessionId, string name = "", bool hasVideo = true, bool hasAudio = true, OutputMode outputMode = OutputMode.COMPOSED, string resolution = null, ArchiveLayout layout = null, StreamMode? streamMode = null, string multiArchiveTag = null)
{
if (string.IsNullOrEmpty(sessionId))
{
@@ -432,6 +440,11 @@ public Archive StartArchive(string sessionId, string name = "", bool hasVideo =
data.Add("layout", layout);
}
+ if (multiArchiveTag is object)
+ {
+ data.Add("multiArchiveTag", multiArchiveTag);
+ }
+
if (streamMode.HasValue)
{
data.Add("streamMode", streamMode.Value.ToString().ToLower());
@@ -496,10 +509,18 @@ public Archive StartArchive(string sessionId, string name = "", bool hasVideo =
/// and
/// methods).
///
+ ///
+ /// Set this to support recording multiple archives for the same session simultaneously.
+ /// Set this to a unique string for each simultaneous archive of an ongoing session.
+ /// You must also set this option when manually starting an archive in a session that
+ /// is automatically archived. If you do not specify a unique multiArchiveTag, you can
+ /// only record one archive at a time for a given session. See
+ /// Simultaneous archives.
+ ///
///
/// The Archive object. This object includes properties defining the archive, including the archive ID.
///
- public async Task StartArchiveAsync(string sessionId, string name = "", bool hasVideo = true, bool hasAudio = true, OutputMode outputMode = OutputMode.COMPOSED, string resolution = null, ArchiveLayout layout = null, StreamMode? streamMode = null)
+ public async Task StartArchiveAsync(string sessionId, string name = "", bool hasVideo = true, bool hasAudio = true, OutputMode outputMode = OutputMode.COMPOSED, string resolution = null, ArchiveLayout layout = null, StreamMode? streamMode = null, string multiArchiveTag = null)
{
if (string.IsNullOrEmpty(sessionId))
{
@@ -540,6 +561,11 @@ public async Task StartArchiveAsync(string sessionId, string name = "",
}
data.Add("layout", layout);
}
+
+ if (multiArchiveTag is object)
+ {
+ data.Add("multiArchiveTag", multiArchiveTag);
+ }
if (streamMode.HasValue)
{
@@ -1044,17 +1070,22 @@ public async Task ForceDisconnectAsync(string sessionId, string connectionId)
/// the HLS URL will include a ?DVR query string appended to the end. See DVR functionality
/// Whether to enable low-latency mode for the HLSstream. Some HLS players do not support low-latency mode.
/// This feature is incompatible with DVR mode HLS broadcasts. See Low-latency HLS broadcasts
+ ///
+ /// Set this to support multiple broadcasts for the same session simultaneously.
+ /// Set this to a unique string for each simultaneous broadcast of an ongoing session. See
+ /// Simultaneous broadcasts.
+ ///
/// The Broadcast object. This object includes properties defining the archive, including the archive ID.
public Broadcast StartBroadcast(string sessionId, bool hls = true, List rtmpList = null, string resolution = null,
- int maxDuration = 7200, BroadcastLayout layout = null, StreamMode? streamMode = null, bool dvr = false, bool? lowLatency = null)
+ int maxDuration = 7200, BroadcastLayout layout = null, StreamMode? streamMode = null, bool dvr = false, bool? lowLatency = null, string multiBroadcastTag = null)
{
- var data = PrepareStartBroadcastData(sessionId, hls, rtmpList, resolution, maxDuration, layout, streamMode, dvr, lowLatency);
+ var data = PrepareStartBroadcastData(sessionId, hls, rtmpList, resolution, maxDuration, layout, streamMode, dvr, lowLatency, multiBroadcastTag);
string url = $"v2/project/{ApiKey}/broadcast";
var headers = new Dictionary { { "Content-Type", "application/json" } };
string response = Client.Post(url, headers, data);
return OpenTokUtils.GenerateBroadcast(response, ApiKey, ApiSecret, OpenTokServer);
}
-
+
///
/// Use this method to start a live streaming for an OpenTok session.
/// This broadcasts the session to an HLS (HTTP live streaming) or to RTMP streams.
@@ -1106,11 +1137,16 @@ public Broadcast StartBroadcast(string sessionId, bool hls = true, List rt
/// the HLS URL will include a ?DVR query string appended to the end. See DVR functionality
/// Whether to enable low-latency mode for the HLSstream. Some HLS players do not support low-latency mode.
/// This feature is incompatible with DVR mode HLS broadcasts. See Low-latency HLS broadcasts
+ ///
+ /// Set this to support multiple broadcasts for the same session simultaneously.
+ /// Set this to a unique string for each simultaneous broadcast of an ongoing session. See
+ /// Simultaneous broadcasts.
+ ///
/// The Broadcast object. This object includes properties defining the archive, including the archive ID.
public async Task StartBroadcastAsync(string sessionId, bool hls = true, List rtmpList = null, string resolution = null,
- int maxDuration = 7200, BroadcastLayout layout = null, StreamMode? streamMode = null, bool dvr = false, bool? lowLatency = null)
+ int maxDuration = 7200, BroadcastLayout layout = null, StreamMode? streamMode = null, bool dvr = false, bool? lowLatency = null, string multiBroadcastTag = null)
{
- var data = PrepareStartBroadcastData(sessionId, hls, rtmpList, resolution, maxDuration, layout, streamMode, dvr, lowLatency);
+ var data = PrepareStartBroadcastData(sessionId, hls, rtmpList, resolution, maxDuration, layout, streamMode, dvr, lowLatency, multiBroadcastTag);
string url = $"v2/project/{ApiKey}/broadcast";
var headers = new Dictionary { { "Content-Type", "application/json" } };
string response = await Client.PostAsync(url, headers, data);
@@ -1118,7 +1154,7 @@ public async Task StartBroadcastAsync(string sessionId, bool hls = tr
}
private Dictionary PrepareStartBroadcastData(string sessionId, bool hls = true, List rtmpList = null, string resolution = null,
- int maxDuration = 7200, BroadcastLayout layout = null, StreamMode? streamMode = null, bool dvr = false, bool? lowLatency = null)
+ int maxDuration = 7200, BroadcastLayout layout = null, StreamMode? streamMode = null, bool dvr = false, bool? lowLatency = null, string multiBroadcastTag = null)
{
if (string.IsNullOrEmpty(sessionId))
{
@@ -1189,6 +1225,11 @@ private Dictionary PrepareStartBroadcastData(string sessionId, b
data.Add("layout", layout);
}
}
+
+ if (multiBroadcastTag is object)
+ {
+ data.Add("multiBroadcastTag", multiBroadcastTag);
+ }
if (streamMode.HasValue)
{
diff --git a/OpenTokTest/ArchiveTests.cs b/OpenTokTest/ArchiveTests.cs
index afcb98b8..c0ac0e98 100644
--- a/OpenTokTest/ArchiveTests.cs
+++ b/OpenTokTest/ArchiveTests.cs
@@ -730,6 +730,53 @@ public async Task StartArchiveAsyncManualStreamMode()
It.IsAny>()), Times.Once());
}
+ [Fact]
+ public void StartArchiveWithMultiArchiveTag()
+ {
+ string responseJson = GetResponseJson();
+ string multiArchiveTagName = "multiArchiveTag";
+ string multiArchiveTag = "TestArchiveTag";
+ var mockClient = new Mock();
+ mockClient.Setup(httpClient => httpClient.Post(It.IsAny(), It.IsAny>(),
+ It.IsAny>()))
+ .Returns(responseJson);
+ OpenTok opentok = this.BuildOpenTok(mockClient.Object);
+ Archive archive = opentok.StartArchive(SessionId, multiArchiveTag: multiArchiveTag);
+ Assert.NotNull(archive);
+ Assert.Equal(multiArchiveTag, archive.MultiArchiveTag);
+ Assert.NotEqual(Guid.Empty, archive.Id);
+ mockClient.Verify(
+ httpClient => httpClient.Post(
+ It.Is(url => url.Equals("v2/project/" + ApiKey + "/archive")),
+ It.IsAny>(),
+ It.Is>(dictionary =>
+ dictionary.ContainsKey(multiArchiveTagName) && dictionary[multiArchiveTagName].ToString() == multiArchiveTag)),
+ Times.Once());
+ }
+
+ [Fact]
+ public async Task StartArchiveWithMultiArchiveTagAsync()
+ {
+ string responseJson = GetResponseJson();
+ string multiArchiveTagName = "multiArchiveTag";
+ string multiArchiveTag = "TestArchiveTag";
+ var mockClient = new Mock();
+ mockClient.Setup(httpClient => httpClient.PostAsync(It.IsAny(),
+ It.IsAny>(), It.IsAny>()))
+ .ReturnsAsync(responseJson);
+ OpenTok opentok = this.BuildOpenTok(mockClient.Object);
+ Archive archive = await opentok.StartArchiveAsync(SessionId, multiArchiveTag: multiArchiveTag);
+ Assert.NotNull(archive);
+ Assert.Equal(multiArchiveTag, archive.MultiArchiveTag);
+ Assert.NotEqual(Guid.Empty, archive.Id);
+ mockClient.Verify(
+ httpClient => httpClient.PostAsync(
+ It.Is(url => url.Equals("v2/project/" + ApiKey + "/archive")),
+ It.IsAny>(),
+ It.Is>(dictionary =>
+ dictionary.ContainsKey(multiArchiveTagName) && dictionary[multiArchiveTagName].ToString() == multiArchiveTag)),
+ Times.Once());
+ }
// AddStreamToArchive
@@ -1724,5 +1771,11 @@ public async Task ListArchivesAsyncBadSessionId()
Assert.Equal("Session Id is not valid", exception.Message);
}
+
+ private OpenTok BuildOpenTok(HttpClient client) =>
+ new OpenTok(this.ApiKey, this.ApiSecret)
+ {
+ Client = client,
+ };
}
}
\ No newline at end of file
diff --git a/OpenTokTest/BroadcastTests.cs b/OpenTokTest/BroadcastTests.cs
index a39ff3ab..487472cc 100644
--- a/OpenTokTest/BroadcastTests.cs
+++ b/OpenTokTest/BroadcastTests.cs
@@ -911,6 +911,30 @@ public async Task StartBroadcastWithLowLatencyAsync()
Assert.True(hls["lowLatency"]);
Assert.False(hls["dvr"]);
}
+
+ [Fact]
+ public void StartBroadcastWithMultiBroadcastTag()
+ {
+ string multiBroadcastTagName = "multiBroadcastTag";
+ string multiBroadcastTag = "TestBroadcastTag";
+ string sessionId = "SESSIONID";
+ string returnString = GetResponseJson();
+ var mockClient = new Mock();
+ mockClient.Setup(httpClient => httpClient.Post(It.IsAny(), It.IsAny>(), It.IsAny>())).Returns(returnString);
+ OpenTok opentok = new OpenTok(ApiKey, ApiSecret);
+ opentok.Client = mockClient.Object;
+ Broadcast broadcast = opentok.StartBroadcast(sessionId, multiBroadcastTag: multiBroadcastTag);
+ Assert.NotNull(broadcast);
+ Assert.Equal(multiBroadcastTag, broadcast.MultiBroadcastTag);
+ Assert.NotNull(broadcast.Id);
+ Assert.Equal(Broadcast.BroadcastStatus.STARTED, broadcast.Status);
+ mockClient.Verify(httpClient => httpClient.Post(
+ It.Is(url => url.Equals("v2/project/" + ApiKey + "/broadcast")),
+ It.IsAny>(),
+ It.Is>(dictionary =>
+ dictionary.ContainsKey(multiBroadcastTagName) && dictionary[multiBroadcastTagName].ToString() == multiBroadcastTag)),
+ Times.Once());
+ }
// AddStreamToBroadcast
diff --git a/OpenTokTest/Data/ArchiveTests/StartArchiveWithMultiArchiveTag-response.json b/OpenTokTest/Data/ArchiveTests/StartArchiveWithMultiArchiveTag-response.json
new file mode 100644
index 00000000..2c195261
--- /dev/null
+++ b/OpenTokTest/Data/ArchiveTests/StartArchiveWithMultiArchiveTag-response.json
@@ -0,0 +1,13 @@
+{
+ "createdAt": 1395183243556,
+ "duration": 0,
+ "id": "30b3ebf1-ba36-4f5b-8def-6f70d9986fe9",
+ "name": "",
+ "partnerId": 123456,
+ "reason": "",
+ "sessionId": "1_MX4xMjM0NTZ-flNhdCBNYXIgMTUgMTQ6NDI6MjMgUERUIDIwMTR-MC40OTAxMzAyNX4",
+ "size": 0,
+ "status": "started",
+ "url": null,
+ "multiArchiveTag": "TestArchiveTag"
+}
\ No newline at end of file
diff --git a/OpenTokTest/Data/ArchiveTests/StartArchiveWithMultiArchiveTagAsync-response.json b/OpenTokTest/Data/ArchiveTests/StartArchiveWithMultiArchiveTagAsync-response.json
new file mode 100644
index 00000000..2c195261
--- /dev/null
+++ b/OpenTokTest/Data/ArchiveTests/StartArchiveWithMultiArchiveTagAsync-response.json
@@ -0,0 +1,13 @@
+{
+ "createdAt": 1395183243556,
+ "duration": 0,
+ "id": "30b3ebf1-ba36-4f5b-8def-6f70d9986fe9",
+ "name": "",
+ "partnerId": 123456,
+ "reason": "",
+ "sessionId": "1_MX4xMjM0NTZ-flNhdCBNYXIgMTUgMTQ6NDI6MjMgUERUIDIwMTR-MC40OTAxMzAyNX4",
+ "size": 0,
+ "status": "started",
+ "url": null,
+ "multiArchiveTag": "TestArchiveTag"
+}
\ No newline at end of file
diff --git a/OpenTokTest/Data/BroadcastTests/StartBroadcastWithMultiBroadcastTag-response.json b/OpenTokTest/Data/BroadcastTests/StartBroadcastWithMultiBroadcastTag-response.json
new file mode 100644
index 00000000..4b603de3
--- /dev/null
+++ b/OpenTokTest/Data/BroadcastTests/StartBroadcastWithMultiBroadcastTag-response.json
@@ -0,0 +1,14 @@
+{
+ "id": "30b3ebf1-ba36-4f5b-8def-6f70d9986fe9",
+ "sessionId": "SESSIONID",
+ "projectId": 123456,
+ "createdAt": 1395183243556,
+ "updatedAt": 1395183243556,
+ "resolution": "640x480",
+ "status": "started",
+ "broadcastUrls": {
+ "hls": "http://server/fakepath/playlist.m3u8"
+ },
+ "settings": { "hls": { "lowLatency": false } },
+ "multiBroadcastTag": "TestBroadcastTag"
+}
\ No newline at end of file
diff --git a/OpenTokTest/OpenTokTest.csproj b/OpenTokTest/OpenTokTest.csproj
index 95303469..8d0efa45 100644
--- a/OpenTokTest/OpenTokTest.csproj
+++ b/OpenTokTest/OpenTokTest.csproj
@@ -77,6 +77,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
@@ -191,6 +197,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest