Skip to content

Commit

Permalink
Merge pull request #226 from opentok/add-broadcast-and-dial-options
Browse files Browse the repository at this point in the history
Add broadcast and dial options
  • Loading branch information
maxkahan authored Aug 21, 2023
2 parents e502713 + 1f23e2d commit 132c8d4
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.6.1
current_version = 3.7.0
commit = True
tag = False

Expand Down
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Release v3.7.0
- Added the `maxBitrate` parameter to the `Client.start_broadcast` method
- Added the `hlsStatus` parameter to the `Broadcast object`
- Added the `streams` parameter so specific streams can be chosen to be included in a SIP call when using the `Client.dial` method

# Release v3.6.1
- Fixed broken `opentok.Client.add_archive_stream`, `opentok.Client.remove_archive_stream`, `opentok.Client.add_broadcast_stream` and `opentok.Client.remove_broadcast_stream` methods and tests
- Fixed `opentok.Endpoints.get_archive_stream` and `opentok.Endpoints.get_broadcast_stream` methods
Expand Down
24 changes: 16 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,8 @@ Your application server can disconnect a client from an OpenTok session by calli
Working with SIP Interconnect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can connect your SIP platform to an OpenTok session, the audio from your end of the SIP call is added to the OpenTok session as an audio-only stream. The OpenTok Media Router mixes audio from other streams in the session and sends the mixed audio to your SIP endpoint.
You can connect your SIP platform to an OpenTok session, the audio from your end of the SIP call is added to the OpenTok session as an audio-only stream.
The OpenTok Media Router mixes audio from other streams in the session and sends the mixed audio to your SIP endpoint.

