Skip to content

Commit

Permalink
Add Initial DRM implementation (#36)
Browse files Browse the repository at this point in the history
* Add API for DRM

* chore: scaffolding for key value observation

* Add Fairplay folder

* Some delegate methods

* up

* up

* Internal skeleton done

* Add DRM config to separate playback policy

* up

* Added session delegate and content key session

* up

* Add AVPlayerItem stuff

* Add DRM Token to the AVURLAsset

* Now we have done it mostly

* Add signed playback initializers back

* move FairplaySessionManager singleton

* Update Sources/MuxPlayerSwift/PublicAPI/Extensions/AVPlayerItem+Mux.swift

Co-authored-by: AJ Lauer Barinov <abarinov@mux.com>

* ok really move the singleton

* ok really move the singleton

* Caps

* api support for custom domain

* More capitalization

* Ignore xcshareddata and .swiftpm directores, they are user-private

* Fix crash on simulator (drm wont work still)

* Some logging

* Making license url

* Add method for requesting licenses

* Add Example videos

* up

* track playback ids

* getting there

* now we are maybe possibly getting somewhere

* Yes we are now getting our certs and things

* we don't need this method

* ok here we are so far

* more stuff

* e2e, doesnt work yet

* comments

* one more todo

* more

* Fixes

* un-dumb a comment

* More logging

* L O G N O I S E

* comments

* respect the safe area

* Some adjustments

* logging change

* unneeded field, nonsense comment

* here we go

* todo- error handling

* dont crash

* Rename a completion handler

* Now that is cleaner

* Less pointless base64

* eke a little more progress

* One more step

* rename slightly

* testability

* here we go

* Custom domains mostly in

* calculating license correctly

* Ok thats custom domains afaik

* here we go

* here we go

* ok

* app cert url

* ok custom domains

* fetch app certs

* And one rename

* And one rename

* cleaning up

* comment: recapitalize FairplaySessionManager

* up

* one last thing

* More cleanup, even more oh my god

* Extract FairPlaySessionManager into a protocol

---------

Co-authored-by: AJ Lauer Barinov <abarinov@mux.com>

maint: Add Unit Tests for FairPlaySessionManager + good DRM errors + small testability changes (#40)

* Ok here we go

* different URLSessions

* Fairplay -> FairPlay

* move helpers out of the protocol

* root domain testable

* file for fpssm tests

* warnings

* there we go. one test

* Rename FairPlaySessionManagerImpl to DefaultFPSMangaer

* Ok that's the trivial tests

* do the URLProtcol thing

* Mock URLSession

* Test success case for requestLicense

* Errors

* Error

* ok there's license almost done

* some tests

* Tests added

* So far so good

* now throw the right errors

* Added tests, need to update license error returns

* Ok now that's some good error handling

* Finished Cert and license tests

* test app cert request

* no more warnings

* Ok removed TempError

* cleanup a little

* little note

* Cleanup more

* Oops forgot ckc request headers

* refactor: redirect singleton calls to injected dependencies

refactor: place AVContentKeySession behind a protocol

build: fix build issues and tests

test setup

fix test

inject correctly

remove empty extension and avoid docc style comments for internal methods

remove optionals

* Rename abbreviated identifiers and split apart protocols

* Remove test session delegate

* turns out we do not need this

* refactor: minimize implicit singleton calls

* test: validate DRM registration when drm token provided

* Non-public API, use extension to initialize URL

* avoid tripping up docc for internal extensions

* cleaner test

* route calls to one chokepoint for simplicity

* We can use generics instead I think

* add a few comments

* some comments

* some comments

* Need to set ContentKeyDelegate

* Tests for ContentKeySessionDelegate + Testability Tweaks (#44)

* Extract AVContentKeyRequest protocol

* remove ContentKeyDelegate methods we're not using

* Hook in KeyRequest

* record some mocks

* ok this is what we can do

* here is something

* Something more

* now we are somewhere

* lol

* setting up

* now we have something goin

* errors

* there we go

* tests

* more error

* more tests

* Content key path

* happy path

* more

* Now that works

* now we are somewhere

* PR Comment: back to one SessionManager

* PR Comments: back to SessionMangaer

* And the tests

* PR comments: make some stuff optional

* nit

---------

Co-authored-by: AJ Lauer Barinov <abarinov@mux.com>

Remove region-check for staging

Beta notice for DRM

chore: merge v1.0.0 changes (#46)

* feat: expose API for configuring existing player view controllers (#41)

* feat: expose API for configuring existing player view controllers

to match what is provided for AVPlayerLayer

* docs: fixup grammar

* fix: remove rendition order ascending (#43)

* docs: fixups (#42)

* Fix up AVPlayerLayer too

* docs: typos

* docs: monitoring options improvements

* feat: HLS proxy server and URLCache integration (#24)

* fix: expose initializers (#26)

* feat: reverse proxy server

* test: add additional ui for testing

* use URLCache built-in as storage

* chore: add basic ABR observation

* chore: extract manifest processing to separate class, log cache size and segment size

* chore: rename playlist parsing to reflect technical definitions and purpose (including tests) (#27)

* test: account for percent encoding when checking URLs in query params

---------

Co-authored-by: Christian Pillsbury <cjpillsbury@gmail.com>

* chore: emit SDK diagnostics into unified logging system (#30)

* fix: Add basic cmaf support. (#31)

* fix: invert API for the smart cache (#32)

* fix: add extra percent encoding to avoid origin url truncation (#37)

* fix: add extra percent encoding to avoid origin url truncation

* fix tests

* fix: cache error fallback (#38)

* build: update Data SDK

* [NFC] reverse proxy cleanup

* use Foundation APIs to extract origin URL query value

* Squashed commit of the following:

commit d83a9aca216c77ea8997bd6111165c6cf5019e4e
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Mon May 6 19:28:48 2024 -0700

    fix customer data passthrough to data

commit 8048f53fde6f32552835e159a46f641b55b161cb
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Mon May 6 19:28:27 2024 -0700

    fix asc

commit 4e673dec1858d0b8f08160abfed0873370da0396
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Mon May 6 19:28:15 2024 -0700

    experiments

commit cff3c873a33182755eff6326bdfa1250a4b0b191
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Fri May 3 14:41:32 2024 -0700

    configurable playback modifiers when testing cache

commit 2e3d21e
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Fri May 3 13:42:44 2024 -0700

    configrable playback modifiers in example

commit e013cc3
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Thu May 2 14:02:09 2024 -0700

    fix: cache error fallback (#38)

    * build: update Data SDK

    * [NFC] reverse proxy cleanup

    * use Foundation APIs to extract origin URL query value

commit a642a87
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Fri Apr 26 12:19:43 2024 -0700

    fix: add extra percent encoding to avoid origin url truncation (#37)

    * fix: add extra percent encoding to avoid origin url truncation

    * fix tests

commit 47cfaf7
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Fri Feb 23 16:24:39 2024 -0800

    fix: invert API for the smart cache (#32)

commit efdeee0
Author: Christian Pillsbury <cjpillsbury@gmail.com>
Date:   Fri Feb 16 08:50:51 2024 -0800

    fix: Add basic cmaf support. (#31)

commit f03a419
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Tue Feb 13 14:45:59 2024 -0800

    chore: emit SDK diagnostics into unified logging system (#30)

commit 4d56d11
Author: AJ Lauer Barinov <abarinov@mux.com>
Date:   Tue Feb 13 11:54:41 2024 -0800

    feat: HLS proxy server and URLCache integration (#24)

    * fix: expose initializers (#26)

    * feat: reverse proxy server

    * test: add additional ui for testing

    * use URLCache built-in as storage

    * chore: add basic ABR observation

    * chore: extract manifest processing to separate class, log cache size and segment size

    * chore: rename playlist parsing to reflect technical definitions and purpose (including tests) (#27)

    * test: account for percent encoding when checking URLs in query params

    ---------

    Co-authored-by: Christian Pillsbury <cjpillsbury@gmail.com>

* chore: example cleanup

* chore: update version

* chore: remove debug view

* ci: add documentation generation scripts

* remove debug view controller

* feat: gate smart cache to single rendition playlists

* docs: release instructions

* docs: fixup single rendition enum descriptions

* docs: add the actual release steps

* build: update to AVPlayer Data SDK with privacy manifest

* start-up reverse proxy only when required

include additional examples

* SingleResolutionTier -> SingleRenditionResolutionTier

* Update installation version in README

* remove readme callout and create consolidated script for docs regeneration

* fix example

* fix capitalization

* disable diagnostics logging when in release mode

* Separate initialization method for single renditions

To help with example in guide. A separate init method rather than a
default parameter helps with discoverability of the enableSmartCache
option

* test: improve tests

* chore: expose environment variable accessors

* docs: add DRM example scaffolding

* add TODO

* restart player when example menu options change

---------

Co-authored-by: Christian Pillsbury <cjpillsbury@gmail.com>

fix: avoid setting empty custom domain in example (#47)

fix: initialize player item only once (#48)

chore: content key internal improvements (#49)

* additional environment variables

* chore: add a content key logger

* refactor: centralize URL construction inputs

* refactor: simplify URL construction logic

add recovery for when license or application certificate endpoint URLs
fail to be constructed

* fix: silent exception when deserializing empty response

* chore: use logger in content key session delegate

and some minor syntactic clean-up

* chore: emit failure to find playback ID in SKD log in the caller

chore: enable background mode picture in picture playback in the example (#50)

chore: synchronize project/drm with main (#51)

* feat: expose API for configuring existing player view controllers (#41)

* feat: expose API for configuring existing player view controllers

to match what is provided for AVPlayerLayer

* docs: fixup grammar

* fix: remove rendition order ascending (#43)

* docs: fixups (#42)

* Fix up AVPlayerLayer too

* docs: typos

* docs: monitoring options improvements

* v1.0.0 (#45)

* feat: HLS proxy server and URLCache integration (#24)

* test: add additional ui for testing

* use URLCache built-in as storage

* chore: add basic ABR observation

* chore: extract manifest processing to separate class, log cache size and segment size

* chore: rename playlist parsing to reflect technical definitions and purpose (including tests) (#27)

* test: account for percent encoding when checking URLs in query params

---------

Co-authored-by: Christian Pillsbury <cjpillsbury@gmail.com>

* chore: emit SDK diagnostics into unified logging system (#30)

* fix: Add basic cmaf support. (#31)

* fix: invert API for the smart cache (#32)

* fix: add extra percent encoding to avoid origin url truncation (#37)

* fix: cache error fallback (#38)

* build: update Data SDK
  • Loading branch information
daytime-em authored and andrewjl-mux committed Jun 28, 2024
1 parent ffc6b34 commit 9957303
Show file tree
Hide file tree
Showing 25 changed files with 2,458 additions and 200 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,8 @@ fastlane/test_output
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/

# The Example App xcodeproj creates these files when a custom scheme is made

.swiftpm
Examples/MuxPlayerSwiftExample/MuxPlayerSwiftExample.xcodeproj/xcshareddata
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
19DD16AF2BEC010400F4DF4F /* SinglePlayerExampleController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DD16AE2BEC010400F4DF4F /* SinglePlayerExampleController.swift */; };
19DD16B12BEC028C00F4DF4F /* SmartCacheExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DD16B02BEC028C00F4DF4F /* SmartCacheExampleViewController.swift */; };
19DD16B32BEC048300F4DF4F /* SinglePlayerLayerExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DD16B22BEC048300F4DF4F /* SinglePlayerLayerExampleViewController.swift */; };
19F6A1CE2C2F23EC00EE408A /* DRMExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19F6A1CD2C2F23EC00EE408A /* DRMExampleViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -56,6 +57,7 @@
19DD16AE2BEC010400F4DF4F /* SinglePlayerExampleController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SinglePlayerExampleController.swift; sourceTree = "<group>"; };
19DD16B02BEC028C00F4DF4F /* SmartCacheExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartCacheExampleViewController.swift; sourceTree = "<group>"; };
19DD16B22BEC048300F4DF4F /* SinglePlayerLayerExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SinglePlayerLayerExampleViewController.swift; sourceTree = "<group>"; };
19F6A1CD2C2F23EC00EE408A /* DRMExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DRMExampleViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -112,6 +114,7 @@
19DD16AE2BEC010400F4DF4F /* SinglePlayerExampleController.swift */,
19DD16B02BEC028C00F4DF4F /* SmartCacheExampleViewController.swift */,
19DD16B22BEC048300F4DF4F /* SinglePlayerLayerExampleViewController.swift */,
19F6A1CD2C2F23EC00EE408A /* DRMExampleViewController.swift */,
193228C02ACF6AC700966FE1 /* Main.storyboard */,
193228C32ACF6AC800966FE1 /* Assets.xcassets */,
193228C52ACF6AC800966FE1 /* LaunchScreen.storyboard */,
Expand Down Expand Up @@ -275,6 +278,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
19F6A1CE2C2F23EC00EE408A /* DRMExampleViewController.swift in Sources */,
19DD16B32BEC048300F4DF4F /* SinglePlayerLayerExampleViewController.swift in Sources */,
193228BB2ACF6AC700966FE1 /* AppDelegate.swift in Sources */,
19DD16B12BEC028C00F4DF4F /* SmartCacheExampleViewController.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
// MuxPlayerSwiftExample
//

import AVFoundation
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSession.Category.playback)
} catch {
print("Setting category to AVAudioSessionCategoryPlayback failed.")
}

return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,33 @@
<segue destination="JrU-9c-zyG" kind="show" id="q3v-VV-Yv9"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="OjC-bp-Jb4" detailTextLabel="bKF-tz-9d2" rowHeight="88" style="IBUITableViewCellStyleSubtitle" id="odP-sm-cIe">
<rect key="frame" x="0.0" y="314" width="393" height="88"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="odP-sm-cIe" id="dOo-zJ-LIx">
<rect key="frame" x="0.0" y="0.0" width="393" height="88"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="DRM Example" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="OjC-bp-Jb4" userLabel="DRM Example">
<rect key="frame" x="20.000000000000007" y="21.333333333333329" width="122.66666666666667" height="24"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Using AVPlayerViewController" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="bKF-tz-9d2" userLabel="Using AVPlayerViewController">
<rect key="frame" x="20" y="49" width="169.33333333333334" height="14.333333333333334"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="0.0"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="buK-6n-LKx" kind="show" id="eWu-XH-VJ4"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
Expand Down Expand Up @@ -163,6 +190,22 @@
</objects>
<point key="canvasLocation" x="-161" y="271"/>
</scene>
<!--Example View Controller-->
<scene sceneID="U4Y-IB-cxt">
<objects>
<viewController id="buK-6n-LKx" customClass="DRMExampleViewController" customModule="MuxPlayerSwiftExample" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="FcW-4i-Ijl">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="kho-JC-OWZ"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<navigationItem key="navigationItem" id="ZYa-D0-7Yh"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vny-A5-ZSO" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="434" y="573"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="2gk-Ck-Rao">
<objects>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//
// DRMExampleViewController.swift
// MuxPlayerSwiftExample
//

import AVKit
import UIKit

import MuxPlayerSwift

class DRMExampleViewController: UIViewController {

// MARK: Player View Controller

lazy var playerViewController = AVPlayerViewController(
playbackID: playbackID,
playbackOptions: PlaybackOptions(
playbackToken: playbackToken,
drmToken: drmToken,
customDomain: customDomain
)
)

// MARK: Mux Data Monitoring Parameters

var playerName: String = "MuxPlayerSwift-DRMExample"

var environmentKey: String? {
ProcessInfo.processInfo.environmentKey
}

// MARK: Mux Video Playback Parameters

var playbackID: String {
ProcessInfo.processInfo.playbackID ?? "qxb01i6T202018GFS02vp9RIe01icTcDCjVzQpmaB00CUisJ4"
}

// TODO: Display error alert if ProcessInfo returns nil
var playbackToken: String {
ProcessInfo.processInfo.playbackToken ?? ""
}

// TODO: Display error alert if ProcessInfo returns nil
var drmToken: String {
ProcessInfo.processInfo.drmToken ?? ""
}

// TODO: Display error alert if ProcessInfo returns nil
var customDomain: String? {
ProcessInfo.processInfo.customDomain ?? nil
}

// MARK: Status Bar Appearance

override var childForStatusBarStyle: UIViewController? {
playerViewController
}

// MARK: View Controller Lifecycle

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = .black

playerViewController.delegate = self
playerViewController.allowsPictureInPicturePlayback = true
playerViewController.canStartPictureInPictureAutomaticallyFromInline = true

displayPlayerViewController()
}

// MARK: Player Lifecycle

func displayPlayerViewController() {
playerViewController.willMove(toParent: self)
addChild(playerViewController)
view.addSubview(playerViewController.view)
playerViewController.didMove(toParent: self)
playerViewController
.view
.translatesAutoresizingMaskIntoConstraints = false
view.addConstraints([
playerViewController.view.leadingAnchor.constraint(
equalTo: view.leadingAnchor
),
playerViewController.view.trailingAnchor.constraint(
equalTo: view.trailingAnchor
),
playerViewController.view.layoutMarginsGuide.topAnchor.constraint(
equalTo: view.topAnchor
),
playerViewController.view.layoutMarginsGuide.bottomAnchor
.constraint(equalTo: view.bottomAnchor),
])
}

func hidePlayerViewController() {
playerViewController.willMove(toParent: nil)
playerViewController.view.removeFromSuperview()
playerViewController.removeFromParent()
}

}

extension DRMExampleViewController: AVPlayerViewControllerDelegate{
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
completionHandler(true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Examples.swift
// MuxPlayerSwiftExample
//
// Created by Emily Dixon on 4/24/24.
//

import Foundation

struct DRMExample {
let title: String
let playbackID: String
let playbackToken: String
let drmToken: String
}

extension DRMExample {
static let DRM_EXAMPLES = [
DRMExample(
title: "Staging test PlaybackID 1",
playbackID: "UHMpUMz4l00SmDcgAAQPd4Yk01200IDwD4uD7K24GPp01yg" ,
playbackToken: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ2IiwiZXhwIjoxNzIyNjE2OTc0LCJraWQiOiJFelE2SkI1ZkQwMmd5TmVxUmE4MDJYT2xnMDE0SzAxckxwdXNDbklRSjJobEtYbyIsInN1YiI6IlVITXBVTXo0bDAwU21EY2dBQVFQZDRZazAxMjAwSUR3RDR1RDdLMjRHUHAwMXlnIn0.rDymk2prKKDqlSKMnWDl24YNQ_LfnPlEzkBFr2-M3Yb_0mABE_bp-a2NeIKgwmqPxSvS0VAXpJApMbNa1j43yzW8oQxyZZXWnw0NLTQfdKfafDs83JVJB7uhL7MeEXcs1lpJGwLPSDYwdIPt2dKNzbATjqRViYbUO4GF14cq_35xsCb-kZy4D42_pdn62K6XnDUqccEeUmBav8W7m8ZILZ4eBJJJdCGVB9B85uGse_YTokGrXZ-chVO-uZ328B6ns_ehnhbJPtpstmUHvaqo0Xf0qF1J7pKkpbVoMwyhERB6M70m3oijP2GM1kLKAayrh1ujmNRNTXLcRJeBobqmPg",
drmToken: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsIiwiZXhwIjoxNzIyNjE2OTE0LCJraWQiOiJFelE2SkI1ZkQwMmd5TmVxUmE4MDJYT2xnMDE0SzAxckxwdXNDbklRSjJobEtYbyIsInN1YiI6IlVITXBVTXo0bDAwU21EY2dBQVFQZDRZazAxMjAwSUR3RDR1RDdLMjRHUHAwMXlnIn0.tHmqMgHf3pY2adP9QVvx9VIUVZvaxzWZP8Qf4DSUBnT4Zxac-tRPBsHDtBlFIILhmPhjBa2IAmD2PdqgHopSxw_zDp9ktTl6QAKCGgw40ZUKt4GD4aZKubKzAyfPm5q0-7f8aW8oNDbejQ1VjN5QqIBb50ytyPc4NkIzwqJ3P3azrr4TSlo-NiXbXhwWuiMHGqspoNPk8BGBcXpSML7vghlncxwKWYAwbpPaz5q5AEMmN5sqKo7woSVsXBxoe78al6cfT2SRdDR6bu92kMf5zSZ9600boNSjmNn2Dx5IidFAZMYy9qVj22W1T-7rCthmc37c9OcUGK9g0unHEAFE6A"
),
DRMExample(
title: "Staging Test PlaybackID 2",
playbackID: "OZYvDVHsfLebZw00En9vOO8Ta1pcIeuPO4Esbv2yCv4E",
playbackToken: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ2IiwiZXhwIjoxNzIyNjE4ODQxLCJraWQiOiJFelE2SkI1ZkQwMmd5TmVxUmE4MDJYT2xnMDE0SzAxckxwdXNDbklRSjJobEtYbyIsInN1YiI6Ik9aWXZEVkhzZkxlYlp3MDBFbjl2T084VGExcGNJZXVQTzRFc2J2MnlDdjRFIn0.p4D33mKmiHZYiO4Zhihx48MNcJQu0orZkezy1Wubrr3rTMInJSSlBEqaqEKgfSo505qXHx9n-zabIuM4hbGmpVNPY2aX8L3jDZU-o076NuYCjpiB87eQd6ilimOw5U-n55uCeYDXO6WYENmsy3trq-8hBMTmdloNeFXnCx1aECETU4ZmXXo3GnZBkWEWpRHyVqhFFOYxkeEWWHMvgrGoqkZHvLhHC93H9maz3KKCrqFqJeFrEo_idoJ-AsBqYhTGKhO2uGV_fhGUda6Qetc9QrqEK0WuxHwqpRbjR1cyvTbWDwCcvES1gXx4UDiWs1wdpZuyC3j2Y4LuPGAiLVWatA",
drmToken: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsIiwiZXhwIjoxNzIyNjE4ODI4LCJraWQiOiJFelE2SkI1ZkQwMmd5TmVxUmE4MDJYT2xnMDE0SzAxckxwdXNDbklRSjJobEtYbyIsInN1YiI6Ik9aWXZEVkhzZkxlYlp3MDBFbjl2T084VGExcGNJZXVQTzRFc2J2MnlDdjRFIn0.K6CCI-RGsTXGK0y-u2SseXea33tR5SbbX9wvucF7j0UictV6_VB0TsZe3SPlU_3ST0ecedLegbyJu-_4I6h7-XDApfXCGslYFoqM5iZnQ_5YtL0Zkdeh2iHJZKyS-mH_z6lyojggbFPLFGgRC0gZVfXJwdDtAUi33wOnlvkvGOdzNXmJCrRInkg7OfRKvLzxkQnQ0kTagKtq74Uv5JpG6XeascSi6tXExM8KVxG-4VEWHvBqCQvrpV6xlZmSnlOvoLT7E2oQB-6rwvy4cFnA_1ZASxHxiAZTNppPTmdmDYxDUd8qwJiL7MtF73sfqcrooH-z9p35u9t7eqiUGlslcA"
)
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@
</array>
</dict>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

import Foundation

// Configure these as environment variables in
// application scheme
extension ProcessInfo {

// MARK: Mux Data Environment Key
var environmentKey: String? {
guard let value = environment["ENV_KEY"],
!value.isEmpty else {
Expand All @@ -15,6 +19,8 @@ extension ProcessInfo {
return value
}

// MARK: Mux Video Playback Constants

var playbackID: String? {
guard let value = environment["PLAYBACK_ID"],
!value.isEmpty else {
Expand All @@ -23,4 +29,71 @@ extension ProcessInfo {

return value
}

var playbackToken: String? {
guard let value = environment["PLAYBACK_TOKEN"],
!value.isEmpty else {
return nil
}

return value
}

var drmToken: String? {
guard let value = environment["DRM_TOKEN"],
!value.isEmpty else {
return nil
}

return value
}

var secondaryPlaybackID: String? {
guard let value = environment["SECONDARY_PLAYBACK_ID"],
!value.isEmpty else {
return nil
}

return value
}

var secondaryPlaybackToken: String? {
guard let value = environment["SECONDARY_PLAYBACK_TOKEN"],
!value.isEmpty else {
return nil
}

return value
}

var secondaryDRMToken: String? {
guard let value = environment["SECONDARY_DRM_TOKEN"],
!value.isEmpty else {
return nil
}

return value
}

// MARK: Mux Video Custom Playback Domain


/// Once Mux has provisioned your Custom Domain, set the
/// `CUSTOM_DOMAIN` environment variable and Mux Player
/// Swift will pass that on to `AVPlayer` to use when
/// streaming video.
///
/// Mux Player Swift automatically prepends the `stream`
/// subdomain for you. This means that if you set
/// `media.example.com` as `CUSTOM_DOMAIN` then `AVPlayer`
/// will use `stream.media.example.com` when requesting
/// media. [See here for more details](https://www.mux.com/blog/introducing-custom-domains).
var customDomain: String? {
guard let value = environment["CUSTOM_DOMAIN"],
!value.isEmpty else {
return nil
}

return value
}
}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ A collection of helpful utilities for using AVKit and AVFoundation to stream vid

We'd love to hear your feedback, shoot us a note at avplayer@mux.com with any feature requests, API feedback, or to tell us about what you'd like to build.

#### Mux Video DRM Beta

This SDK supports Mux Video's DRM feature, which is currently in closed beta. If you are interested in using our DRM features, please sign up on our [beta page](https://www.mux.com/beta/drm)

## Installation

### Installing in Xcode using Swift Package Manager
Expand Down
Loading

0 comments on commit 9957303

Please sign in to comment.