Skip to content

Commit

Permalink
Merge branch 'release/1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
defagos committed Sep 28, 2018
2 parents e3f3f6c + 3786b32 commit 0b74b7e
Show file tree
Hide file tree
Showing 32 changed files with 494 additions and 139 deletions.
9 changes: 6 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
*.xcscmblueprint
xcuserdata

archive
build
/archive
/build

Carthage
/Carthage

/fastlane/report.xml
/fastlane/test_output
3 changes: 2 additions & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
github "SRGSSR/srgnetwork-ios" "0.2"
github "SRGSSR/srgdiagnostics-ios" "1.0"
github "SRGSSR/srgnetwork-ios" "0.2.1"
3 changes: 2 additions & 1 deletion Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
github "SRGSSR/srgnetwork-ios" "0.2"
github "SRGSSR/srgdiagnostics-ios" "1.0"
github "SRGSSR/srgnetwork-ios" "0.2.1"
2 changes: 1 addition & 1 deletion Demo/Sources/Application/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
return UIApplicationMain(argc, argv, nil, NSStringFromClass(AppDelegate.class));
}
}
4 changes: 2 additions & 2 deletions Demo/Sources/Demos/DemosViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
}

case 1: {
asset = [AVURLAsset srg_assetWithURL:URL licenseURL:nil];
asset = [AVURLAsset srg_assetWithURL:URL certificateURL:nil];
break;
}

case 2: {
asset = [AVURLAsset srg_assetWithURL:URL licenseURL:[NSURL URLWithString:@"https://rng.stage.ott.irdeto.com/licenseServer/streaming/v1/SRG/getcertificate?applicationId=stage"]];
asset = [AVURLAsset srg_assetWithURL:URL certificateURL:[NSURL URLWithString:@"https://rng.stage.ott.irdeto.com/licenseServer/streaming/v1/SRG/getcertificate?applicationId=stage"]];
break;
}

Expand Down
42 changes: 21 additions & 21 deletions Demo/Sources/Demos/DemosViewController.storyboard

Large diffs are not rendered by default.

24 changes: 19 additions & 5 deletions Framework/Sources/Categories/AVURLAsset+SRGContentProtection.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// License information is available from the LICENSE file.
//

#import "SRGContentProtectionConstants.h"

#import <AVFoundation/AVFoundation.h>

NS_ASSUME_NONNULL_BEGIN
Expand All @@ -21,18 +23,30 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Create an asset supporting standard SRG SSR content protection.
*
* @param URL The URL to be played.
* @param URL The URL to be played.
* @param options Asset playback options.
*/
+ (instancetype)srg_assetWithURL:(NSURL *)URL options:(nullable NSDictionary<SRGAssetOption, id> *)options;

/**
* Same as `-srg_assetWithURL:userInfo:`, but without user information dictionary.
*/
+ (instancetype)srg_assetWithURL:(NSURL *)URL;

/**
* Create an asset supporting standard SRG SSR content protection. Digital rights management can optionally be enabled
* by supplying a URL to retrieve licenses from.
* by supplying a URL to retrieve the certificate from.
*
* @param URL The URL to be played.
* @param licenseURL The URL where licenses must be retrieved.
* @param URL The URL to be played.
* @param certificateURL The URL where the certificate must be retrieved.
* @param options Asset playback options.
*/
+ (instancetype)srg_assetWithURL:(NSURL *)URL certificateURL:(nullable NSURL *)certificateURL options:(nullable NSDictionary<SRGAssetOption, id> *)options;

/**
* Same as `-srg_assetWithURL:certificateURL:userInfo:`, but without user information dictionary.
*/
+ (instancetype)srg_assetWithURL:(NSURL *)URL licenseURL:(nullable NSURL *)licenseURL;
+ (instancetype)srg_assetWithURL:(NSURL *)URL certificateURL:(nullable NSURL *)certificateURL;

@end

