Multiple players

With v4.4.0 of the Wowza Flowplayer Apple SDK, we added multiple player support to integrate more than one player simultaneously in your iOS applications.

This feature is helpful when you intend to play two different media sources within the same user interface. Both player instances containing the media can be controlled separately as they function independently of each other.

info

To view an example of this feature, see the iOS Example application in our apple-sdk-releases repository. The multi-player examples contain a video-on-demand (VOD) sample that incorporates two different players in the same view.

For information related to listening to events, managing media playback, and handling errors, see these pages:

Wowza Flowplayer Apple SDK multiple players

Identify a player instance

To manage each view instance, you can use the id property of the FlowplayerAPI protocol. By default, the view randomly generates and emits the value of this property. However, you can also set a custom string identifier.

This section provides examples of how to identify a player instance, then use the delegate pattern or the notification dispatch mechanism to perform a certain action.

Use delegation to identify a player

You can use the delegate pattern to listen for and capture the id of a view that's triggered a specific event.

The following example monitors changes in the player's state and responds based on which player instance triggered the state change. For an event listeners reference, see Listen for events with the delegate method.

Example
Copy
Copied
// Declare player instances
let mainPlayer = FlowplayerView()
let secondaryPlayer = FlowplayerView()

// Set delegate property and conform to FlowplayerDelegate protocol
mainPlayer.delegate = self
secondaryPlayer.delegate = self

// Use FlowplayerDelegate protocol to observe and respond to player state changes
func player(player: FlowplayerAPI, didChangeState state: PlayerState) {

    // Compare id property of mainPlayer variable and player parameter
    guard mainPlayer.id == player.id else {
        // If not equal, indicate event was triggered by secondaryPlayer instance
        print("secondaryPlayer triggered this event")
        return
    }

    // If equal, indicate event was triggered by mainPlayer instance
    print("mainPlayer changed the state to: \(state)")
}

Use notifications to identify a player

You can also use the notification dispatch mechanism in the Wowza Flowplayer Apple SDK to detect the id of the player and respond to player events.

The following code snippet sets up a notification observer for changes in the player's state. When a state notification is received, it checks the player's identifier and performs a certain action based on which player triggered the event. For more information, see Listen for events with the NotificationCenter.

Example
Copy
Copied
// Declare player instances
let mainPlayer = FlowplayerView()
let secondaryPlayer = FlowplayerView()

// Register observer for flowplayerDidChangeState notification
NotificationCenter.default.addObserver(
  self,
  selector: #selector(onReceivedState),
  name: .flowplayerDidChangeState,
  object: nil
)

// Call onReceivedState method when notification is received
@objc
private func onReceivedState(_ notification: Notification) {
  guard
    // Retrieve id from notification's user info and check if it matches mainPlayer id
    let id = notification.userInfo?[\FlowplayerAPI.id] as? String,
    mainPlayer.id == id
  else {
    // If not equal, indicate event was triggered by secondaryPlayer instance
    print("myOtherPlayer triggered this event")
    return
  }

  guard let state = notification.object as? PlayerState else {
    return
  }

  // If equal, indicate event was triggered by mainPlayer instance
  print("mainPlayer changed state to: \(state)")
}

Set a custom player identifier

The player's default behavior randomly generates and emits the value of an id property to identify each player instance. You can also set a player id that uses a custom string. This is helpful when you have a requirement to use a specific identifier for your player instance.

To set up a player with a custom id, use this FlowplayerView initializer:

Copy
Copied
public init(avPlayer: AVPlayer? = nil, id: String? = nil)

When you initialize a FlowplayerView programmatically, add the initializer and replace the [some-id] placeholder with a desired ID value:

Copy
Copied
// Create instance of FlowplayerView, initialize it with avPlayer and id parameters
let flowplayerView = FlowplayerView(avPlayer: nil, id: "[some-id]")

The avPlayer and id parameters are optional. If avPlayer is omitted, the FlowplayerView class creates its own AVPlayer instance instead of using an instance you provide.

Feature Limitations

This section outlines limitations to consider when using multiple players at the same time in your iOS applications.

Handling full-screen mode

If using the FlowplayerView class to render multiple player instances at once, some limitations exist when managing full-screen behavior.

Multiple players in the same UIViewController class can't enter the full-screen display simply with device rotation. This occurs because each FlowplayerView instance doesn't know what triggered the orientation change, which could have been caused by user action or another player instance.

For this reason, disable the following properties for all FlowplayerView instances used inside a single UIViewController class:

Copy
Copied
// Player isn't forced into full-screen mode when orientation change occurs
flowplayerView.orientationControlsFullscreen = false
Copy
Copied
// Player isn't forced to rotate into landscape mode when entering full-screen mode
flowplayerView.fullscreenControlsOrientation = false
info

If you would still like to have a single FlowplayerView instance go into full-screen mode when the device orientation changes, set the fullscreenControlsOrientation property to true for that specific instance. Make sure to disable the same property for all other instances of FlowplayerView.

To learn more, see Enter or exit full-screen mode and the FlowplayerViewAPI properties.