Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

Commit

Permalink
[FEATURE] added Example app;
Browse files Browse the repository at this point in the history
  • Loading branch information
Denpex committed Feb 9, 2022
1 parent ec68c6c commit 9384042
Show file tree
Hide file tree
Showing 31 changed files with 1,245 additions and 8 deletions.
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ playground.xcworkspace
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#

Pods/
Podfile.lock

# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
*.xcworkspace

# Carthage
#
Expand Down
445 changes: 445 additions & 0 deletions Example App/Example App.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E16FA8802746FAF70047ABE6"
BuildableName = "Example App.app"
BlueprintName = "Example App"
ReferencedContainer = "container:Example App.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E16FA8802746FAF70047ABE6"
BuildableName = "Example App.app"
BlueprintName = "Example App"
ReferencedContainer = "container:Example App.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E16FA8802746FAF70047ABE6"
BuildableName = "Example App.app"
BlueprintName = "Example App"
ReferencedContainer = "container:Example App.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
30 changes: 30 additions & 0 deletions Example App/Example App/source/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// AppDelegate.swift
// flowplayer-tvOS
//
// Created by Mehdi on 18. 11. 2021..
//

import UIKit
import AVFoundation

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let audioSession = AVAudioSession.sharedInstance()

do {
// Required for audio & video playback on physical devices
try audioSession.setCategory(.playback, mode: .moviePlayback)
} catch {
print("Setting category to AVAudioSessionCategoryPlayback failed.")
}

return true
}

}

26 changes: 26 additions & 0 deletions Example App/Example App/source/Constants.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Constants.swift
// flowplayer-tvOS
//
// Created by Mehdi on 18. 11. 2021..
//

import Foundation

struct Constants {
// - Videos
static let DEMO_MEDIA_ID = "69891ec1-2d90-423c-9892-5a9ee87b6d86"
static let DEMO_PLAYER_ID = "ac6dea7c-acf1-472a-bdab-efdd85f092f1"
static let DEMO_URL_HLS = "https://wowzaec2demo.streamlock.net/vod-multitrack/_definst_/smil:ElephantsDream/ElephantsDream.smil/playlist.m3u8"
static let DEMO_URL_MP4 = "https://edge.flowplayer.org/drive.mp4"
static let DEMO_URL_HLS_SUBTITLES = "https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
static let DEMO_MEDIA_ID_SUBTITLES = "279a8421-2488-4698-b0bd-2df15b2fabfe"
static let DEMO_URL_VMAP = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&cmsid=496&vid=short_onecue&correlator="

// - Ads
static let DEMO_URL_AD_PREROLL = "https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&vad_type=linear&vpos=preroll&pod=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6376&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&url=&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0"
static let DEMO_URL_AD_MIDROLL1 = "https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&ppos=1&min_ad_duration=0&max_ad_duration=30000&vrid=6376&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&url=&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0"
static let DEMO_URL_AD_MIDROLL2 = "https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&ppos=2&min_ad_duration=0&max_ad_duration=30000&vrid=6376&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&url=&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0"
static let DEMO_URL_AD_MIDROLL3 = "https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&cue=15000&vad_type=linear&vpos=midroll&pod=2&mridx=1&ppos=3&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6376&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&url=&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0"
static let DEMO_URL_AD_POSTROLL = "https://pubads.g.doubleclick.net/gampad/ads?slotname=/124319096/external/ad_rule_samples&sz=640x480&ciu_szs=300x250&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&vad_type=linear&vpos=postroll&pod=3&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=6376&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&url=&video_doc_id=short_onecue&cmsid=496&kfa=0&tfcd=0"
}
216 changes: 216 additions & 0 deletions Example App/Example App/source/MainController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//
// MainController.swift
// flowplayer-tvOS
//
// Created by Mehdi on 18. 11. 2021..
//

import AVKit
import Flowplayer

// - Identifiers
fileprivate let CELL_ID = "video-cell"