Expand Down
26 changes: 19 additions & 7 deletions Framework/Sources/Categories/AVURLAsset+SRGContentProtection.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ @implementation AVURLAsset (SRGContentProtection)

#pragma mark Class methods

+ (instancetype)srg_assetWithURL:(NSURL *)URL resourceLoaderDelegate:(id<SRGAssetResourceLoaderDelegate>)resourceLoaderDelegate
+ (instancetype)srg_assetWithURL:(NSURL *)URL resourceLoaderDelegate:(SRGAssetResourceLoaderDelegate *)resourceLoaderDelegate
{
NSURL *assetURL = [resourceLoaderDelegate respondsToSelector:@selector(assetURLForURL:)] ? [resourceLoaderDelegate assetURLForURL:URL] : URL;
NSURL *assetURL = resourceLoaderDelegate ? [resourceLoaderDelegate assetURLForURL:URL] : URL;
AVURLAsset *asset = [AVURLAsset assetWithURL:assetURL];
objc_setAssociatedObject(asset, SRGContentProtectionResourceLoaderDelegateKey, resourceLoaderDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

Expand All @@ -29,21 +29,33 @@ + (instancetype)srg_assetWithURL:(NSURL *)URL resourceLoaderDelegate:(id<SRGAsse
return asset;
}

+ (instancetype)srg_assetWithURL:(NSURL *)URL options:(NSDictionary<SRGAssetOption,id> *)options
{
return [self srg_assetWithURL:URL certificateURL:nil options:options];
}

+ (instancetype)srg_assetWithURL:(NSURL *)URL
{
return [self srg_assetWithURL:URL licenseURL:nil];
return [self srg_assetWithURL:URL];
}

+ (instancetype)srg_assetWithURL:(NSURL *)URL licenseURL:(NSURL *)licenseURL
+ (instancetype)srg_assetWithURL:(NSURL *)URL certificateURL:(NSURL *)certificateURL options:(NSDictionary<SRGAssetOption,id> *)options
{
id<SRGAssetResourceLoaderDelegate> resourceLoaderDelegate = nil;
if (licenseURL) {
resourceLoaderDelegate = [[SRGFairPlayAssetResourceLoaderDelegate alloc] initWithCertificateURL:licenseURL];
SRGAssetResourceLoaderDelegate *resourceLoaderDelegate = nil;
if (certificateURL) {
resourceLoaderDelegate = [[SRGFairPlayAssetResourceLoaderDelegate alloc] initWithCertificateURL:certificateURL];
}
else if ([URL.host containsString:@"akamai"] && [URL.path.pathExtension isEqualToString:@"m3u8"]) {
resourceLoaderDelegate = [[SRGAkamaiAssetResourceLoaderDelegate alloc] init];
}
resourceLoaderDelegate.options = options;

return [self srg_assetWithURL:URL resourceLoaderDelegate:resourceLoaderDelegate];
}

+ (instancetype)srg_assetWithURL:(NSURL *)URL certificateURL:(NSURL *)certificateURL
{
return [self srg_assetWithURL:URL certificateURL:certificateURL options:nil];
}

@end
4 changes: 2 additions & 2 deletions Framework/Sources/Categories/NSBundle+SRGContentProtection.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Convenience macro for localized strings associated with the framework.
*/
#define SRGContentProtectionLocalizedString(key, comment) [[NSBundle srg_contentProtectionBundle] localizedStringForKey:(key) value:@"" table:nil]
#define SRGContentProtectionLocalizedString(key, comment) [NSBundle.srg_contentProtectionBundle localizedStringForKey:(key) value:@"" table:nil]

@interface NSBundle (SRGContentProtection)

/**
* The framework resource bundle.
*/
+ (NSBundle *)srg_contentProtectionBundle;
@property (class, nonatomic, readonly) NSBundle *srg_contentProtectionBundle;

@end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ + (instancetype)srg_contentProtectionBundle
static NSBundle *s_bundle;
static dispatch_once_t s_onceToken;
dispatch_once(&s_onceToken, ^{
NSString *bundlePath = [[NSBundle bundleForClass:[SRGAkamaiAssetResourceLoaderDelegate class]].bundlePath stringByAppendingPathComponent:@"SRGContentProtection.bundle"];
NSString *bundlePath = [[NSBundle bundleForClass:SRGAkamaiAssetResourceLoaderDelegate.class].bundlePath stringByAppendingPathComponent:@"SRGContentProtection.bundle"];
s_bundle = [NSBundle bundleWithPath:bundlePath];
NSAssert(s_bundle, @"Please add SRGContentProtection.bundle to your project resources");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Resource loader delegate for Akamai token-protected streams.
*/
@interface SRGAkamaiAssetResourceLoaderDelegate : NSObject <SRGAssetResourceLoaderDelegate>
@interface SRGAkamaiAssetResourceLoaderDelegate : SRGAssetResourceLoaderDelegate

@end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#import "SRGAkamaiToken.h"
#import "SRGContentProtectionError.h"

#import <SRGDiagnostics/SRGDiagnostics.h>

static NSString * const SRGStandardURLSchemePrefix = @"akamai";

@interface SRGAkamaiAssetResourceLoaderDelegate ()
Expand Down Expand Up @@ -42,15 +44,51 @@ - (instancetype)init
return self;
}

#pragma mark Common resource loading request processing
#pragma mark Getters and setters

- (SRGDiagnosticInformation *)diagnosticInformation
{
NSString *serviceName = self.options[SRGAssetOptionDiagnosticServiceNameKey];
NSString *reportName = self.options[SRGAssetOptionDiagnosticReportNameKey];
if (serviceName && reportName) {
return [[[SRGDiagnosticsService serviceWithName:serviceName] reportWithName:reportName] informationForKey:@"tokenResult"];
}
else {
return nil;
}
}

#pragma mark Subclassing hooks

- (NSURL *)assetURLForURL:(NSURL *)URL
{
/**
* Use non-standard scheme unkwown to AirPlay receivers like the Apple TV. This ensures that the resource
* loader delegate is used (if the resource is simply an HTTP one, the receiver thinks it can handle it,
* and does not call the resource loader delegate).
*
* See https://stackoverflow.com/a/30154884/760435
*/
NSURLComponents *components = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
components.scheme = [@[ SRGStandardURLSchemePrefix, components.scheme ] componentsJoinedByString:@"+"];
return components.URL;
}

- (BOOL)shouldProcessResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
SRGDiagnosticInformation *diagnosticInformation = [self diagnosticInformation];
[diagnosticInformation startTimeMeasurementForKey:@"duration"];

// About thread-safety considerations: The delegate methods are called from background threads, and though there is
// no explicit documentation, Apple examples show that completion calls can be made from background threads. There
// is probably no need to dispatch any work to the main thread.
NSURL *requestURL = [self URLForAssetURL:loadingRequest.request.URL];
self.request = [SRGAkamaiToken tokenizeURL:requestURL withSession:self.session completionBlock:^(NSURL * _Nonnull URL, NSHTTPURLResponse * _Nonnull HTTPResponse) {
self.request = [SRGAkamaiToken tokenizeURL:requestURL withSession:self.session completionBlock:^(NSURL * _Nonnull URL, NSHTTPURLResponse * _Nonnull HTTPResponse, NSError * _Nullable error) {
[diagnosticInformation setURL:HTTPResponse.URL forKey:@"url"];
[diagnosticInformation setInteger:HTTPResponse.statusCode forKey:@"httpStatusCode"];
[diagnosticInformation setString:error.localizedDescription forKey:@"message"];
[diagnosticInformation stopTimeMeasurementForKey:@"duration"];

NSMutableURLRequest *playlistRequest = [loadingRequest.request mutableCopy];
playlistRequest.URL = URL;
self.request = [[SRGNetworkRequest alloc] initWithURLRequest:playlistRequest session:self.session options:0 completionBlock:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
Expand All @@ -75,33 +113,7 @@ - (BOOL)shouldProcessResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loa
return YES;
}

#pragma mark SRGAssetResourceLoaderDelegate protocol

- (NSURL *)assetURLForURL:(NSURL *)URL
{
/**
* Use non-standard scheme unkwown to AirPlay receivers like the Apple TV. This ensures that the resource
* loader delegate is used (if the resource is simply an HTTP one, the receiver thinks it can handle it,
* and does not call the resource loader delegate).
*
* See https://stackoverflow.com/a/30154884/760435
*/
NSURLComponents *components = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
components.scheme = [@[ SRGStandardURLSchemePrefix, components.scheme ] componentsJoinedByString:@"+"];
return components.URL;
}

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
return [self shouldProcessResourceLoadingRequest:loadingRequest];
}

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForRenewalOfRequestedResource:(AVAssetResourceRenewalRequest *)renewalRequest
{
return [self shouldProcessResourceLoadingRequest:renewalRequest];
}

- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
- (void)didCancelResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
[self.request cancel];
}
Expand Down
28 changes: 23 additions & 5 deletions Framework/Sources/ResourceLoaders/SRGAssetResourceLoaderDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,40 @@
// License information is available from the LICENSE file.
//

#import "SRGContentProtectionConstants.h"

#import <AVFoundation/AVFoundation.h>

NS_ASSUME_NONNULL_BEGIN

/**
* Resource loader delegate protocol.
* Resource loader abstract base class.
*/
@protocol SRGAssetResourceLoaderDelegate <AVAssetResourceLoaderDelegate>

@optional
@interface SRGAssetResourceLoaderDelegate : NSObject <AVAssetResourceLoaderDelegate>

/**
* Return the asset URL to use for a given URL. If not implemented, the original URL will be used.
* Suclasses can override this method to return another URL to use for a given URL. The default implementation returns
* the original URL received as parameter.
*/
- (NSURL *)assetURLForURL:(NSURL *)URL;

/**
* Subclasses must override this method to process the loading request appropriately. The default implementation does
* nothing and returns `NO`.
*/
- (BOOL)shouldProcessResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest;

/**
* Subclasses must override this method to respond to a resource having been cancelled. The default implementation does
* nothing.
*/
- (void)didCancelResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest;

/**
* Optional information associated with the receiver.
*/
@property (nonatomic, nullable) NSDictionary<SRGAssetOption, id> *options;

@end

NS_ASSUME_NONNULL_END
43 changes: 43 additions & 0 deletions Framework/Sources/ResourceLoaders/SRGAssetResourceLoaderDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

#import "SRGAssetResourceLoaderDelegate.h"

@implementation SRGAssetResourceLoaderDelegate

#pragma mark Default implementations

- (NSURL *)assetURLForURL:(NSURL *)URL
{
return URL;
}

- (BOOL)shouldProcessResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
return NO;
}

- (void)didCancelResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{}

#pragma mark AVAssetResourceLoaderDelegate protocol

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
{
return [self shouldProcessResourceLoadingRequest:loadingRequest];
}

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForRenewalOfRequestedResource:(AVAssetResourceRenewalRequest *)renewalRequest
{
return [self shouldProcessResourceLoadingRequest:renewalRequest];
}

- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest
{
[self didCancelResourceLoadingRequest:loadingRequest];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Resource loader delegate for streams encrypted with FairPlay.
*/
@interface SRGFairPlayAssetResourceLoaderDelegate : NSObject <SRGAssetResourceLoaderDelegate>
@interface SRGFairPlayAssetResourceLoaderDelegate : SRGAssetResourceLoaderDelegate

/**
* Create an instance retrieving certificates at the specified URL.
Expand Down
Loading

0 comments on commit 0b74b7e

Please sign in to comment.