Learn how to add a player view to a Wowza GoCoder™ SDK for iOS app and play an ultra low latency live stream from the Wowza Streaming Cloud™ service.
Notes:
- Creating ultra low latency stream targets requires a separate subscription to Wowza Streaming Cloud with Ultra Low Latency.
- Playback over SSL isn't supported by GoCoder SDK at this time.
Before you begin
Before adding the functionality below to an app, make sure you've set up the Wowza GoCoder SDK for your project:
- Request a free license and download the latest version of the SDK.
- Configure your Xcode project to use the SDK.
See Download and install GoCoder SDK for iOS for detailed instructions.
Set up an ultra low latency stream target in Wowza Streaming Cloud
For Wowza Gocoder playback from the Wowza Streaming Cloud with Ultra Low Latency service, start by setting up an ultra low latency stream target. For instructions, see one of these resources:
- Get started with ultra low latency streaming using the Wowza Streaming Cloud REST API
- Add an ultra low latency stream target
Note: If you want to configure the ultra low latency target to enable HLS fallback, you must do so while creating the target. HLS fallback helps ensure successful playback but increases latency.
After you set up the stream target, note the WOWZ Playback URL and the optional HLS fallback URL, as you will use them to set up the WowzaConfig object.
Add a player view to an app
Use the WOWZPlayer and WowzaConfig classes to add a player view to an app.
- Create configuration and player properties.
#pragma mark - GoCoder SDK Components @property (nonatomic, strong) WowzaConfig *goCoderConfig; @property (nonatomic, strong) WOWZPlayer *player;
- Create a WOWZPlayer object and, if desired, register it for data events.
// Register the GoCoder SDK license key NSString *SDKSampleAppLicenseKey = @"your-GoCoder-SDK-license-key"; NSError *goCoderLicensingError = [WowzaGoCoder registerLicenseKey:SDKSampleAppLicenseKey]; if (goCoderLicensingError != nil) { // Handle license key registration failure } else { self.player = [WOWZPlayer new]; //Set default preroll buffer duration if you want a preroll buffer before a stream starts self.player.prerollDuration = 3; // 1-3 second buffer //Optionally set up data sink to handle in-stream events [self.player registerDataSink:self eventName:@"onTextData"]; }
- Implement the WOWZPlayerStatusCallback methods to respond and assign your player view.
#pragma mark - WOWZPlayerStatusCallback Protocol Instance Methods - (void) onWOWZStatus:(WOWZPlayerStatus *) goCoderStatus { // A successful status transition has been reported by the GoCoder SDK switch (goCoderStatus.state) { case WOWZPlayerStateIdle: break; case WOWZPlayerStateConnecting: // A streaming playback session is connecting to a Wowza Streaming Cloud edge. self.player.playerView = self.view; break; case WOWZPlayerStateBuffering: break; case WOWZPlayerStatePlaying: break; case WOWZPlayerStateStopping: break; default: break; } }
Configure the streaming server
Specify the streaming server connection properties.
- Write a configuration method that instantiates and assigns a configuration object to your property.
-(void)setupConfig{ WowzaConfig *config = [WowzaConfig new]; config.hostAddress = @"your_server_ip"; config.portNumber = 1935; config.streamName = @"your_stream_name"; config.applicationName = @"your_application_name"; config.audioEnabled = YES; config.videoEnabled = YES; self.goCoderConfig = config; }
Parse the ultra low latency WOWZ playback URL to get the necessary values. For example, using this WOWZ playback URL,
wowz://edge.cdn.wowza.com/live/_definst_/0ABC2R1FvREJWak43cmxBOGhQTH12345
The configuration should look something like this:-(void)setupConfig{ WowzaConfig *config = [WowzaConfig new]; config.hostAddress = @"edge.cdn.wowza.com"; config.portNumber = 1935; config.streamName = @"0ABC2R1FvREJWak43cmxBOGhQTH12345"; config.applicationName = @"live"; config.audioEnabled = YES; config.videoEnabled = YES; self.goCoderConfig = config; }
- Call the configuration method.
- (void)viewDidLoad { [super viewDidLoad]; [self setupConfig];
- Instruct the self.player object to play with the configuration method and register self as a delegate for callbacks.
- (IBAction) didTapPlaybackButton:(id)sender { if ([self.player currentPlayState] == WOWZPlayerStateIdle) { [self.player play:self.goCoderConfig callback:self]; } else { [self.player stop]; } }
Configure HLS fallback
You can instruct the Wowza GoCoder SDK app to play an HLS stream as a fallback if the primary ultra low latency WOWZ over Websocket stream fails to connect.
HLS fallback also helps with viewer limits. Ultra low latency streams are subject to a default viewer limit of simultaneous viewers per stream according to the subscription plan you select. If this limit is exceeded, new stream viewers will receive an error and won't be able to establish a connection. If you have enabled and configured HLS as a backup for playback, ultra low latency stream viewers beyond the allotted limit can view the steam via the fallback HLS connection. See Wowza Streaming Cloud REST API limits for more information about limits.
Use the following properties in WowzaConfig to set up HLS fallback:
Property | Type | Description |
allowHLSPlayback | Boolean | Specify true to enable HLS fallback. When enabled, the player will switch to the HLS URL after three failed attempts to play over the primary protocol. |
hlsURL | string | The .m3u8 HLS playlist URL from the Wowza Streaming Cloud ultra low latency stream target. This is an NSString object. |
Update the WowzaConfig object to add the HLS fallback properties:
-(void)setupConfig{ WowzaConfig *config = [WowzaConfig new]; config.hostAddress = @"your_server_ip"; config.portNumber = 1935; config.streamName = @"your_stream_name"; config.applicationName = @"your_application_name"; config.audioEnabled = YES; config.videoEnabled = YES; //Configure HLS fallback config.allowHLSPlayback = YES; config.hlsURL = @"your_hls_playback_url"; self.goCoderConfig = config; }
Set play options
syncOffset
If your source stream has a constant audio/video sync offset, use the syncOffset option to adjust how the audio/video sync is set.
-(IBAction)syncSliderChanged:(id)sender { UISlider *slider = (UISlider *)sender; Float32 value = slider.value; self.player.syncOffset = value; }
prerollDuration
Use the prerollDuration option to set the time, in seconds, that the stream should buffer before playing.
self.player.prerollDuration = 3; //3 second buffer.
play and stop
Use play to start playing the stream and stop to stop playing the stream.
- (IBAction) didTapPlaybackButton:(id)sender { if ([self.player currentPlayState] == WOWZStateIdle) { [self.player play:self.goCoderConfig callback:self]; } else { [self.player stop]; } }
mute
Use the mute option to silence the audio of the stream.
- (IBAction)didTapMuteButton:(id)sender { self.player.muted = !self.player.muted; UIImage *muteButtonImage = [UIImage imageNamed:self.player.muted ? @"volume_mute" : @"volume_unmute"]; [self.muteButton setImage:muteButtonImage forState:UIControlStateNormal]; self.volumeSlider.enabled = !self.player.muted; }
volume
Use the volume option to adjust the audio volume of the stream.
- (IBAction)didChangeVolume:(id)sender { UISlider *slider = (UISlider *)sender; self.player.volume = slider.value; }
playerViewGravity
Use the following playerViewGravity properties to specify how the player preview should display:
Property | Description |
WOWZPlayerViewGravityResizeAspect | Scale the camera preview to fit within the screen area. Letterboxing may be applied to maintain the aspect ratio. |
WOWZPlayerViewGravityResizeAspectFitFill | Scale the camera preview to fill the screen area. The preview may be cropped to maintain the aspect ratio. |
Set the previewGravity mode.
self.player.playerViewGravity = WOWZPlayerViewGravityResizeAspect;
Get the bitrate during playback
You can get the bitrate of a live stream as it's received across the network socket for playback.
The bitrate is updated every three seconds based on the average bitrate from the start of playback to the current time.
You can get the bitrate either by using the currentInjestBitrate property in the WowzaPlayer class or by listening for the value with NSNotificationCenter.
To get the bitrate by using currentInjestBitrate:
// Get the bitrate of the stream at the network socket self.player.currentInjestBitrate
To listen for the bitrate:
// Listen for the bitrate of the stream at the network socket name@"WOWZBitrateUpdate" object:nil