Skip to content

Commit 3f1d6d7

Browse files
committed
adding hasAudio and hasVideo to Broadcast object, update readme, add tests
1 parent 31fa070 commit 3f1d6d7

File tree

4 files changed

+245
-2
lines changed

4 files changed

+245
-2
lines changed

README.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ The live streaming broadcast can target one HLS endpoint and up to five RTMP ser
417417
'stylesheet': 'the layout stylesheet (only used with type == custom)'
418418
},
419419
'maxDuration': 5400,
420+
'hasAudio': True
421+
'hasVideo': True
420422
'outputs': {
421423
'hls': {},
422424
'rtmp': [{
@@ -473,6 +475,37 @@ You can specify the following broadcast resolutions:
473475
To enable multiple simultaneous broadcasts on the same session, specify a unique value for the
474476
``multiBroadcastTag`` parameter in ``options`` when calling the ``opentok.start_broadcast`` method.
475477

478+
You can broadcast only audio, or only video, for a stream by setting ``hasAudio`` or ``hasVideo``
479+
to ``False`` as required. These fields are ``True`` by default.
480+
481+
.. code:: python
482+
483+
session_id = 'SESSIONID'
484+
options = {
485+
'layout': {
486+
'type': 'custom',
487+
'stylesheet': 'the layout stylesheet (only used with type == custom)'
488+
},
489+
'maxDuration': 5400,
490+
'hasAudio': True
491+
'hasVideo': False
492+
'outputs': {
493+
'hls': {},
494+
'rtmp': [{
495+
'id': 'foo',
496+
'serverUrl': 'rtmp://myfooserver/myfooapp',
497+
'streamName': 'myfoostream'
498+
}, {
499+
'id': 'bar',
500+
'serverUrl': 'rtmp://mybarserver/mybarapp',
501+
'streamName': 'mybarstream'
502+
}]
503+
},
504+
'resolution': '640x480'
505+
}
506+
507+
broadcast = opentok.start_broadcast(session_id, options)
508+
476509
You can stop a started Broadcast using the ``opentok.stop_broadcast(broadcast_id)`` method.
477510

478511
.. code:: python

opentok/broadcast.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class Broadcast(object):
2828
:ivar status:
2929
The status of the broadcast.
3030
31+
:ivar hasAudio:
32+
Whether the broadcast has audio.
33+
34+
:ivar hasVideo:
35+
Whether the broadcast has video.
36+
3137
:ivar broadcastUrls:
3238
An object containing details about the HLS and RTMP broadcasts.
3339
@@ -63,6 +69,8 @@ def __init__(self, kwargs):
6369
self.projectId = kwargs.get("projectId")
6470
self.createdAt = kwargs.get("createdAt")
6571
self.updatedAt = kwargs.get("updatedAt")
72+
self.hasAudio = kwargs.get("hasAudio")
73+
self.hasVideo = kwargs.get("hasVideo")
6674
self.resolution = kwargs.get("resolution")
6775
self.status = kwargs.get("status")
6876
self.broadcastUrls = kwargs.get("broadcastUrls")
@@ -71,7 +79,7 @@ def __init__(self, kwargs):
7179

7280
def json(self):
7381
"""
74-
Returns a JSON representation of the broadcast
82+
Returns a JSON representation of the broadcast.
7583
"""
7684
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
7785

opentok/opentok.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,7 @@ def start_broadcast(self, session_id, options, stream_mode=BroadcastStreamModes.
13771377
BroadcastStreamModes.manual to explicitly select streams to include in the the broadcast, using the
13781378
OpenTok.add_broadcast_stream() and OpenTok.remove_broadcast_stream() methods.
13791379
1380-
:rtype A Broadcast object, which contains information of the broadcast: id, sessionId
1380+
:rtype A Broadcast object, which contains information of the broadcast: id, sessionId,
13811381
projectId, createdAt, updatedAt, resolution, status and broadcastUrls
13821382
"""
13831383

tests/test_broadcast.py

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,208 @@ def test_start_broadcast_with_screenshare_type(self):
292292
expect(list(broadcast.broadcastUrls)).to(have_length(2))
293293
expect(list(broadcast.broadcastUrls["rtmp"])).to(have_length(2))
294294

295+
@httpretty.activate
296+
def test_start_broadcast_audio_only(self):
297+
"""
298+
Test start_broadcast() method
299+
"""
300+
httpretty.register_uri(
301+
httpretty.POST,
302+
u("https://api.opentok.com/v2/project/{0}/broadcast").format(self.api_key),
303+
body=textwrap.dedent(
304+
u(
305+
"""\
306+
{
307+
"id": "1748b7070a81464c9759c46ad10d3734",
308+
"sessionId": "2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4",
309+
"projectId": 100,
310+
"createdAt": 1437676551000,
311+
"updatedAt": 1437676551000,
312+
"resolution": "640x480",
313+
"status": "started",
314+
"hasAudio": true,
315+
"hasVideo": false,
316+
"broadcastUrls": {
317+
"hls" : "http://server/fakepath/playlist.m3u8",
318+
"rtmp": {
319+
"foo": {
320+
"serverUrl": "rtmp://myfooserver/myfooapp",
321+
"streamName": "myfoostream"
322+
},
323+
"bar": {
324+
"serverUrl": "rtmp://mybarserver/mybarapp",
325+
"streamName": "mybarstream"
326+
}
327+
}
328+
}
329+
}
330+
"""
331+
)
332+
),
333+
status=200,
334+
content_type=u("application/json"),
335+
)
336+
337+
options = {
338+
"layout": {
339+
"type": "custom",
340+
"stylesheet": "the layout stylesheet (only used with type == custom)",
341+
},
342+
"maxDuration": 5400,
343+
"hasAudio": True,
344+
"hasVideo": False,
345+
"outputs": {
346+
"hls": {},
347+
"rtmp": [
348+
{
349+
"id": "foo",
350+
"serverUrl": "rtmp://myfooserver/myfooapp",
351+
"streamName": "myfoostream",
352+
},
353+
{
354+
"id": "bar",
355+
"serverUrl": "rtmp://mybarserver/mybarapp",
356+
"streamName": "mybarstream",
357+
},
358+
],
359+
},
360+
"resolution": "640x480",
361+
}
362+
363+
broadcast = self.opentok.start_broadcast(self.session_id, options)
364+
validate_jwt_header(self, httpretty.last_request().headers[u("x-opentok-auth")])
365+
expect(httpretty.last_request().headers[u("user-agent")]).to(
366+
contain(u("OpenTok-Python-SDK/") + __version__)
367+
)
368+
expect(httpretty.last_request().headers[u("content-type")]).to(
369+
equal(u("application/json"))
370+
371+
)
372+
# non-deterministic json encoding. have to decode to test it properly
373+
if PY2:
374+
body = json.loads(httpretty.last_request().body)
375+
if PY3:
376+
body = json.loads(httpretty.last_request().body.decode("utf-8"))
377+
378+
expect(body).to(have_key(u("layout")))
379+
expect(broadcast).to(be_an(Broadcast))
380+
expect(broadcast).to(
381+
have_property(u("id"), u("1748b7070a81464c9759c46ad10d3734"))
382+
)
383+
expect(broadcast).to(
384+
have_property(u("sessionId"), u("2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4"))
385+
)
386+
expect(broadcast).to(have_property(u("projectId"), 100))
387+
expect(broadcast).to(have_property(u("createdAt"), 1437676551000))
388+
expect(broadcast).to(have_property(u("updatedAt"), 1437676551000))
389+
expect(broadcast).to(have_property(u("hasAudio"), True))
390+
expect(broadcast).to(have_property(u("hasVideo"), False))
391+
expect(broadcast).to(have_property(u("resolution"), u("640x480")))
392+
expect(broadcast).to(have_property(u("status"), u("started")))
393+
expect(list(broadcast.broadcastUrls)).to(have_length(2))
394+
expect(list(broadcast.broadcastUrls["rtmp"])).to(have_length(2))
395+
396+
@httpretty.activate
397+
def test_start_broadcast_video_only(self):
398+
"""
399+
Test start_broadcast() method
400+
"""
401+
httpretty.register_uri(
402+
httpretty.POST,
403+
u("https://api.opentok.com/v2/project/{0}/broadcast").format(self.api_key),
404+
body=textwrap.dedent(
405+
u(
406+
"""\
407+
{
408+
"id": "1748b7070a81464c9759c46ad10d3734",
409+
"sessionId": "2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4",
410+
"projectId": 100,
411+
"createdAt": 1437676551000,
412+
"updatedAt": 1437676551000,
413+
"resolution": "640x480",
414+
"status": "started",
415+
"hasAudio": false,
416+
"hasVideo": true,
417+
"broadcastUrls": {
418+
"hls" : "http://server/fakepath/playlist.m3u8",
419+
"rtmp": {
420+
"foo": {
421+
"serverUrl": "rtmp://myfooserver/myfooapp",
422+
"streamName": "myfoostream"
423+
},
424+
"bar": {
425+
"serverUrl": "rtmp://mybarserver/mybarapp",
426+
"streamName": "mybarstream"
427+
}
428+
}
429+
}
430+
}
431+
"""
432+
)
433+
),
434+
status=200,
435+
content_type=u("application/json"),
436+
)
437+
438+
options = {
439+
"layout": {
440+
"type": "custom",
441+
"stylesheet": "the layout stylesheet (only used with type == custom)",
442+
},
443+
"maxDuration": 5400,
444+
"hasAudio": False,
445+
"hasVideo": True,
446+
"outputs": {
447+
"hls": {},
448+
"rtmp": [
449+
{
450+
"id": "foo",
451+
"serverUrl": "rtmp://myfooserver/myfooapp",
452+
"streamName": "myfoostream",
453+
},
454+
{
455+
"id": "bar",
456+
"serverUrl": "rtmp://mybarserver/mybarapp",
457+
"streamName": "mybarstream",
458+
},
459+
],
460+
},
461+
"resolution": "640x480",
462+
}
463+
464+
broadcast = self.opentok.start_broadcast(self.session_id, options)
465+
validate_jwt_header(self, httpretty.last_request().headers[u("x-opentok-auth")])
466+
expect(httpretty.last_request().headers[u("user-agent")]).to(
467+
contain(u("OpenTok-Python-SDK/") + __version__)
468+
)
469+
expect(httpretty.last_request().headers[u("content-type")]).to(
470+
equal(u("application/json"))
471+
472+
)
473+
# non-deterministic json encoding. have to decode to test it properly
474+
if PY2:
475+
body = json.loads(httpretty.last_request().body)
476+
if PY3:
477+
body = json.loads(httpretty.last_request().body.decode("utf-8"))
478+
479+
expect(body).to(have_key(u("layout")))
480+
expect(broadcast).to(be_an(Broadcast))
481+
expect(broadcast).to(
482+
have_property(u("id"), u("1748b7070a81464c9759c46ad10d3734"))
483+
)
484+
expect(broadcast).to(
485+
have_property(u("sessionId"), u("2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4"))
486+
)
487+
expect(broadcast).to(have_property(u("projectId"), 100))
488+
expect(broadcast).to(have_property(u("createdAt"), 1437676551000))
489+
expect(broadcast).to(have_property(u("updatedAt"), 1437676551000))
490+
expect(broadcast).to(have_property(u("hasAudio"), False))
491+
expect(broadcast).to(have_property(u("hasVideo"), True))
492+
expect(broadcast).to(have_property(u("resolution"), u("640x480")))
493+
expect(broadcast).to(have_property(u("status"), u("started")))
494+
expect(list(broadcast.broadcastUrls)).to(have_length(2))
495+
expect(list(broadcast.broadcastUrls["rtmp"])).to(have_length(2))
496+
295497
@httpretty.activate
296498
def test_start_broadcast_with_streammode_auto(self):
297499
url = f"https://api.opentok.com/v2/partner/{self.api_key}/broadcast"

0 commit comments

Comments
 (0)