Release Notes
The most current release of the iOS SDK is 2022.0.3
Release notes for this version are shown below, followed by notes from prior releases.
To get the iOS SDK for a specific version, update the Phenix SDK version Podfile to match the version number
followed by '-beta', e.g., 2021.0.15-beta
, or contact Phenix for the iOS SDK download location.
Some versions require additional integration steps; these are called out in the version-specific release notes.
v2022.0.5 Release Notes
Release Date: 2022.12.02
Features/Improvements
-
Now available in both SPM and CocoaPods
-
Added support for VP9 encoding/decoding
-
Channel or room ID/alias provided in the publish token is used to publish the stream
Fixes/Updates
- Various low-level bug fixes and improvements to stability
v2022.0.3 Release Notes
Release Date: 2022.07.27
Features/Improvements
-
Added support for using a different CDN domain for playlists.
-
Added support for PCastUri in tokens.
-
Added support for channel/room alias or ID in tokens.
-
Improved network usage.
-
Improved video performance and compatibility
Fixes
-
Fixed chat room's messages loss in case of network issues.
-
Fixed late PhenixChannelExpress.joinChannel callback call in case of network issues.
-
Updated third-party library dependencies, including update to address potential expat vulnerability
-
Removed hardcoded TLS certificate and RSA key
-
ARMv7 and ARMv7s architectures are no longer supported
v2022.0.3 Notes
CDN Domain support
The SDK can now send HTTP requests to URLs that redirect to non-Phenix CDNs for replays or for VOD playlists.
To use alternate CDN domains, use the capability cdn-domain on viewing channels, with the CDN domain as its value. Do not include the protocol prefix (e.g., https://) in the value. For example: cdn-domain=mycdn.mycompany.com
The platform will replace the default streaming domain with the specified CDN domain in playlist URLs for the primary manifest of the content.
PCast™ URI in tokens
A PCast™ URI contained in the token will now be used instead of a URI passed as a parameter. Putting the URI in the token is now the preferred behavior, and passing in a PCast™ URI as a parameter is now deprecated. To include the URI in the token, add the uri capability as described in the EdgeAuth library documentation.
If the token contains a URI that differs from the one passed as a parameter, the URI from the token is used and a warning is written to the log.
Room/Channel ID/Alias in tokens
A room/channel ID or alias passed in the token will be used to join the respective room or channel. As with the PCast™ URI, putting the Room or Channel ID or Alias in the token is now the preferred behavior, and passing in that information as a parameter is now deprecated and will generate a deprecation warning in the log. To include the Room or Channel information in the token, add the roomId, channelId, roomAlias or channelAlias capability as described in the EdgeAuth library documentation.
If a value is provided both as a direct parameter and in the token, the values must match; otherwise the operation will fail.
Improved network usage
When using previous releases, Room members rejoining after network changes would sometimes cause zombie room members. This has been improved and the behavior in case of network changes is more consistent.
In addition, network usage is reduced when downloading stream replay segments.
Fixed chat room messages loss in case of network issues
Previously, any messages still cached by the SDK during reconnection after a network change were silently discarded. Now they are preserved and will be returned by the next call to GetLastMessages. In addition, an issue has been fixed where new messages were discarded instead of old ones when there were many cached and incoming messages.
Upon lost network connectivity, the SDK will now keep trying to reconnect instead of ceasing to retry after a few minutes.
v2021.0.15 Pre-release Notes
Release Date: 2021.08.18
Features/Improvements
No customer-impacting changes.
v2021.0.14 Pre-release Notes
Release Date: 2021.08.09
Features/Improvements
No customer-impacting changes.
v2021.0.11 Pre-release Notes
Release Date: 2021.06.08
Features/Improvements
- Increased internal timeout when connecting to PCast™ platform to avoid SDK initialization failures on clients with lossy network connections
Fixes
- Fixed memory leaks occurring when stopping a room publisher
v2021.0.8 Pre-release Notes
Release Date: 2021.05.14
Features/Improvements
- User media stream instances will no longer get stopped because of network disruptions or switches so they can be retained for as long as needed by an app
v2021.0.8 Integration Notes
PhenixUserMediaStream on iOS.
v2021.0.7 Pre-release Notes
Release Date: 2021.05.06
Features/Improvements
- None
Issues addressed in this release
-
Fixed null pointer crash in AudioPlaybackJniAdapter
-
Fixed sporadic crashes
v2021.0.5 Pre-release Notes
Release Date: 2021.04.12
Features/Improvements
- None
Issues addressed in this release
- Fixed bug resulting in subscribers not getting audio
v2021.0.2 Pre-release Notes
Release Date: 2021.03.02
Features/Improvements
- When no Admin API (e.g. backend) is provided, channel publisher wildcard tokens are now automatically disabled to avoid failures
Issues addressed in this release
-
Fixed audio only real-time stream rendering
-
Fixed missing callback invocation for PhenixRoomExpress.subscribeToMemberStream if member stream has ended already
-
Added missing API PhenixPublishToChannelOptionsBuilder.withoutWildcardTokens
v2021.0.0 Pre-release Notes
Release Date: 2021.01.07
Features/Improvements
-
Improved error handling when attempting to start subscribers and publishers with capabilities and edge stream tokens
-
Publish and subscribe should fail when caller supplies a stream token with capabilities in conjunction with explicitly capabilities (withCapabilities) to the builder; either approach works independently but both simultaneously will fail
Issues addressed in this release
- Fixed broken time shifts for very long running streams
v2020.1.76 Pre-release Notes
Release Date: 2020.12.22
Features/Improvements
-
PhenixTimeShiftOptions.chunkRetrievalTimeout
property allows overriding the maximum amount of time the SDK will wait to download a chunk for time-shift playback -
PhenixChannelExpress.joinChannel
will now return with an "unauthorized" status (subscriber callback) when the stream token that was provided when the channel was joined is either invalid or has expired. The recourse for the app is to leave the channel(PhenixRoomService.leaveRoom())
and then re-join the channel with an updated stream token.
Issues addressed in this release
- None
Notes on Integrating the iOS SDK
// The current implementation of `PhenixTimeShift` leverages HLS chunks.
// It is possible that retrieval of such chunks can take a very long time.
// This will impact playback if the playback head catches up with the end
// of the prefetch window, which will lead to a stall.
// By default, a timeout of 10 seconds for each chunk retrieval is used
// to avoid holding off playback for too long (worst case a chunk will be
// skipped and playback may pause temporarily).
// This timeout is configurable by setting the following option (it defaults
// to 0, which indicates that we should use the internal default):
let timeout: TimeInterval = 5
rendererOptions.timeShiftOptions.chunkRetrievalTimeout = timeout
v2020.1.75 Pre-release Notes
Release Date: 2020.12.11
Features/Improvements
PhenixTimeShiftOptions
viaPhenixRendererOptions
allows customization of rendition selection behavior
Issues addressed in this release
-
Fixed possible crash due race condition occurring when shutting down a renderer
-
Fixed resource leaks associated with time-shifts
Notes on Integrating the iOS SDK
import PhenixSdk
// Renderer has been obtained from `PhenixMediaStream` or
// `PhenixExpressSubscriber`:
var renderer: PhenixRenderer = ...
if (!renderer.isSeekable) {
// This stream does not support time shifting
return;
}
// Must be in UTC:
let timePoint = Date(...)
var timeShift = renderer.seek(timePoint)
// Observe ready status and call `loop` once PhenixTimeShift is ready.
// This ensures that when `loop` is called playback will start
// instantly.
// All observables return a `PhenixDisposable` object. This needs to be stored
// in order to keep the observable subscription alive.
// It is recommended to make this a member of the enclosing class
let readyDisposable = timeShift?.
getObservableReadyForPlaybackStatus()?.subscribe { (isReadyChange) in
if (isReadyChange?.value.boolValue) {
let loopDuration = TimeInterval(30.0)
timeShift?.loop(loopDuration)
}
}
// When time shifted viewing is no longer desired:
// Dispose the `PhenixTimeShift` object.
timeShift = nil // <-- Playback will jump back to real-time head
// It is also possible to stop a timeshift in progress so it can
// be used again by calling `loop` later
timeShift?.stop() // <-- Playback will jump back to real-time head
// After `stop()` the ready status will (briefly) switch to false, then
// back to true when enough data has been re-cached.
// `PhenixTimeShift` objects can fail, either during creating when passing in
// an invalid timestamp to `PhenixRenderer.seek()` or any of the other
// `PhenixTimeShift` method. Once a `PhenixTimeShift` has failed, it should be
// dropped and a new one created.
let failureDisposable = timeShift?.
getObservableFailure()?.subscribe { (failureChange) in
let errorStatus: PhenixRequestStatus = (failureChange?.value.status)!
// a non-ok `PhenixRequestStatus` is returned here
}
// Pause playback
timeShift?.pause()
// Resume playback after pause
timeShift?.play()
// The current playback head can be observed. Each video frame will trigger
// the observable. The head is reported as a `NSDate` object and represents
// UTC.
let playbackHeadDisposable = timeShift?.
getObservablePlaybackHead()?.subscribe { (playbackHeadChange) in
let currentPlaybackHead: NSDate = (playbackHeadChange?.value!)!
// Avoid blocking this thread and dispatch UI updates as needed
}
// `PhenixTimeShift` supports seeking to any location within the current
// segment.
// The segment is defined by:
// Start: Time point passed into `PhenixRenderer.seek`
// End : Start plus duration passed into `PhenixTimeShift.loop`
// Seeking is only possible if the `PhenixTimeShift` is either stopped or
// paused.
// Once `PhenixTimeShift` is ready for playback, the observable returned by
// `seek` will return a status code. Call `play()` to start/resume playback if
// the status is OK.
let relativeSeekTime: TimeInterval = -10.0 // Seeks back 10 seconds
let seekDisposable = timeShift?.
seekRelative(relativeSeekTime)?.subscribe { (seekChange) in
let status: PhenixRequestStatus = (seekChange?.value.status)!
if (status == .ok) {
timeShift?.play()
} else {
// Handle error. In most cases the seek argument would have
// led to a location outside of the segment
}
}
// There is also a second version of seek available named `seekAbsolute`,
// which accepts a `Date` as its argument representing an absolute time point
// in UTC (also has to fall within the boundaries of the segment).
// A `PhenixTimeShift` stream generally consists of several so called layers.
// Layers have different bitrates, usually by varying resolution and framerate
// (lower bitrate layers tend to have lower resolutions and/or framerates).
// While a `PhenixTimeShift` is playing back content, it will automatically
// select an appropriate layer based on the pixel resolution of the rendering
// layer. The logic attempts to select a layer, whose resolution matches
// that of the rendering layer as closely as possible.
// Sometimes an app may want to further restrict the playback layer in order
// to reduce battery usage for instance. This is possible via the
// `PhenixTimeShift.limitBandwidth` API. It forces the `PhenixTimeShift` to
// only select layers with an average bitrate less or equal to the value
// passed into `limitBandwidth`.
// The limitation will remain in effect for as long as the app holds on to
// the `PhenixDisposable` object returned by the API.
// This API can be called at any time: before and during playback.
let bandwithLimitInBps: UInt64 = 400000
var limitBandwidthDisposable = timeShift?.limitBandwidth(bandwithLimitInBps)
// Set the `PhenixDisposable` object to nil to release the bandwidth limit
limitBandwidthDisposable = nil
// Certain behaviors of `PhenixTimeShift` can be changed by passing in
// custom options when the `PhenixRenderer` is created:
let rendererOptions = PhenixRendererOptions()
// When calling `PhenixRenderer.seek` or `PhenixTimeShift.seek` the
// bandwidth will be automatically limited to shorten the amount of time
// it takes for the `PhenixTimeShift` object to become ready.
// The downside of this approach is that once the playback starts, it will
// do so on a lower bitrate rendition of the stream and it generally takes a
// few seconds before the rendition switches to a higher bitrate.
// This behavior is enabled by default, but can be disabled by setting the
// following option to false:
rendererOptions.timeShiftOptions.lowerBandwidthWhileSeekingEnabled = false
// The size of the viewport will determine which rendition of the stream is
// selected (the rendition whose height in pixels is closest to the current
// height of the viewport). This selection process is continuous, which means
// that as the viewport size changes, so does the selected rendition.
// After a new rendition has been selected, it will not render frames
// instantly. Instead, it will take up to about 5 seconds before it will
// render frames.
// This behavior is enabled by default, but can be disabled by setting the
// following option to false:
rendererOptions.timeShiftOptions.viewportSizeBasedRenditionSelectionEnabled
= false
// The options object can be passed in directly to the `createRenderer`
// method:
var subscriber: PhenixExpressSubscriber = ... // previously obtained
let renderer = subscriber.createRenderer(rendererOptions)
// Alternatively, it can be passed via various options builders, for example
// for `joinChannel`:
let joinChannelOptionsBuilder =
PhenixChannelExpressFactory.createJoinChannelOptionsBuilder()
joinChannelOptionsBuilder.withRendererOptions(rendererOptions)
v2020.1.73 Pre-release Notes
Release Date: 2020.12.01
Features/Improvements
-
Improved stability in the case where Bluetooth permission is missing
-
Improved audio stream reliability by increasing audio render buffer size
-
Reduced time taken for TimeShift playback to reach higher rendition
-
Improved TimeShift playback reliability
Issues addressed in this release
- None
v2020.1.68 Pre-release Notes
Release Date: 2020.11.12
Features/Improvements
-
Shortened duration for TimeShift to become ready
-
Improved TimeShift playback reliability
-
Setting the RTP/UTC time base needs to use the correct DVR section start time
-
TimeShift seeking needs to prevent deadlocks on calling thread
-
Revert audio capture time-stamping logic back to using local timestamp
Issues addressed in this release
- None
v2020.1.61 Pre-release Notes
Release Date: 2020.09.22
Features/Improvements
-
Fix for occasional failures when creating
RoomChatService
. Extra delay before creating service is no longer needed. -
Fix for failing TimeShift objects after calling
Renderer.Seek
for Live streams
Issues addressed in this release
- None
v2020.1.60 Pre-release Notes
Release Date: 2020.09.16
IMPORTANT
We only recommend this update for the VOD applications (not Live). This release has an issue that affects Live timeshifts.
Features/Improvements
- None
Issues addressed in this release
-
Fix for further potential deadlocks that may occur when calling
Renderer.Seek
-
Fix for short DVR segments not looping
-
Fix for deadlock when calling Renderer.Seek
-
Improved VOD stream startup and seeking times and stability
-
Improved performance by avoiding pixel format conversions where possible
v2020.1.56 Pre-release Notes
Release Date: 2020.08.31
Features/Improvements
- None
Issues addressed in this release
-
Added support for subscribing to messages based on mime-types
-
Added client side timeouts for member updates
v2020.1.56 Integration Notes
In order to specify the iOS release in the pod spec
In order to pick up that latest version, you may need to run this pod command:
pod install --repo-update
To change this in the Podfile:
def phenix
pod 'PhenixSdk', '~> 2020.1.56-beta'
end
In order to subscribe to messages by mime-type
import PhenixSdk
import PhenixRoomChatServiceFactory
var wantedMimeTypes = Set<String>()
wantedMimeTypes.insert(“text/javascript”)
var chatService = PhenixRoomChatService.createRoomChatService(
roomService, // previously obtained
batchSize, // previously obtained
wantedMimeTypes
);
var subscriptionLastChatMessage =
chatService.getObservableLastChatMessage().subscribe({
change in
if let change = change, let chatMessage = change.value {
assert(
chatMessage.getObservableMimeType().value == “text/javascript”,
“chatService will only get messages with wanted MIME types”
)
})
var subscriptionLastChatMessage =
chatService.getObservableLastChatMessage().subscribe({
change in
if let change = change {
let messages = change.value as! [PhenixChatMessage]
for message in messages {
assert(
chatMessage.getObservableMimeType().value ==“text/javascript”,
“chatService will only get messages with wanted MIME types”
)
}
}
})
chatService.getMessages(batchSize, afterMessageId, beforeMessageId) {
(chatService: PhenixRoomChatService?,
messages: [PhenixChatMessage]?,
status: PhenixRequestStatus) in
if status == .ok, let messages = messages {
for message in messages {
assert(
chatMessage.getObservableMimeType().value ==“text/javascript”,
“chatService will only get messages with wanted MIME types”
)
}
}
}
// send message with a specific MIME type
// with just the message, MIME type defaults to “text/plain”:
chatService.sendMessageToRoom("My First Message");
// with message and MIME type, but using default callback
chatService.sendMessageToRoom("My First Message", "text/javascript");
// with message, MIME type, and callback
chatService.sendMessageToRoom(
"My First Message",
"text/javascript") {
(status: PhenixRequestStatus, message: String?) in {
...
}
}
v2020.1.52 Pre-release Notes
Release Date: 2020.08.27
Features/Improvements
- None
Issues addressed in this release
-
Support for configurable sampling rate for BlueTooth SCO capability
-
Improvements on re-establishing connections after changing network type
-
Improved reliability of room member updates, which impacts for instance toggling audio/video muted states
-
Added support for obtaining beta iOS releases via pod spec
v2020.1.49 Pre-release Notes
Release Date: 2020.08.21
Features/Improvements
- None
Issues addressed in this release
-
Stream restart on change in network type
-
Fix for the last message observable - improve reliability on new message arrival
-
Removed unnecessary animation (iOS)
Notes
To take advantage of the new functionality in support of stream restarts on change in network type, it works as follows:
-
App calls subscribeToMemberStream and passes a callback (last argument) to get notified when we successfully subscribed.
-
Once subscribed, the app's callback is invoked.
-
If there is a network switch, the SDK will start monitoring the stream and watch for data for about 5 seconds. If there is no (or very little) data, we consider the connection lost and the SDK will restart it.
-
If a stream is restarted due to a lack of data, the callback set by the app in subscribeToMemberStream will be invoked, to indicate the restart. This will provide the app with a new ExpressSubscriber (and Renderer if the app requested one).
Based on the options initially passed to subscribeToMemberStream, the app can either let the SDK create the renderer, or the app can create a renderer itself.
-
If the app is letting the SDK manage the renderer, the SDK will stop the renderer and create a new renderer when the stream needs to be restarted.
-
If the app manages the renderer, then the app must make sure to stop and dispose of the old renderer and before creating a new one once it receives a new ExpressSubscriber.
v2020.1.47 Pre-release Notes
Release Date: 2020.08.20
Features/Improvements
- None
Issues addressed in this release
-
Added observable in RoomChatService that fires individually for each chat message as they come in
-
Fixes for iOS renderers (includes detaching our render layers when we're done)
-
Other minor fixes to handle TimeShift.seek when time-shift is stopped
v2020.1.43 Pre-release Notes
Release Date: 2020.08.18
Features/Improvements
- None
Issues addressed in this release
-
Frame-ready API needs to relay frames from time-shifted content when a TimeShift is playing
-
Various fixes
v2020.1.40 Pre-release Notes
Release Date: 2020.08.12
Features/Improvements
- None
Issues addressed in this release
-
Fix for deadlock when layer resolution changes
-
LimitBandwidth API (on TimeShift).
v2020.1.38 Pre-release Notes
Release Date: 2020.08.07
Features/Improvements
- None
Issues addressed in this release
-
Support for “click and seek” into a timeshift segment (details on usage below)
-
Timeshift observable playback head reports position in UTC time
-
Timeshift pause and play options
-
Timeshift observable failure report
v2020.1.33 Pre-release Notes
Release Date: 2020.07.16
Features/Improvements
- None
Issues addressed in this release
-
Includes viewport based HLS layer selection
-
Prefetch window is updated based on layer bitrate for faster switching from very low bitrate layers
-
Includes a fix for iOS, which previously caused image corruption during time-shifted playback
v2020.1.30 Pre-release Notes
Release Date: 2020.07.08
Features/Improvements
- None
Issues addressed in this release
-
Audio muted status needs to be honored when rendering time-shifted content
-
Add support for Automatic Gain Control