Skip to content

Commit ccdcae2

Browse files
Add support for screenshareType and ability to set layout for Archives (#189)
* quick adding of the layout param * Added test * Added screenshareType to other needed endpoints * Added fix for rsa on python 2.7 * Added tests Co-authored-by: Alex Tsai <[email protected]>
1 parent f7b8211 commit ccdcae2

File tree

4 files changed

+283
-8
lines changed

4 files changed

+283
-8
lines changed

opentok/opentok.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ def start_archive(
477477
name=None,
478478
output_mode=OutputModes.composed,
479479
resolution=None,
480+
layout=None,
480481
):
481482
"""
482483
Starts archiving an OpenTok session.
@@ -508,6 +509,19 @@ def start_archive(
508509
or "1280x720". This parameter only applies to composed archives. If you set this
509510
parameter and set the output_mode parameter to OutputModes.individual, the call to the
510511
start_archive() method results in an error.
512+
:param Dictionary 'layout' optional: Specify this to assign the initial layout type for the
513+
archive.
514+
515+
String 'type': Type of layout. Valid values for the layout property are "bestFit" (best fit),
516+
"custom" (custom), "horizontalPresentation" (horizontal presentation), "pip" (picture-in-picture),
517+
and "verticalPresentation" (vertical presentation)). If you specify a "custom" layout type, set
518+
the stylesheet property of the layout object to the stylesheet.
519+
520+
String 'stylesheet' optional: Custom stylesheet to use for layout. Must set 'type' to custom,
521+
and cannot use 'screenshareType'
522+
523+
String 'screenshareType' optional: Layout to use for screenshares. If this is set, you must
524+
set 'type' to 'bestFit'
511525
512526
:rtype: The Archive object, which includes properties defining the archive,
513527
including the archive ID.
@@ -535,6 +549,9 @@ def start_archive(
535549
"resolution": resolution,
536550
}
537551

552+
if layout is not None:
553+
payload['layout'] = layout
554+
538555
logger.debug(
539556
"POST to %r with params %r, headers %r, proxies %r",
540557
self.endpoints.archive_url(),
@@ -898,7 +915,7 @@ def force_disconnect(self, session_id, connection_id):
898915
else:
899916
raise RequestError("An unexpected error occurred", response.status_code)
900917

901-
def set_archive_layout(self, archive_id, layout_type, stylesheet=None):
918+
def set_archive_layout(self, archive_id, layout_type, stylesheet=None, screenshare_type=None):
902919
"""
903920
Use this method to change the layout of videos in an OpenTok archive
904921
@@ -909,11 +926,17 @@ def set_archive_layout(self, archive_id, layout_type, stylesheet=None):
909926
910927
:param String stylesheet optional: CSS used to style the custom layout.
911928
Specify this only if you set the type property to 'custom'
929+
930+
:param String screenshare_type optional: Layout to use for screenshares. Must
931+
set 'layout_type' to 'bestFit'
912932
"""
913933
payload = {
914934
"type": layout_type,
915935
}
916936

937+
if screenshare_type is not None:
938+
payload["screenshareType"] = screenshare_type
939+
917940
if layout_type == "custom":
918941
if stylesheet is not None:
919942
payload["stylesheet"] = stylesheet
@@ -1096,11 +1119,18 @@ def start_broadcast(self, session_id, options):
10961119
:param Dictionary options, with the following properties:
10971120
10981121
Dictionary 'layout' optional: Specify this to assign the initial layout type for the
1099-
broadcast. Valid values for the layout property are "bestFit", "custom",
1100-
"horizontalPresentation", "pip" and "verticalPresentation". If you specify a "custom"
1101-
layout type, set the stylesheet property of the layout object to the stylesheet.
1102-
If you do not specify an initial layout type, the broadcast stream uses the Best Fit
1103-
layout type
1122+
broadcast.
1123+
1124+
String 'type': Type of layout. Valid values for the layout property are "bestFit" (best fit),
1125+
"custom" (custom), "horizontalPresentation" (horizontal presentation), "pip" (picture-in-picture),
1126+
and "verticalPresentation" (vertical presentation)). If you specify a "custom" layout type, set
1127+
the stylesheet property of the layout object to the stylesheet.
1128+
1129+
String 'stylesheet' optional: Custom stylesheet to use for layout. Must set 'type' to custom,
1130+
and cannot use 'screenshareType'
1131+
1132+
String 'screenshareType' optional: Layout to use for screenshares. If this is set, you must
1133+
set 'type' to 'bestFit'
11041134
11051135
Integer 'maxDuration' optional: The maximum duration for the broadcast, in seconds.
11061136
The broadcast will automatically stop when the maximum duration is reached. You can
@@ -1241,7 +1271,7 @@ def get_broadcast(self, broadcast_id):
12411271
else:
12421272
raise RequestError("OpenTok server error.", response.status_code)
12431273

1244-
def set_broadcast_layout(self, broadcast_id, layout_type, stylesheet=None):
1274+
def set_broadcast_layout(self, broadcast_id, layout_type, stylesheet=None, screenshare_type=None):
12451275
"""
12461276
Use this method to change the layout type of a live streaming broadcast
12471277
@@ -1252,11 +1282,17 @@ def set_broadcast_layout(self, broadcast_id, layout_type, stylesheet=None):
12521282
12531283
:param String stylesheet optional: CSS used to style the custom layout.
12541284
Specify this only if you set the type property to 'custom'
1285+
1286+
:param String screenshare_type optional: Layout to use for screenshares. Must
1287+
set 'layout_type' to 'bestFit'
12551288
"""
12561289
payload = {
12571290
"type": layout_type,
12581291
}
12591292

1293+
if screenshare_type is not None:
1294+
payload["screenshareType"] = screenshare_type
1295+
12601296
if layout_type == "custom":
12611297
if stylesheet is not None:
12621298
payload["stylesheet"] = stylesheet

setup.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ def find_version(*file_paths):
3838
if sys.version_info[0] < 3 or sys.version_info[1] < 4:
3939
install_requires.append('enum34')
4040

41+
if sys.version_info[0] < 3:
42+
install_requires.append('rsa<=4.0')
43+
4144
setup(
4245
name = 'opentok',
4346
version = find_version('opentok', 'version.py'),

tests/test_archive_api.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,72 @@ def test_start_composed_archive(self):
517517
expect(archive).to(have_property(u("output_mode"), OutputModes.composed))
518518
expect(archive).to(have_property(u("url"), None))
519519

520+
@httpretty.activate
521+
def test_start_archive_with_layout(self):
522+
httpretty.register_uri(
523+
httpretty.POST,
524+
u("https://api.opentok.com/v2/project/{0}/archive").format(self.api_key),
525+
body=textwrap.dedent(
526+
u(
527+
"""\
528+
{
529+
"createdAt" : 1395183243556,
530+
"duration" : 0,
531+
"id" : "30b3ebf1-ba36-4f5b-8def-6f70d9986fe9",
532+
"name" : "",
533+
"partnerId" : 123456,
534+
"reason" : "",
535+
"sessionId" : "SESSIONID",
536+
"size" : 0,
537+
"status" : "started",
538+
"hasAudio": true,
539+
"hasVideo": true,
540+
"outputMode": "composed",
541+
"url" : null
542+
}
543+
"""
544+
)
545+
),
546+
status=200,
547+
content_type=u("application/json"),
548+
)
549+
550+
archive = self.opentok.start_archive(self.session_id, layout={"type": "pip", "screenshareType": "horizontal"})
551+
552+
validate_jwt_header(self, httpretty.last_request().headers[u("x-opentok-auth")])
553+
expect(httpretty.last_request().headers[u("user-agent")]).to(
554+
contain(u("OpenTok-Python-SDK/") + __version__)
555+
)
556+
expect(httpretty.last_request().headers[u("content-type")]).to(
557+
equal(u("application/json"))
558+
)
559+
# non-deterministic json encoding. have to decode to test it properly
560+
if PY2:
561+
body = json.loads(httpretty.last_request().body)
562+
if PY3:
563+
body = json.loads(httpretty.last_request().body.decode("utf-8"))
564+
expect(body).to(have_key(u("sessionId"), u("SESSIONID")))
565+
expect(body).to(have_key(u("name"), None))
566+
expect(body).to(have_key(u("layout"), {"type": "pip", "screenshareType": "horizontal"}))
567+
expect(archive).to(be_an(Archive))
568+
expect(archive).to(
569+
have_property(u("id"), u("30b3ebf1-ba36-4f5b-8def-6f70d9986fe9"))
570+
)
571+
expect(archive).to(have_property(u("name"), ("")))
572+
expect(archive).to(have_property(u("status"), u("started")))
573+
expect(archive).to(have_property(u("session_id"), u("SESSIONID")))
574+
expect(archive).to(have_property(u("partner_id"), 123456))
575+
if PY2:
576+
created_at = datetime.datetime.fromtimestamp(1395183243, pytz.UTC)
577+
if PY3:
578+
created_at = datetime.datetime.fromtimestamp(
579+
1395183243, datetime.timezone.utc
580+
)
581+
expect(archive).to(have_property(u("created_at"), equal(created_at)))
582+
expect(archive).to(have_property(u("size"), equal(0)))
583+
expect(archive).to(have_property(u("duration"), equal(0)))
584+
expect(archive).to(have_property(u("url"), equal(None)))
585+
520586
@httpretty.activate
521587
def test_stop_archive(self):
522588
archive_id = u("30b3ebf1-ba36-4f5b-8def-6f70d9986fe9")
@@ -1373,6 +1439,39 @@ def test_set_archive_layout(self):
13731439
equal(u("application/json"))
13741440
)
13751441

1442+
@httpretty.activate
1443+
def test_set_archive_screenshare_type(self):
1444+
""" Test set archive layout functionality """
1445+
archive_id = u("f6e7ee58-d6cf-4a59-896b-6d56b158ec71")
1446+
1447+
httpretty.register_uri(
1448+
httpretty.PUT,
1449+
u("https://api.opentok.com/v2/project/{0}/archive/{1}/layout").format(
1450+
self.api_key, archive_id
1451+
),
1452+
status=200,
1453+
content_type=u("application/json"),
1454+
)
1455+
1456+
self.opentok.set_archive_layout(archive_id, "bestFit", screenshare_type="horizontalPresentation")
1457+
1458+
validate_jwt_header(self, httpretty.last_request().headers[u("x-opentok-auth")])
1459+
expect(httpretty.last_request().headers[u("user-agent")]).to(
1460+
contain(u("OpenTok-Python-SDK/") + __version__)
1461+
)
1462+
expect(httpretty.last_request().headers[u("content-type")]).to(
1463+
equal(u("application/json"))
1464+
)
1465+
1466+
if PY2:
1467+
body = json.loads(httpretty.last_request().body)
1468+
if PY3:
1469+
body = json.loads(httpretty.last_request().body.decode("utf-8"))
1470+
1471+
expect(body).to(have_key(u("type"), u("bestFit")))
1472+
expect(body).to_not(have_key(u("stylesheet")))
1473+
expect(body).to(have_key(u("screenshareType"), u("horizontalPresentation")))
1474+
13761475
@httpretty.activate
13771476
def test_set_custom_archive_layout(self):
13781477
""" Test set a custom archive layout specifying the 'stylesheet' parameter """

0 commit comments

Comments
 (0)