class MainController: UIViewController {

// - Views
@IBOutlet weak var tableView: UITableView!

// - Props
private var flowplayer: FPFlowplayer!
private let player = AVPlayer()
private let playerController = AVPlayerViewController()

override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self

playerController.player = player
playerController.modalPresentationStyle = .fullScreen
playerController.delegate = self
flowplayer = FPFlowplayer(player: player, controller: playerController)
flowplayer.delegate = self
}

}

// MARK: - UITableViewDatasource
extension MainController: UITableViewDataSource {

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CELL_ID, for: indexPath)
cell.textLabel?.text = tableData[indexPath.row].title
cell.accessoryType = .disclosureIndicator
return cell
}

}

// MARK: - UITableViewDelegate
extension MainController: UITableViewDelegate {

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = tableData[indexPath.row]

present(playerController, animated: true) { [weak self] in
// INFO: For the ADs to load, media needs to be loaded after the controller has been presented
self?.onPlayControllerPresented(item: item)
}
}

}

// MARK: - Private
extension MainController {

private func onPlayControllerPresented(item: TableItem) {
if let externalMedia = item.externalMedia {
self.flowplayer.load(external: externalMedia, autoStart: true)
}

if let flowplayerMedia = item.flowplayerMedia {
self.flowplayer.load(flowplayer: flowplayerMedia, autoStart: true)
}
}

}

// MARK: - AVPlayer
extension MainController: AVPlayerViewControllerDelegate {

func playerViewControllerWillBeginDismissalTransition(_ playerViewController: AVPlayerViewController) {
// Stop flowplayer playback
flowplayer.stop()
}

}

// MARK: - FPFlowplayerDelegate
extension MainController: FPFlowplayerDelegate {

func onIdle(event: FPIdleEvent) {
print(#function)
print(event)
}

func onReady(event: FPReadyEvent) {
print(#function)
print(event)
}

func onPlay(event: FPPlayEvent) {
print(#function)
print(event)
}

func onPause(event: FPPauseEvent) {
print(#function)
print(event)
}

func onBuffer(event: FPBufferEvent) {
print(#function)
print(event)
}

func onComplete(event: FPCompleteEvent) {
print(#function)
print(event)
}

func onMute(event: FPMuteEvent) {
print(#function)
print(event)
}

func onVolume(event: FPVolumeEvent) {
print(#function)
print(event)
}

func onSpeed(event: FPSpeedEvent) {
print(#function)
print(event)
}

func onAudioTracksLoaded(event: FPAudioTracksEvent) {
print(#function)
print(event)
}

func onAudioTrackSelect(event: FPAudioTrackSelectEvent) {
print(#function)
print(event.audioTrack)
}

func onSubtitleTrackSelect(event: FPSubtitleTrackSelectEvent) {
print(#function)
dump(event.subtitleTrack)
}

func onSubtitleTracksLoaded(event: FPSubtitleTracksEvent) {
print(#function)
print(event)
}

func onOvpMetadata(event: FPOvpMetadataEvent) {
print(#function)
print(event)
}

func onError(event: FPErrorEvent) {
print(#function)
print(event)
}

func onAdBreakStart(event: FPAdBreakStartEvent) {
print(#function)
print(event)
}

func onAdBreakComplete(event: FPAdBreakCompleteEvent) {
print(#function)
print(event)
}

func onAdStart(event: FPAdStartEvent) {
print(#function)
print(event)
}

func onAdPause(event: FPAdPauseEvent) {
print(#function)
print(event)
}

func onAdResume(event: FPAdResumeEvent) {
print(#function)
print(event)
}

func onAdClick(event: FPAdClickEvent) {
print(#function)
print(event)
}

func onAdSkip(event: FPAdSkipEvent) {
print(#function)
print(event)
}

func onAdComplete(event: FPAdCompleteEvent) {
print(#function)
print(event)
}

func onAdError(event: FPAdErrorEvent) {
print(#function)
print(event)
}

}
Loading

0 comments on commit 9384042

Please sign in to comment.