We use cookies to enhance your browsing experience, serve personalized ads or content, and analyze our traffic. By clicking "Accept All", you consent to our use of cookies. Click here for more information on our Privacy Policy.
Customize Consent Preferences
We use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.
The cookies that are categorized as "Necessary" are stored on your browser as they are essential for enabling the basic functionalities of the site. ...
Always Active
Necessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.
No cookies to display.
Functional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.
No cookies to display.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.
No cookies to display.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
No cookies to display.
Advertisement cookies are used to provide visitors with customized advertisements based on the pages you visited previously and to analyze the effectiveness of the ad campaigns.
The intent of this document is to provide information for developers using the iOS Mobile SDK on migrating from Stream Manager 1.0 integration to Stream Manager 2.0 integration for mobile clients.
The architecture of an autoscale environment under a Stream Manager deployment is such that Origin and Edge nodes are dynamically spun up and torn down in response to publisher and subscriber amounts within respect to their node configuration settings. It is too much for this document to cover such a topic, but is important to note that the Stream Manager API provides the ability to request which Origin or Edge node to publish or subscriber on, respectively, for mobile clients over RTSP.
The following information in this document describes how this was achieved previously in the Stream Manager 1.0 release and how to migrate your code to integration with the Stream Manager 2.0 release.
Integrating web clients using the Red5 WebRTC SDK and Stream Manager 1.0 involved first making an API request for either the Origin or Edge (for publisher or subscriber, respectively), then responding to the payload to assign the target node IP as the host on the R5Configuration for the client, e.g.,:
func requestOrigin(_ url:String, resolve:@escaping(_ ip:String?, _ error:Error?)->Void){NSURLConnection.sendAsynchronousRequest(NSURLRequest( url: NSURL(string: url)!as URL )asURLRequest,
queue:OperationQueue(),
completionHandler:{(response:URLResponse?, data:Data?, error:Error?)->Voidinif((error)!=nil){print(error)return}// Convert our response to a usable NSStringlet dataAsString =NSString( data: data!, encoding:String.Encoding.utf8.rawValue)// The string above is in JSON format, we specifically need the serverAddress valuevar json:[String:AnyObject]do{
json =tryJSONSerialization.jsonObject(with: data!, options:JSONSerialization.ReadingOptions())as![String:AnyObject]}catch{print(error)return}iflet ip = json["serverAddress"]as?String{print("Retrieved %@ from %@, of which the usable IP is %@", dataAsString!, url, ip);
resolve(ip,nil)}elseiflet errorMessage = json["errorMessage"]as?String{print(AccessError.error(message: errorMessage))}})}
func startPublish()->Void{let host ="streammanager.red5.host"let app ="live"let streamName ="stream1"let url ="https://(host)/streammanager/api/4.0/event/(app)/(streamName)?action=broadcast"
requestOrigin(url,(_ ip:String?, _ error:Error?)->Void){let config = R5Configuration()
config.host = ip
config.port =8554
config.contextName = app
// Create a new connection using the configuration abovelet connection = R5Connection(config: config)let publishStream = R5Stream(connection: connection)// Attach media...
publishStream.publish(streamName, type: R5RecordTypeLive)})}
Unlike the Red WebRTC SDK – which requires the Stream Manager endpoint to act as a proxy due to browser security restrictions – the RTSP connection used in the iOS Mobile SDK can take the IP of the node returned by the REST request from Stream Manager.
With the release of Stream Manager 2.0, Node Groups and their configurations play a more significant role in the autoscale functionality. As such, the target node group for streaming is required in the REST call in obtaining an Origin or Edge.
Additionally, the response payload for Node request differs slightly from that of Stream Manager 1.0 API.
func requestOrigin(_ url:String, resolve:@escaping(_ ip:String?, _ error:Error?)->Void){NSURLConnection.sendAsynchronousRequest(NSURLRequest( url: NSURL(string: url)!as URL )asURLRequest,
queue:OperationQueue(),
completionHandler:{(response:URLResponse?, data:Data?, error:Error?)->Voidinif((error)!=nil){print(error)return}// Convert our response to a usable NSStringlet dataAsString =NSString( data: data!, encoding:String.Encoding.utf8.rawValue)// The string above is in JSON format, we specifically need the serverAddress valuevar json:[[String:AnyObject]]do{
json =tryJSONSerialization.jsonObject(with: data!, options:JSONSerialization.ReadingOptions())as![[String:AnyObject]]}catch{print(error)return}iflet origin = json.first {iflet ip = origin["serverAddress"]as?String,let guid = origin["streamGuid"]as?String{print("Retrieved %@ from %@, of which the usable IP is %@", dataAsString!, url, ip);
resolve(ip, guid,nil)}elseiflet errorMessage = origin["errorMessage"]as?String{print(AccessError.error(message: errorMessage))}}})}
func startPublish()->Void{let host ="streammanager.red5.host"let app ="live"let streamName ="stream1"let nodeGroup ="nodegroup-oci"let url ="https://(host)/as/v1/streams/stream/(nodeGroup)/publish/(app)/(streamName)"
requestOrigin(url,(_ ip:String?, _ streamGuid:String?, _ error:Error?)->Void){var paths = streamGuid?.split(separator:"/")let name =String((paths?.popLast())!)let scope = paths?.joined(separator:"/")let config = R5Configuration()
config.host = ip
config.port =8554
config.contextName = scope
// Create a new connection using the configuration abovelet connection = R5Connection(config: config)let publishStream = R5Stream(connection: connection)// Attach media...
publishStream.publish(streamName, type: R5RecordTypeLive)}}
While the above example demonstrates making requests for an Origin node for a publishing client, the URI component of the URL request can be changed from publish to subscribe to access an Edge node for subscribing.
The Red5 Server supports Adaptive Bitrate (ABR) streaming through the submission of Provisions to the Stream Manager. The provision structure – which will be detailed for both Stream Manager 1.0 and Stream Manager 2.0 in this section – consists of a listing of variants of stream properties, of which the highest variant is expected to be delivered in a stream related to the associated Stream GUID; the server will handle transcoding the lower variants for delivery to subscribing clients based on bandwidth estimation.
With the Stream Manager 2.0 release, the endpoint to submit provision requests has changed as well as the structure of the provision to submit and the return payload.
Additionally, while both versions require authentication credentials, Stream Manager 2.0 authentication is based on JWT and requires a token to perform administrative tasks – such as provisioning.
Whe submitting provisions to Stream Manager 1.0, an accessToken was used for authentication of the request. This accessToken was a value pre-defined for your Stream Manager 1.0 deployment and shared with only those that were privy to perform administrative tasks.
The URL structure for provision submission was the following:
The stream listing of the provision details the variant ladder of streams that the server will generate for consumption. In order for the ABR streams to be made available related to the stream name GUID (that is stream1 in these examples and used to construct the request URL in the previous section), a publish stream is then expected to be started for the top-level variant (stream1_1) with the bitrate and resolution defined.
As such, the URL to access a Node address to stream the top-level variant through Stream Manager 1.0 was slightly different than the basic node request:
func startPublish()->Void{let host ="streammanager.red5.host"let app ="live"let streamName ="stream1"let url ="https://(host)/streammanager/api/4.0/event/(app)/(streamName)?action=broadcast&transcode=true"
requestOrigin(url,(_ ip:String?, _ error:Error?)->Void){let config = R5Configuration()
config.host = ip
config.port =8554
config.contextName = app
// Create a new connection using the configuration abovelet connection = R5Connection(config: config)let publishStream = R5Stream(connection: connection)// Attach media...
publishStream.publish("(streamName)_1", type: R5RecordTypeLive)})}
Of note in the above example is the addition of transcode=true to the query parameters for Node address request, and the subsequent call to pushing with stream name "(streamName)_1", denoting that the client is going to be streaming with the highest variant quality to be transcoded.
As mentioned at the start of this section, the authentication process for administrative tasks is different between Stream Manager 1.0 and Stream Manager 2.0, mainly in the fact that all requests as such require a JWT token in Stream Manager 2.0. You can access a JWT token by authenticating with a username and password defined in the Stream Manager 2.0 deployment.
With the username and password known, you can access a JWT token in order to submit an ABR provision as follows:
func authenticate(host:String, username:String, password:String, resolve:@escaping(_ token:String?, _ error:Error?)->Void){let data ="(username):(password)".data(using:.utf8)!let base64String = data.base64EncodedString()let url ="https://(host)/as/v1/auth/login"var request =URLRequest(url: URL(string: url)!)
request.httpMethod ="PUT"
request.setValue("Basic (base64String)", forHTTPHeaderField:"Authorization")let session =URLSession.shared
let task = session.dataTask(with: request){ data, response, error iniflet error = error {print("Error: (error)")return}iflet httpResponse = response as?HTTPURLResponse{print("Status code: (httpResponse.statusCode)")iflet data = data {if(httpResponse.statusCode >=200&& httpResponse.statusCode <300){var json:[String:AnyObject]do{
json =tryJSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions())as![String:AnyObject]iflet token = json["token"]as?String{
resolve(token,nil)}}catch{print("Could not Authenticate to post Provisions.")return}}}}}
task.resume()}
With the JWT token accessed through authentication, a submission of ABR pvovision can be achieved as such providing the Bearer token in an Auth Header:
The schema of a Provision to be submitted to Stream Manager 2.0 differs slightly from that delivered to Stream Manager 1.0. Here is an example of the Provision schema for Stream Manager 2.0:
To begin a stream with the high-level variant is variant similar to a non-ABR stream, but with the transcode=true query parameter appended. This allows the Stream Manager 2.0 to know to direct the stream to a Transcoder Node:
func startPublish(_ streamGuid:String/* e.g., live/stream1_1 */)->Void{let host ="streammanager.red5.host"let nodeGroup ="nodegroup-oci"let url ="https://(host)/as/v1/streams/stream/(nodeGroup)/publish/(streamGuid)?transcode=true"
requestOrigin(url,(_ ip:String?, _ streamGuid:String?, _ error:Error?)->Void){var paths = streamGuid?.split(separator:"/")let name =String((paths?.popLast())!)let scope = paths?.joined(separator:"/")let config = R5Configuration()
config.host = ip
config.port =8554
config.contextName = scope
// Create a new connection using the configuration abovelet connection = R5Connection(config: config)let publishStream = R5Stream(connection: connection)// Attach media...
publishStream.publish(name, type: R5RecordTypeLive)})}
Subscribing to an ABR Variant
It should be noted that accessing an Edge address for a subscriber client for ABR support is very similar to that of a non-ABR subscriber. The only difference is that the stream name in the request would be the initial desired variant and not the top-level GUID for the stream, i.e.,:
The Stream Manager 2.0 will return the Edge node address to be used in configuration of the RTSP Subscriber client and will initially deliver the variant stream defined. As network conditions change for the subscriber client, so will the variant stream being delivered.