Release Notes
The most current release version is 2022.0.3
Release notes for this version are shown below, followed by notes from prior releases.
To get the Android SDK for a specific version, update the Phenix SDK version in build.gradle file to match the version number,
e.g., 2021.0.11
. Some versions require additional integration steps; these are called out in the version-specific release notes.
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
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
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.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
Notes on Integrating the Android SDK
UserMediaStream on Android.
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
Reduce occurrences of audio drop out and lip sync issues on Android
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 playbackPhenixChannelExpress.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 Android SDK
1// The current implementation of `TimeShift` leverages HLS chunks.2// It is possible that retrieval of such chunks can take a very long time.3// This will impact playback if the playback head catches up with the end4// of the prefetch window, which will lead to a stall.5// By default, a timeout of 10 seconds for each chunk retrieval is used6// to avoid holding off playback for too long (worst case a chunk will be7// skipped and playback may pause temporarily).8// This timeout is configurable by setting the following option (it defaults9// to 0, which indicates that we should use the internal default):10var timeoutInMilliseconds = 5000L11rendererOptions.timeShiftOptions.chunkRetrievalTimeoutInMilliseconds12 = timeoutInMilliseconds
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 Android SDK
1import com.phenixrts.common.Disposable;2import com.phenixrts.pcast.Renderer;3import com.phenixrts.pcast.TimeShift;45import java.util.Date;67// Renderer has been obtained from `MediaStream` or `ExpressSubscriber`:8var renderer: Renderer = ...91011if (!renderer.isSeekable) {12 // This stream does not support time shifting13 return;14}1516// Must be in UTC:17var timePoint = Date(...)1819var timeShift = renderer.seek(timePoint)2021// Observe ready status and call `loop` once TimeShift is ready.22// This ensures that when `loop` is called playback will start23// instantly.2425// All observables return a `Disposable` object. This needs to be stored26// in order to keep the observable subscription alive.27// It is recommended to make this a member of the enclosing class28var disposables = mutableListOf<Disposable>()2930timeShift.observableReadyForPlaybackStatus.subscribe { isReady ->31 if (isReady) {32 var loopDurationInMilliseconds = 30000L3334 timeShift.loop(loopDurationInMilliseconds)35 }36}.run{ disposables.add(this) }3738// When time shifted viewing is no longer desired:3940// Dispose the `TimeShift` object. It will no longer be useable41// after this operation. A new instance can be obtained via `seek`42timeShift.dispose() // <-- Playback will jump back to real-time head4344// It is also possible to stop a timeshift in progress so it can45// be used again by calling `loop` later46timeShift.stop() // <-- Playback will jump back to real-time head4748// After `stop()` the ready status will (briefly) switch to false, then49// back to true when enough data has been re-cached.5051// `TimeShift` objects can fail, either during creating when passing in52// an invalid timestamp to `Renderer.seek()` or any of the other `TimeShift`53// method. Once a `TimeShift` has failed, it should be disposed and a new54// one created.55timeShift.observableFailure.subscribe { status ->56 // a non-OK `RequestStatus` is returned here57}.run { disposables.add(this) }5859// Pause playback60timeShift.pause()6162// Resume playback after pause63timeShift.play()6465// The current playback head can be observed. Each video frame will trigger66// the observable. The head is reported as a `Date` object and represents UTC.67timeShift.observablePlaybackHead.subscribe { playbackHead ->68 // a `Date` object. Avoid blocking this thread and dispatch UI updates69 // as needed.70}.run { disposables.add(this) }7172// `TimeShift` supports seeking to any location within the current segment.73// The segment is defined by:74// Start: Time point passed into `Renderer.seek`75// End : Start plus duration passed into `TimeShift.loop`7677// Seeking is only possible if the `TimeShift` is either stopped or paused.78// Once `TimeShift` is ready for playback, the observable returned by `seek`79// will return a status code. Call `play()` to start/resume playback if the80// status is OK.81var relativeSeekTimeInMillis = -10000L // Seeks back 10 seconds8283timeShift.seek(relativeSeekTimeInMillis).subscribe { status ->84 if (status == RequestStatus.OK) {85 timeShift.play()86 } else {87 // Handle error. In most cases the seek argument would have led to88 // a location outside of the segment89 }90}.run { disposables.add(this) }9192// There is also a second version of `seek` available, which accepts a `Date`93// as its argument representing an absolute time point in UTC (also has to94// fall within the boundaries of the segment).959697// A `TimeShift` stream generally consists of several so called layers. Layers98// have different bitrates, usually by varying resolution and framerate (lower99// bitrate layers tend to have lower resolutions and/or framerates).100101// While a `TimeShift` is playing back content, it will automatically select102// an appropriate layer based on the pixel resolution of the rendering103// surface. The logic attempts to select a layer, whose resolution matches104// that of the rendering surface as closely as possible.105106// Sometimes an app may want to further restrict the playback layer in order107// to reduce battery usage for instance. This is possible via the108// `TimeShift.limitBandwidth` API. It forces the `TimeShift` to only select109// layers with an average bitrate less or equal to the value passed into110// `limitBandwidth`.111// The limitation will remain in effect for as long as the app holds on to112// the `Disposable` object returned by the API.113// This API can be called at any time: before and during playback.114var bandwithLimitInBps = 400000L115116var limitBandwidthDisposable = timeShift?.limitBandwidth(bandwithLimitInBps)117118// Call `dispose()` on the `Disposable` object to release the bandwidth limit119limitbandwidthDisposable?.dispose()120121122// Certain behaviors of `TimeShift` can be changed by passing in123// custom options when the `Renderer` is created:124125var rendererOptions = RendererOptions()126127// When calling `Renderer.seek` or `TimeShift.seek` the128// bandwidth will be automatically limited to shorten the amount of time129// it takes for the `TimeShift` object to become ready.130// The downside of this approach is that once the playback starts, it will131// do so on a lower bitrate rendition of the stream and it generally takes a132// few seconds before the rendition switches to a higher bitrate.133// This behavior is enabled by default, but can be disabled by setting the134// following option to false:135rendererOptions.timeShiftOptions.lowerBandwidthWhileSeekingEnabled = false136137// The size of the viewport will determine which rendition of the stream is138// selected (the rendition whose height in pixels is closest to the current139// height of the viewport). This selection process is continuous, which means140// that as the viewport size changes, so does the selected rendition.141// After a new rendition has been selected, it will not render frames142// instantly. Instead, it will take up to about 5 seconds before it will143// render frames.144// This behavior is enabled by default, but can be disabled by setting the145// following option to false:146rendererOptions.timeShiftOptions.viewportSizeBasedRenditionSelectionEnabled147 = false148149// The options object can be passed in directly to the `createRenderer`150// method:151var subscriber: ExpressSubscriber = ... // previously obtained152153var renderer = subscriber.createRenderer(rendererOptions)154155// Alternatively, it can be passed via various options builders, for example156// for `joinChannel`:157var joinChannelOptionsBuilder =158 ChannelExpressFactory.createJoinChannelOptionsBuilder()159160joinChannelOptionsBuilder.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
Move callback handling in AndroidJavaAudioRenderDevice to a separate thread
Handle bluetooth headset connections and disconnections with AEC enabled on Android
Revert audio capture time-stamping logic back to using local timestamp
Issues addressed in this release
- None
Notes on Integrating the Android SDK
In order to support BlueTooth functionality, add the following to the manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
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
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
Fix to properly expose API in support for configurable sampling rate for BlueTooth SCO capability in Android
Added client side timeouts for member updates
Notes on Integrating the Android SDK
In order to support BlueTooth SCO headsets
- Configure the sample rate overrides for recording and playback to values that are required by SCO:
1try {2 Os.setenv("PHENIX_AUDIO_PLAYBACK_SAMPLE_RATE_OVERRIDE", "16000", true);3 Os.setenv("PHENIX_AUDIO_RECORDING_SAMPLE_RATE_OVERRIDE", "8000", true);4 } catch (ErrnoException e) {5 // handle exception6 }
- Enable SCO in the AudioManager (this example assumes the code is placed in your Application subclass):
1AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);23 // call at appropriate time - detection of BT on4 audioManager.startBluetoothSco();56 // call at appropriate time - detection of BT off7 audioManager.stopBluetoothSco();
- For both publishing and subscribing, make sure that audio echo cancellation is enabled in the respective options:
1// publishing2 final UserMediaOptions mediaConstraints = new UserMediaOptions();3 mediaConstraints.getAudioOptions().capabilityConstraints.put(4 DeviceCapability.AUDIO_ECHO_CANCELATION_MODE,5 singletonList(new DeviceConstraint(AudioEchoCancelationMode.ON)));6 PublishOptions publishOptions = PCastExpressFactory.createPublishOptionsBuilder()7 .withMediaConstraints(mediaConstraints)8 // add any other options9 .buildPublishOptions();10 // subscribing11 final RendererOptions rendererOptions = new RendererOptions();12 rendererOptions.audioEchoCancelationMode = AudioEchoCancelationMode.ON;13 JoinChannelOptionsBuilder joinChannelOptionsBuilder = ChannelExpressFactory14 .createJoinChannelOptionsBuilder()15 .withRendererOptions(rendererOptions)16 // add any other options17 .buildJoinChannelOptions()
- Note that only mono streams are supported by SCO.
In order to subscribe to messages by mime-type
1import com.phenixrts.chat.RoomChatServiceFactory;2import com.phenixrts.room.RoomService;34final int batchSize = ...5final RoomService roomService = ...; // previously obtained67final HashSet<String> wantedMimeTypes = new HashSet<String>();8wantedMimeTypes.add(“text/javascript”);910final RoomChatService chatService =11 RoomChatServiceFactory.createRoomChatService(12 roomService,13 batchSize,14 wantedMimeTypes15 );1617// “chatService” retrieves only messages of “wantedMimeTypes”18final Disposable subscriptionLastChatMessage =19 chatService.getObservableLastChatMessage().subscribe((change) -> {20 final ChatMessage message = (ChatMessage)change;21 assert message.getObservableMimeType().getValue() == “text/javascript”;22});2324final Disposable subscriptionChatMessages =25 chatService.getObservableChatMessages().subscribe((change) -> {26 final ChatMessage[] messages = (ChatMessage[])change;2728 for (int i = 0; i < messages.length; ++i) {29 assert message.getObservableMimeType().getValue() ==30 “text/javascript”;31 }32});3334chatService.getMessages(35 batchSize,36 afterMessageId,37 beforeMessageId,38 (RoomChatService service, ChatMessage[] messages, RequestStatus status) -> {39 for (int i = 0; i < messages.length; ++i) {40 assert message.getObservableMimeType().getValue() ==41 “text/javascript”;42 }43});4445// send message with a specific MIME type46// with just the message, MIME type defaults to “text/plain”:47chatService.sendMessageToRoom("My First Message");4849// with message and MIME type, but using default callback50chatService.sendMessageToRoom("My First Message", "text/javascript");5152// with message, MIME type, and callback53chatService.sendMessageToRoom(54 "My First Message",55 "text/javascript",56 (RequestStatus status, String message) -> { ... }57);
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
Android camera reconnection logic
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