Skip to content

Commit 35d2f19

Browse files
committed
Adding properties streamMode, streams and new methods for archive and broadcast
1 parent b92dd73 commit 35d2f19

File tree

6 files changed

+181
-67
lines changed

6 files changed

+181
-67
lines changed

opentok/archives.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ class Archive(object):
6262
Whether all streams in the archive are recorded to a single file
6363
(OutputModes.composed) or to individual files (OutputModes.individual).
6464
65+
:ivar streamMode:
66+
Determines the archive stream handling mode. It's set to 'auto' by
67+
default if you want all streams. To explicitly select specific streams
68+
in the archive then set to 'manual'.
69+
70+
:ivar streams:
71+
A list of streams in an archive.
72+
6573
:ivar partner_id:
6674
The API key associated with the archive.
6775
@@ -120,7 +128,8 @@ def __init__(self, sdk, values):
120128
self.has_audio = values.get("hasAudio")
121129
self.has_video = values.get("hasVideo")
122130
self.output_mode = OutputModes[values.get("outputMode", "composed")]
123-
self.stream_mode = StreamModes[values.get("auto", "manual")]
131+
self.stream_mode = values.get("streamMode", StreamModes.auto)
132+
self.streams = values.get("streams")
124133
self.url = values.get("url")
125134
self.resolution = values.get("resolution")
126135

opentok/broadcast.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
class Broadcast(object):
88
"""
99
Represents a live streaming broadcast
10+
11+
:ivar streamMode:
12+
Determines the broadcast stream handling mode. It's set to 'auto' by
13+
default if you want all streams. To explicitly select specific streams
14+
in the broadcast then set to 'manual'.
15+
16+
:ivar streams:
17+
A list of streams in a broadcast.
1018
"""
1119

1220
def __init__(self, kwargs):
@@ -18,7 +26,8 @@ def __init__(self, kwargs):
1826
self.resolution = kwargs.get("resolution")
1927
self.status = kwargs.get("status")
2028
self.broadcastUrls = kwargs.get("broadcastUrls")
21-
self.streamMode = kwargs.get(BroadcastStreamModes.auto)
29+
self.stream_mode = kwargs.get("streamMode", BroadcastStreamModes.auto)
30+
self.streams = kwargs.get("streams")
2231

2332
def json(self):
2433
"""

opentok/opentok.py

Lines changed: 107 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -749,51 +749,82 @@ def list_archives(self, offset=None, count=None, session_id=None):
749749
"""
750750
return self.get_archives(offset, count, session_id)
751751

