Skip to content

Commit 43b00d0

Browse files
authored
Merge pull request #208 from opentok/add-rendering-api
Add rendering api
2 parents 2218083 + aeaa669 commit 43b00d0

File tree

5 files changed

+423
-0
lines changed

5 files changed

+423
-0
lines changed

opentok/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
from .streamlist import StreamList
1515
from .sip_call import SipCall
1616
from .broadcast import Broadcast, BroadcastStreamModes
17+
from .render import Render, RenderList

opentok/endpoints.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,11 @@ def get_broadcast_stream(self, broadcast_id=None):
200200
)
201201

202202
return url
203+
204+
def get_render_url(self, render_id: str = None):
205+
"Returns URLs for working with the Render API."""
206+
url = self.api_url + "/v2/project/" + self.api_key + "/render"
207+
if render_id:
208+
url += "/" + render_id
209+
210+
return url

opentok/opentok.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from .endpoints import Endpoints
2929
from .session import Session
3030
from .archives import Archive, ArchiveList, OutputModes, StreamModes
31+
from .render import Render, RenderList
3132
from .stream import Stream
3233
from .streamlist import StreamList
3334
from .sip_call import SipCall
@@ -1615,6 +1616,164 @@ def set_broadcast_layout(self, broadcast_id, layout_type, stylesheet=None, scree
16151616
else:
16161617
raise RequestError("OpenTok server error.", response.status_code)
16171618

1619+
def start_render(self, session_id, opentok_token, url, max_duration=7200, resolution="1280x720", status_callback_url=None, properties: dict = None):
1620+
"""
1621+
Starts an Experience Composer for the specified OpenTok session.
1622+
For more information, see the
1623+
`Experience Composer developer guide <https://tokbox.com/developer/guides/experience-composer>`_.
1624+
1625+
:param String 'session_id': The session ID of the OpenTok session that will include the Experience Composer stream.
1626+
:param String 'token': A valid OpenTok token with a Publisher role and (optionally) connection data to be associated with the output stream.
1627+
:param String 'url': A publically reachable URL controlled by the customer and capable of generating the content to be rendered without user intervention.
1628+
:param Integer 'maxDuration' Optional: The maximum time allowed for the Experience Composer, in seconds. After this time, it is stopped automatically, if it is still running. The maximum value is 36000 (10 hours), the minimum value is 60 (1 minute), and the default value is 7200 (2 hours). When the Experience Composer ends, its stream is unpublished and an event is posted to the callback URL, if configured in the Account Portal.
1629+
:param String 'resolution' Optional: The resolution of the Experience Composer, either "640x480" (SD landscape), "480x640" (SD portrait), "1280x720" (HD landscape), "720x1280" (HD portrait), "1920x1080" (FHD landscape), or "1080x1920" (FHD portrait). By default, this resolution is "1280x720" (HD landscape, the default).
1630+
:param Dictionary 'properties' Optional: Initial configuration of Publisher properties for the composed output stream.
1631+
String name Optional: The name of the composed output stream which will be published to the session. The name must have a minimum length of 1 and a maximum length of 200.
1632+
"""
1633+
payload = {
1634+
"sessionId": session_id,
1635+
"token": opentok_token,
1636+
"url": url,
1637+
"maxDuration": max_duration,
1638+
"resolution": resolution,
1639+
"properties": properties
1640+
}
1641+
1642+
logger.debug(
1643+
"POST to %r with params %r, headers %r, proxies %r",
1644+
self.endpoints.get_render_url(),
1645+
json.dumps(payload),
1646+
self.get_json_headers(),
1647+
self.proxies,
1648+
)
1649+
1650+
response = requests.post(
1651+
self.endpoints.get_render_url(),
1652+
json=payload,
1653+
headers=self.get_json_headers(),
1654+
proxies=self.proxies,
1655+
timeout=self.timeout,
1656+
)
1657+
1658+
if response and response.status_code == 202:
1659+
return Render(response.json())
1660+
elif response.status_code == 400:
1661+
"""
1662+
The HTTP response has a 400 status code in the following cases:
1663+
You do not pass in a session ID or you pass in an invalid session ID.
1664+
You specify an invalid value for input parameters.
1665+
"""
1666+
raise RequestError(response.json().get("message"))
1667+
elif response.status_code == 403:
1668+
raise AuthError("You passed in an invalid OpenTok API key or JWT token.")
1669+
else:
1670+
raise RequestError("An unexpected error occurred", response.status_code)
1671+
1672+
1673+
def get_render(self, render_id):
1674+
"""
1675+
This method allows you to see the status of a render, which can be one of the following:
1676+
['starting', 'started', 'stopped', 'failed']
1677+
1678+
:param String 'render_id': The ID of a specific render.
1679+
"""
1680+
logger.debug(
1681+
"GET to %r with headers %r, proxies %r",
1682+
self.endpoints.get_render_url(render_id=render_id),
1683+
self.get_json_headers(),
1684+
self.proxies,
1685+
)
1686+
1687+
response = requests.get(
1688+
self.endpoints.get_render_url(render_id=render_id),
1689+
headers=self.get_json_headers(),
1690+
proxies=self.proxies,
1691+
timeout=self.timeout,
1692+
)
1693+
1694+
if response.status_code == 200:
1695+
return Render(response.json())
1696+
elif response.status_code == 400:
1697+
raise RequestError(
1698+
"Invalid request. This response may indicate that data in your request is invalid JSON. Or it may indicate that you do not pass in a session ID."
1699+
)
1700+
elif response.status_code == 403:
1701+
raise AuthError("You passed in an invalid OpenTok API key or JWT token.")
1702+
elif response.status_code == 404:
1703+
raise NotFoundError("No render matching the specified render ID was found.")
1704+
else:
1705+
raise RequestError("An unexpected error occurred", response.status_code)
1706+
1707+
def stop_render(self, render_id):
1708+
"""
1709+
This method stops a render.
1710+
1711+
:param String 'render_id': The ID of a specific render.
1712+
"""
1713+
logger.debug(
1714+
"DELETE to %r with headers %r, proxies %r",
1715+
self.endpoints.get_render_url(render_id=render_id),
1716+
self.get_headers(),
1717+
self.proxies,
1718+
)
1719+
1720+
response = requests.delete(
1721+
self.endpoints.get_render_url(render_id=render_id),
1722+
headers=self.get_headers(),
1723+
proxies=self.proxies,
1724+
timeout=self.timeout,
1725+
)
1726+
1727+
if response.status_code == 200:
1728+
return response
1729+
elif response.status_code == 400:
1730+
raise RequestError(
1731+
"Invalid request. This response may indicate that data in your request is invalid JSON. Or it may indicate that you do not pass in a session ID."
1732+
)
1733+
elif response.status_code == 403:
1734+
raise AuthError("You passed in an invalid OpenTok API key or JWT token.")
1735+
elif response.status_code == 404:
1736+
raise NotFoundError("No render matching the specified render ID was found.")
1737+
else:
1738+
raise RequestError("An unexpected error occurred", response.status_code)
1739+
1740+
def list_renders(self, offset=0, count=50):
1741+
"""
1742+
List existing renders associated with the project's API key.
1743+
1744+
:param Integer 'offset' Optional: Start offset in the list of existing renders.
1745+
:param Integer 'count' Optional: Number of renders to retrieve, starting at 'offset'.
1746+
"""
1747+
1748+
query_params = {"offset": offset, "count": count}
1749+
1750+
logger.debug(
1751+
"GET to %r with headers %r, params %r, proxies %r",
1752+
self.endpoints.get_render_url(),
1753+
self.get_headers(),
1754+
query_params,
1755+
self.proxies,
1756+
)
1757+
1758+
response = requests.get(
1759+
self.endpoints.get_render_url(),
1760+
headers=self.get_headers(),
1761+
params=query_params,
1762+
proxies=self.proxies,
1763+
timeout=self.timeout,
1764+
)
1765+
1766+
if response.status_code == 200:
1767+
return RenderList(self, response.json())
1768+
elif response.status_code == 400:
1769+
raise RequestError(
1770+
"Invalid request. This response may indicate that data in your request is invalid JSON. Or it may indicate that you do not pass in a session ID."
1771+
)
1772+
elif response.status_code == 403:
1773+
raise AuthError("You passed in an invalid OpenTok API key or JWT token.")
1774+
else:
1775+
raise RequestError("An unexpected error occurred", response.status_code)
1776+
16181777
def _sign_string(self, string, secret):
16191778
return hmac.new(
16201779
secret.encode("utf-8"), string.encode("utf-8"), hashlib.sha1

opentok/render.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import json
2+
from six import iteritems
3+
4+
class Render:
5+
"""Represents an Experience Composer render of an OpenTok session."""
6+
7+
def __init__(self, kwargs):
8+
self.id = kwargs.get("id")
9+
self.sessionId = kwargs.get("sessionId")
10+
self.projectId = kwargs.get("projectId")
11+
self.createdAt = kwargs.get("createdAt")
12+
self.updatedAt = kwargs.get("updatedAt")
13+
self.url = kwargs.get("url")
14+
self.resolution = kwargs.get("resolution")
15+
self.status = kwargs.get("status")
16+
self.streamId = kwargs.get("streamId") or None
17+
self.reason = kwargs.get("reason") or None
18+
19+
def json(self):
20+
"""Returns a JSON representation of the render."""
21+
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
22+
23+
def attrs(self):
24+
"""
25+
Returns a dictionary of the render's attributes.
26+
"""
27+
return dict((k, v) for k, v in iteritems(self.__dict__))
28+
29+
class RenderList:
30+
"""Object that represents a list of renders."""
31+
def __init__(self, sdk, values):
32+
self.count = values.get("count")
33+
self.items = list(map(lambda x: Render(x), values.get("items", [])))
34+
35+
def attrs(self):
36+
return {"count": self.count, "items": map(Render.attrs, self.items)}
37+
38+
def json(self):
39+
return json.dumps(self.attrs(), indent=4)

0 commit comments

Comments
 (0)