.. code:: python
Expand All @@ -397,8 +398,7 @@ You can connect your SIP platform to an OpenTok session, the audio from your end
# call the method with the required parameters
sip_call = opentok.dial(session_id, token, sip_uri)
# the method also support aditional options to establish the sip call
# the method also supports aditional options to establish the sip call
options = {
'from': '[email protected]',
'headers': {
Expand All @@ -408,7 +408,10 @@ You can connect your SIP platform to an OpenTok session, the audio from your end
'username': 'username',
'password': 'password'
},
'secure': True
'secure': True,
'video': True,
'observeForceMute': True,
'streams': ['stream-id-1', 'stream-id-2']
}
# call the method with aditional options
Expand Down Expand Up @@ -438,8 +441,9 @@ The live streaming broadcast can target one HLS endpoint and up to five RTMP ser
'stylesheet': 'the layout stylesheet (only used with type == custom)'
},
'maxDuration': 5400,
'hasAudio': True
'hasVideo': True
'hasAudio': True,
'hasVideo': True,
'maxBitrate': 2000000,
'outputs': {
'hls': {},
'rtmp': [{
Expand All @@ -466,6 +470,8 @@ You can specify the following broadcast resolutions:
* "1920x1080" (FHD landscape)
* "1080x1920" (FHD portrait)

You can specify a maximum bitrate between 100000 and 6000000.

.. code:: python
session_id = 'SESSIONID'
Expand All @@ -476,6 +482,7 @@ You can specify the following broadcast resolutions:
'stylesheet': 'the layout stylesheet (only used with type == custom)'
},
'maxDuration': 5400,
'maxBitrate': 2000000,
'outputs': {
'hls': {},
'rtmp': [{
Expand Down Expand Up @@ -508,8 +515,9 @@ to ``False`` as required. These fields are ``True`` by default.
'stylesheet': 'the layout stylesheet (only used with type == custom)'
},
'maxDuration': 5400,
'hasAudio': True
'hasVideo': False
'hasAudio': True,
'hasVideo': False,
'maxBitrate': 2000000,
'outputs': {
'hls': {},
'rtmp': [{
Expand Down
40 changes: 25 additions & 15 deletions opentok/broadcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Broadcast(object):
:ivar resolution:
The resolution of the broadcast (either "640x480", "1280x720", "1920x1080", "480x640", "720x1280", or "1920x1080").
:ivar status:
The status of the broadcast.
Expand All @@ -34,29 +34,36 @@ class Broadcast(object):
:ivar hasVideo:
Whether the broadcast has video.
:ivar 'maxBitrate' optional:
The maximum bitrate (bits per second) used by the broadcast.
:ivar broadcastUrls:
An object containing details about the HLS and RTMP broadcasts.
If you specified an HLS endpoint, the object includes an hls property, which is set to the URL for the HLS broadcast.
Note this HLS broadcast URL points to an index file, an .M3U8-formatted playlist that contains a list of URLs
If you specified an HLS endpoint, the object includes an hls property, which is set to the URL for the HLS broadcast.
Note this HLS broadcast URL points to an index file, an .M3U8-formatted playlist that contains a list of URLs
to .ts media segment files (MPEG-2 transport stream files).
While the URLs of both the playlist index file and media segment files are provided as soon as the HTTP response
is returned, these URLs should not be accessed until 15 - 20 seconds later,
after the initiation of the HLS broadcast, due to the delay between the HLS broadcast and the live streams
in the OpenTok session.
See https://developer.apple.com/library/ios/technotes/tn2288/_index.html for more information about the playlist index
is returned, these URLs should not be accessed until 15 - 20 seconds later,
after the initiation of the HLS broadcast, due to the delay between the HLS broadcast and the live streams
in the OpenTok session.
See https://developer.apple.com/library/ios/technotes/tn2288/_index.html for more information about the playlist index
file and media segment files for HLS.
If you specified RTMP stream endpoints, the object includes an rtmp property.
This is an array of objects that include information on each of the RTMP streams.
Each of these objects has the following properties: id (the ID you assigned to the RTMP stream),
serverUrl (the server URL), streamName (the stream name), and status property (which is set to "connecting").
You can call the OpenTok REST method to check for status updates for the broadcast:
If you specified an HLS endpoint, the object will also include an "hlsStatus" property with
information about the HLS broadcast. This will have one of the following values:
["connecting", "ready", "live", "ended", "error"].
If you specified RTMP stream endpoints, the object includes an rtmp property.
This is an array of objects that include information on each of the RTMP streams.
Each of these objects has the following properties: id (the ID you assigned to the RTMP stream),
serverUrl (the server URL), streamName (the stream name), and status property (which is set to "connecting").
You can call the OpenTok REST method to check for status updates for the broadcast:
https://tokbox.com/developer/rest/#get_info_broadcast
:ivar streamMode:
Whether streams included in the broadcast are selected automatically
("auto", the default) or manually ("manual").
("auto", the default) or manually ("manual").
:ivar streams:
A list of streams currently being broadcasted. This is only set for a broadcast with
Expand All @@ -71,6 +78,8 @@ def __init__(self, kwargs):
self.updatedAt = kwargs.get("updatedAt")
self.hasAudio = kwargs.get("hasAudio")
self.hasVideo = kwargs.get("hasVideo")
self.maxBitrate = kwargs.get("maxBitrate")
self.maxDuration = kwargs.get("maxDuration")
self.resolution = kwargs.get("resolution")
self.status = kwargs.get("status")
self.broadcastUrls = kwargs.get("broadcastUrls")
Expand All @@ -83,8 +92,9 @@ def json(self):
"""
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)


class BroadcastStreamModes(Enum):
""""List of valid settings for the stream_mode parameter of the OpenTok.start_broadcast()
""" "List of valid settings for the stream_mode parameter of the OpenTok.start_broadcast()
method."""

auto = u("auto")
Expand Down
12 changes: 10 additions & 2 deletions opentok/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ class BroadcastError(OpenTokException):

pass


class DTMFError(OpenTokException):
"""
Indicates that one of the properties digits, session_id or connection_id is invalid
"""


class ArchiveStreamModeError(OpenTokException):
"""
Indicates that the archive is configured with a streamMode that does not support stream manipulation.
Expand All @@ -110,12 +112,18 @@ class BroadcastStreamModeError(OpenTokException):

class BroadcastHLSOptionsError(OpenTokException):
"""
Indicates that HLS options have been set incorrectly.
Indicates that HLS options have been set incorrectly.
dvr and lowLatency modes cannot both be set to true in a broadcast.
"""


class BroadcastOptionsError(OpenTokException):
"""
Indicates that broadcast options have been set incorrectly.
"""


class InvalidWebSocketOptionsError(OpenTokException):
"""
Indicates that the WebSocket options selected are invalid.
Expand Down
79 changes: 40 additions & 39 deletions opentok/opentok.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from .websocket_audio_connection import WebSocketAudioConnection
from .exceptions import (
ArchiveStreamModeError,
BroadcastOptionsError,
BroadcastHLSOptionsError,
BroadcastStreamModeError,
OpenTokException,
Expand Down Expand Up @@ -1170,7 +1171,7 @@ def set_archive_layout(
else:
raise RequestError("OpenTok server error.", response.status_code)

def dial(self, session_id, token, sip_uri, options=[]):
def dial(self, session_id, token, sip_uri, options={}):
"""
Use this method to connect a SIP platform to an OpenTok session. The audio from the end
of the SIP call is added to the OpenTok session as an audio-only stream. The OpenTok Media
Expand Down Expand Up @@ -1213,27 +1214,30 @@ def dial(self, session_id, token, sip_uri, options=[]):
in the OpenTok stream that is sent to the OpenTok session. The SIP client will receive a single
composed video of the published streams in the OpenTok session.
This is an example of what the payload POST data body could look like:
List 'streams': An array of stream IDs for streams to include in the SIP call.
If you do not set this property, all streams in the session are included in the call.
This is an example of what the payload POST data dictionary could look like:
{
"sessionId": "Your OpenTok session ID",
"token": "Your valid OpenTok token",
"sip": {
"uri": "sip:[email protected];transport=tls",
"from": "[email protected]",
"headers": {
"headerKey": "headerValue"
},
"uri": "sip:[email protected];transport=tls",
"from": "[email protected]",
"headers": {
"headerKey": "headerValue"
},
"auth": {
"username": "username",
"password": "password"
},
"secure": true|false,
"observeForceMute": true|false,
"video": true|false
}
"secure": True,
"video": True,
"observeForceMute": True,
"streams": ["stream-id-1", "stream-id-2"]
}
}
:rtype: A SipCall object, which contains data of the SIP call: id, connectionId and streamId.
This is what the response body should look like after returning with a status code of 200:
Expand All @@ -1246,29 +1250,9 @@ def dial(self, session_id, token, sip_uri, options=[]):
Note: Your response will have a different: id, connectionId and streamId
"""
payload = {"sessionId": session_id, "token": token, "sip": {"uri": sip_uri}}
observeForceMute = False
video = False

if "from" in options:
payload["sip"]["from"] = options["from"]

if "headers" in options:
payload["sip"]["headers"] = options["headers"]

if "auth" in options:
payload["sip"]["auth"] = options["auth"]

if "secure" in options:
payload["sip"]["secure"] = options["secure"]

if "observeForceMute" in options:
observeForceMute = True
payload["sip"]["observeForceMute"] = options["observeForceMute"]

if "video" in options:
video = True
payload["sip"]["video"] = options["video"]
payload = {"sessionId": session_id, "token": token, "sip": {"uri": sip_uri}}
payload.update(options)

endpoint = self.endpoints.dial_url()

Expand Down Expand Up @@ -1367,11 +1351,11 @@ def start_broadcast(
:param String session_id: The session ID of the OpenTok session you want to broadcast
:param Boolean optional hasAudio: Whether the stream is broadcast with audio.
:param Dictionary options, with the following properties:
:param Boolean optional hasVideo: Whether the stream is broadcast with video.
:param Boolean optional hasAudio: Whether the stream is broadcast with audio.
:param Dictionary options, with the following properties:
:param Boolean optional hasVideo: Whether the stream is broadcast with video.
Dictionary 'layout' optional: Specify this to assign the initial layout type for the
broadcast.
Expand All @@ -1392,6 +1376,9 @@ def start_broadcast(
set the maximum duration to a value from 60 (60 seconds) to 36000 (10 hours). The
default maximum duration is 4 hours (14,400 seconds)
Integer 'maxBitrate' optional: The maximum bitrate (bits per second) used by the broadcast.
Value must be between 100_000 and 6_000_000.
Dictionary 'outputs': This object defines the types of broadcast streams you want to
start (both HLS and RTMP). You can include HLS, RTMP, or both as broadcast streams.
If you include RTMP streaming, you can specify up to five target RTMP streams. For
Expand Down Expand Up @@ -1448,6 +1435,16 @@ def start_broadcast(
'HLS options "lowLatency" and "dvr" cannot both be set to "True".'
)

if "maxBitrate" in options:
if (
type(options["maxBitrate"]) != int
or options["maxBitrate"] < 100000
or options["maxBitrate"] > 6000000
):
raise BroadcastOptionsError(
"maxBitrate must be an integer between 100000 and 6000000."
)

payload = {"sessionId": session_id, "streamMode": stream_mode.value}

payload.update(options)
Expand Down Expand Up @@ -1578,7 +1575,9 @@ def add_broadcast_stream(
"Your broadcast is configured with a streamMode that does not support stream manipulation."
)
elif response.status_code == 409:
raise BroadcastError("The broadcast has already started for the session.")
raise BroadcastError(
"The broadcast has already started for the session."
)
else:
raise RequestError("An unexpected error occurred.", response.status_code)

Expand Down Expand Up @@ -1621,7 +1620,9 @@ def remove_broadcast_stream(
"Your broadcast is configured with a streamMode that does not support stream manipulation."
)
elif response.status_code == 409:
raise BroadcastError("The broadcast has already started for the session.")
raise BroadcastError(
"The broadcast has already started for the session."
)
else:
raise RequestError("OpenTok server error.", response.status_code)

Expand Down
2 changes: 1 addition & 1 deletion opentok/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# see: http://legacy.python.org/dev/peps/pep-0440/#public-version-identifiers
__version__ = "3.6.1"
__version__ = "3.7.0"

Loading

0 comments on commit 132c8d4

Please sign in to comment.