752-
753-
def update_archive(
752+
def add_archive_stream(
754753
self,
755754
archive_id: str,
756-
add_stream: List[str],
757-
remove_stream: List[str],
755+
stream_id: str,
758756
has_audio: bool = True,
759757
has_video: bool = True
760758
) -> requests.Response:
759+
761760
"""
762-
New method to update the archive with addStream for new participant or
763-
removeStream to a new participant stream (choosing audio, video or both)
761+
This method will add streams to the archive with addStream for new participant(choosing audio, video or both).
764762
765-
:param String archive_id: The ID of the archive that will be updated
766-
:param List of Strings add_stream will add a participant stream (which audio and video) to the archive
767-
:param List of Strings remove_stream will remove a partcipant stream from the archive
763+
:param String archive_id: the ID of the archive that will be updated
764+
:param String stream_id: the id of the stream that will get added to the archive
768765
:param Boolean has_audio: if set to True, an audio track will be inserted to the archive.
769766
has_audio is an optional parameter that is set to True by default. If you set both
770-
has_audio and has_video to False, the call to the update_archive() method results in
767+
has_audio and has_video to False, the call to the add_archive_stream() method results in
771768
an error.
772769
:param Boolean has_video: if set to True, a video track will be inserted to the archive.
773770
has_video is an optional parameter that is set to True by default.
774771
"""
775-
endpoint = self.endpoints.get_archive_stream()
776772

777-
stream_list = []
773+
endpoint = self.endpoints.get_archive_stream(archive_id)
778774

779-
payload = {
775+
streams = {
780776
"hasAudio": has_audio,
781777
"hasVideo": has_video,
778+
"addStream": stream_id
782779
}
783780

784-
if add_stream:
785-
payload["addStream"] = stream_list.append(add_stream)
786-
else:
787-
payload["addStream"] = None
788-
789-
if remove_stream:
790-
payload["removeStream"] = stream_list.append(remove_stream)
791-
else:
792-
payload["removeStream"] = None
781+
response = requests.patch(
782+
endpoint,
783+
data=json.dumps(streams),
784+
headers=self.get_json_headers(),
785+
proxies=self.proxies,
786+
timeout=self.timeout,
787+
)
788+
789+
if response:
790+
return Archive(self, response.json())
791+
elif response.status_code == 403:
792+
raise AuthError()
793+
elif response.status_code == 400:
794+
"""
795+
The HTTP response has a 400 status code in the following cases:
796+
You do not pass in a session ID or you pass in an invalid session ID.
797+
No clients are actively connected to the OpenTok session.
798+
You specify an invalid resolution value.
799+
The outputMode property is set to "individual" and you set the resolution property and (which is not supported in individual stream archives).
800+
"""
801+
raise RequestError(response.json().get("message"))
802+
elif response.status_code == 404:
803+
raise NotFoundError("Archive or Stream not found")
804+
elif response.status_code == 405:
805+
raise ArchiveStreamModeError("Your archive is configured with a streamMode that does not support stream manipulation.")
806+
elif response.status_code == 409:
807+
raise ArchiveError(response.json().get("message"))
808+
else:
809+
raise RequestError("An unexpected error occurred", response.status_code)
810+
811+
def remove_archive_stream(self, archive_id: str, stream_id: str) -> requests.Response:
812+
"""
813+
This method will remove streams from the archive with removeStream.
814+
815+
:param String archive_id: the ID of the archive that will be updated
816+
:param String stream_id: the ID of the stream that will get added to the archive
817+
"""
818+
819+
endpoint = self.endpoints.get_archive_stream(archive_id)
820+
821+
streams = {
822+
"removeStream": stream_id
823+
}
793824

794825
response = requests.patch(
795826
endpoint,
796-
data=json.dumps(payload),
827+
data=json.dumps(streams),
797828
headers=self.get_json_headers(),
798829
proxies=self.proxies,
799830
timeout=self.timeout,
@@ -822,6 +853,7 @@ def update_archive(
822853
raise RequestError("An unexpected error occurred", response.status_code)
823854

824855

856+
825857
def send_signal(self, session_id, payload, connection_id=None):
826858
"""
827859
Send signals to all participants in an active OpenTok session or to a specific client
@@ -1320,50 +1352,79 @@ def stop_broadcast(self, broadcast_id):
13201352
else:
13211353
raise RequestError("OpenTok server error.", response.status_code)
13221354

1323-
def update_broadcast(
1355+
def add_broadcast_stream(
13241356
self,
13251357
broadcast_id: str,
1326-
add_stream: List[str],
1327-
remove_stream: List[str],
1358+
stream_id: str,
13281359
has_audio: bool = True,
1329-
has_video: bool = True,
1360+
has_video: bool = True
13301361
) -> requests.Response:
1362+
13311363
"""
1332-
New method to update the archive with addStream for new participant or
1333-
removeStream to a new participant stream (choosing audio, video or both)
1364+
This method will add streams to the broadcast with addStream for new participant(choosing audio, video or both).
13341365
1335-
:param String broadcast_id: The ID of the broadcast that will be updated
1336-
:param List of Strings add_stream will add a participant stream (which audio and video) to the broadcast
1337-
:param List of Strings remove_stream will remove a partcipant stream from the broadcast
1366+
:param String broadcast_id: the ID of the broadcast that will be updated
1367+
:param String stream_id: the id of the stream that will get added to the broadcast
13381368
:param Boolean has_audio: if set to True, an audio track will be inserted to the broadcast.
13391369
has_audio is an optional parameter that is set to True by default. If you set both
1340-
has_audio and has_video to False, the call to the update_broadcast() method results in
1370+
has_audio and has_video to False, the call to the add_broadcast_stream() method results in
13411371
an error.
13421372
:param Boolean has_video: if set to True, a video track will be inserted to the broadcast.
13431373
has_video is an optional parameter that is set to True by default.
13441374
"""
1345-
endpoint = self.endpoints.get_broadcast_stream()
13461375

1347-
stream_list = []
1376+
endpoint = self.endpoints.get_broadcast_stream(broadcast_id)
13481377

1349-
payload = {
1378+
streams = {
13501379
"hasAudio": has_audio,
13511380
"hasVideo": has_video,
1381+
"addStream": stream_id
13521382
}
13531383

1354-
if add_stream:
1355-
payload["addStream"] = stream_list.append(add_stream)
1356-
else:
1357-
payload["addStream"] = None
1358-
1359-
if remove_stream:
1360-
payload["removeStream"] = stream_list.append(remove_stream)
1361-
else:
1362-
payload["removeStream"] = None
1384+
response = requests.patch(
1385+
endpoint,
1386+
data=json.dumps(streams),
1387+
headers=self.get_json_headers(),
1388+
proxies=self.proxies,
1389+
timeout=self.timeout,
1390+
)
1391+
1392+
if response:
1393+
return Broadcast(response.json())
1394+
elif response.status_code == 400:
1395+
raise BroadcastError(
1396+
"Invalid request. This response may indicate that data in your request data is "
1397+
"invalid JSON. It may also indicate that you passed in invalid layout options. "
1398+
"Or you have exceeded the limit of five simultaneous RTMP streams for an OpenTok "
1399+
"session. Or you specified and invalid resolution."
1400+
)
1401+
elif response.status_code == 403:
1402+
raise AuthError("Authentication error.")
1403+
elif response.status_code == 405:
1404+
raise BroadcastStreamModeError("Your broadcast is configured with a streamMode that does not support stream manipulation.")
1405+
elif response.status_code == 409:
1406+
raise BroadcastError("The broadcast has already started for the session.")
1407+
else:
1408+
raise RequestError("OpenTok server error.", response.status_code)
1409+
1410+
1411+
def remove_broadcast_stream(self, broadcast_id: str, stream_id: str) -> requests.Response:
1412+
"""
1413+
This method will remove streams from the broadcast with removeStream.
1414+
1415+
:param String broadcast_id: the ID of the broadcast that will be updated
1416+
:param String stream_id: the id of the stream that will get added to the broadcast
1417+
"""
1418+
1419+
endpoint = self.endpoints.get_broadcast_stream(broadcast_id)
1420+
1421+
streams = {
1422+
"removeStream": stream_id
1423+
}
13631424

13641425
response = requests.patch(
13651426
endpoint,
1366-
data=json.dumps(payload),
1427+
data=json.dumps(streams),
13671428
headers=self.get_json_headers(),
13681429
proxies=self.proxies,
13691430
timeout=self.timeout,

tests/test_archive.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,14 @@ def test_stop_archive(self):
105105

106106

107107
@httpretty.activate
108-
def test_update_archive_auto(self):
108+
def test_add_archive_stream(self):
109109
archive_id = u("ARCHIVEID")
110110
url = f"https://api.opentok.com/v2/project/{self.api_key}/archive/{archive_id}/streams"
111111

112112
payload = {
113113
"hasAudio": True,
114114
"hasVideo": True,
115-
"addStream": [self.stream1, self.stream2]
115+
"addStream": self.stream1
116116
}
117117

118118
httpretty.register_uri(httpretty.PATCH,
@@ -129,20 +129,18 @@ def test_update_archive_auto(self):
129129
response.json().should.equal({
130130
"hasAudio": True,
131131
"hasVideo": True,
132-
"addStream": [self.stream1, self.stream2]
132+
"addStream": self.stream1
133133
})
134134

135135
response.headers["Content-Type"].should.equal("application/json")
136136

137137
@httpretty.activate
138-
def test_update_archive_manual(self):
138+
def test_remove_archive_stream(self):
139139
archive_id = u("ARCHIVEID")
140140
url = f"https://api.opentok.com/v2/project/{self.api_key}/archive/{archive_id}/streams"
141141

142142
payload = {
143-
"hasAudio": True,
144-
"hasVideo": True,
145-
"addStream": [self.stream1]
143+
"removeStream": self.stream1
146144
}
147145

148146
httpretty.register_uri(httpretty.PATCH,
@@ -157,9 +155,7 @@ def test_update_archive_manual(self):
157155

158156
response.status_code.should.equal(200)
159157
response.json().should.equal({
160-
"hasAudio": True,
161-
"hasVideo": True,
162-
"addStream": [self.stream1]
158+
"removeStream": self.stream1
163159
})
164160

165161
response.headers["Content-Type"].should.equal("application/json")

tests/test_archive_api.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,7 +1509,7 @@ def test_start_archive_with_streammode_auto(self):
15091509
httpretty.register_uri(httpretty.POST,
15101510
url,
15111511
responses=[
1512-
httpretty.Response(body=json.dumps({"stream_mode":"auto"}),
1512+
httpretty.Response(body=json.dumps({"streamMode":"auto"}),
15131513
content_type="application/json",
15141514
status=200)
15151515
])
@@ -1518,7 +1518,7 @@ def test_start_archive_with_streammode_auto(self):
15181518
response = requests.post(url)
15191519

15201520
response.status_code.should.equal(200)
1521-
response.json().should.equal({"stream_mode":"auto"})
1521+
response.json().should.equal({"streamMode":"auto"})
15221522
response.headers["Content-Type"].should.equal("application/json")
15231523

15241524

@@ -1530,7 +1530,7 @@ def test_start_archive_with_streammode_manual(self):
15301530
httpretty.register_uri(httpretty.POST,
15311531
url,
15321532
responses=[
1533-
httpretty.Response(body=json.dumps({"stream_mode":"manual"}),
1533+
httpretty.Response(body=json.dumps({"streamMode":"manual"}),
15341534
content_type="application/json",
15351535
status=200)
15361536
])
@@ -1539,7 +1539,7 @@ def test_start_archive_with_streammode_manual(self):
15391539
response = requests.post(url)
15401540

15411541
response.status_code.should.equal(200)
1542-
response.json().should.equal({"stream_mode":"manual"})
1542+
response.json().should.equal({"streamMode":"manual"})
15431543
response.headers["Content-Type"].should.equal("application/json")
15441544

15451545

0 commit comments

Comments
 (0)