Skip to content

Commit

Permalink
Merge branch 'release/3.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
defagos committed Jan 22, 2018
2 parents e9b72e9 + b7f71aa commit f519c52
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 268 deletions.
4 changes: 2 additions & 2 deletions Cartfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
github "SRGSSR/SRGMediaPlayer-iOS" "2.2.1"
github "SRGSSR/srgdataprovider-ios" "5.5.2"
github "SRGSSR/SRGMediaPlayer-iOS" "2.2.2"
github "SRGSSR/srgdataprovider-ios" "5.6"
github "SRGSSR/tagcommander-ios" "4.1.5_4.1.3"
github "comScore/ComScore-iOS-SDK" "92f34897cd7659d56bb5a3e9e85b808cf3758bda"
4 changes: 2 additions & 2 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
github "Mantle/Mantle" "2.1.0"
github "SRGSSR/MAKVONotificationCenter" "d5af67218b3b7b49660a43edef5e6eb9c437d670"
github "SRGSSR/SRGMediaPlayer-iOS" "2.2.1"
github "SRGSSR/SRGMediaPlayer-iOS" "2.2.2"
github "SRGSSR/libextobjc" "46f179fbba8dde2a3eb3da284919789b78aac441"
github "SRGSSR/srgdataprovider-ios" "5.5.2"
github "SRGSSR/srgdataprovider-ios" "5.6"
github "SRGSSR/srglogger-ios" "1.0"
github "SRGSSR/tagcommander-ios" "4.1.5_4.1.3"
github "comScore/ComScore-iOS-SDK" "92f34897cd7659d56bb5a3e9e85b808cf3758bda"
Expand Down
17 changes: 17 additions & 0 deletions Framework/Sources/Core/SRGAnalyticsTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ - (void)startTagCommanderTrackerWithConfiguration:(SRGAnalyticsConfiguration *)c
[self.tagCommander addPermanentData:@"app_library_version" withValue:SRGAnalyticsMarketingVersion()];
[self.tagCommander addPermanentData:@"navigation_app_site_name" withValue:configuration.comScoreVirtualSite];
[self.tagCommander addPermanentData:@"navigation_environment" withValue:[NSBundle srg_isProductionVersion] ? @"prod" : @"preprod"];
[self.tagCommander addPermanentData:@"navigation_device" withValue:[self device]];
}
}

Expand Down Expand Up @@ -148,6 +149,22 @@ - (NSString *)pageIdWithTitle:(NSString *)title levels:(NSArray<NSString *> *)le
return [NSString stringWithFormat:@"%@.%@", category, title.srg_comScoreFormattedString];
}

- (NSString *)device
{
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
return @"phone";
}
else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
return @"tablet";
}
else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomTV) {
return @"tvbbox";
}
else {
return @"phone";
}
}

#pragma mark General event tracking (internal use only)

- (void)trackEventWithLabels:(NSDictionary<NSString *, NSString *> *)labels
Expand Down
2 changes: 1 addition & 1 deletion Framework_DataProvider/SRGAnalytics_DataProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
#import <UIKit/UIKit.h>

// Public headers.
#import "SRGMediaComposition+SRGAnalytics_DataProvider.h"
#import "SRGMediaPlayerController+SRGAnalytics_DataProvider.h"
#import "SRGSegment+SRGAnalytics_DataProvider.h"
#import "SRGSubdivision+SRGAnalytics_DataProvider.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

#import <SRGAnalytics/SRGAnalytics.h>
#import <SRGMediaPlayer/SRGMediaPlayer.h>
#import <SRGDataProvider/SRGDataProvider.h>

NS_ASSUME_NONNULL_BEGIN

// Completion block signatures.
typedef void (^SRGResourceCompletionBlock)(NSURL * _Nullable tokenizedURL, SRGResource *resource, NSArray<id<SRGSegment>> *segments, NSInteger index, SRGAnalyticsStreamLabels * _Nullable analyticsLabels, NSError * _Nullable error);

@interface SRGMediaComposition (SRGAnalytics_DataProvider)

/**
* Return a request to retrieve a playable resource for the receiver, trying to use the specified preferred settings.
* If no exact match can be found for the specified settings, a recommended valid setup will be used instead. A
* readily tokenized URL (playable for a limited time only) is also provided to the completion block.
*
* @param streamingMethod The streaming method to use. If `SRGStreamingMethodNone` or if the method is not
* found, a recommended method will be used instead.
* @param streamType The stream type to use. If `SRGStreamTypeNone` or not found, the optimal available stream
* type is used.
* @param quality The quality to use. If `SRGQualityNone` or not found, the best available quality
* is used.
* @param startBitRate The bit rate the media should start playing with, in kbps. This parameter is a
* recommendation with no result guarantee, though it should in general be applied. The
* nearest available quality (larger or smaller than the requested size) will be used.
* Usual SRG SSR valid bit ranges vary from 100 to 3000 kbps. Use 0 to start with the
* lowest quality stream.
* @param userInfo Optional dictionary conveying arbitrary information during playback.
* @param completionHandler The completion handler, returning the URL, the associated resource, the segments associated
* with the media, the segment index to start with, as well as consolidated analytics labels.
*
* @return The method might return `nil` if no protocol / quality combination is found. Resource lookup is performed so
* that a matching streaming method is found first, then a matching stream type, and finally a quality.
*/
- (nullable SRGRequest *)resourceWithPreferredStreamingMethod:(SRGStreamingMethod)streamingMethod
streamType:(SRGStreamType)streamType
quality:(SRGQuality)quality
startBitRate:(NSInteger)startBitRate
completionBlock:(SRGResourceCompletionBlock)completionBlock;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

#import "SRGMediaComposition+SRGAnalytics_DataProvider.h"

#import "SRGAnalyticsMediaPlayerLogger.h"
#import "SRGSegment+SRGAnalytics_DataProvider.h"

#import <libextobjc/libextobjc.h>

@implementation SRGMediaComposition (SRGAnalytics_DataProvider)

- (SRGAnalyticsStreamLabels *)analyticsLabelsForResource:(SRGResource *)resource
{
NSAssert([self.mainChapter.resources containsObject:resource], @"The specified resource must be associated with the current context");

SRGAnalyticsStreamLabels *labels = [[SRGAnalyticsStreamLabels alloc] init];

NSMutableDictionary<NSString *, NSString *> *customInfo = [NSMutableDictionary dictionary];
if (self.analyticsLabels) {
[customInfo addEntriesFromDictionary:self.analyticsLabels];
}
if (self.mainChapter.analyticsLabels) {
[customInfo addEntriesFromDictionary:self.mainChapter.analyticsLabels];
}
if (resource.analyticsLabels) {
[customInfo addEntriesFromDictionary:resource.analyticsLabels];
}
labels.customInfo = [customInfo copy];

NSMutableDictionary<NSString *, NSString *> *comScoreCustomInfo = [NSMutableDictionary dictionary];
if (self.comScoreAnalyticsLabels) {
[comScoreCustomInfo addEntriesFromDictionary:self.comScoreAnalyticsLabels];
}
if (self.mainChapter.comScoreAnalyticsLabels) {
[comScoreCustomInfo addEntriesFromDictionary:self.mainChapter.comScoreAnalyticsLabels];
}
if (resource.comScoreAnalyticsLabels) {
[comScoreCustomInfo addEntriesFromDictionary:resource.comScoreAnalyticsLabels];
}
labels.comScoreCustomInfo = [comScoreCustomInfo copy];

return labels;
}

- (SRGRequest *)resourceWithPreferredStreamingMethod:(SRGStreamingMethod)streamingMethod
streamType:(SRGStreamType)streamType
quality:(SRGQuality)quality
startBitRate:(NSInteger)startBitRate
completionBlock:(SRGResourceCompletionBlock)completionBlock
{
if (startBitRate < 0) {
startBitRate = 0;
}

SRGChapter *chapter = self.mainChapter;

if (streamingMethod == SRGStreamingMethodNone) {
streamingMethod = chapter.recommendedStreamingMethod;
}

NSArray<SRGResource *> *resources = [chapter resourcesForStreamingMethod:streamingMethod];
if (resources.count == 0) {
resources = [chapter resourcesForStreamingMethod:chapter.recommendedStreamingMethod];
}

// Determine the stream type order to use (start with a default setup, overridden if a preferred type has been set),
// from the lowest to the highest priority.
NSArray<NSNumber *> *orderedStreamTypes = @[@(SRGStreamTypeOnDemand), @(SRGStreamTypeLive), @(SRGStreamTypeDVR)];
if (streamType != SRGStreamTypeNone) {
orderedStreamTypes = [[orderedStreamTypes mtl_arrayByRemovingObject:@(streamType)] arrayByAddingObject:@(streamType)];
}

NSSortDescriptor *streamTypeSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@keypath(SRGResource.new, streamType) ascending:NO comparator:^(NSNumber * _Nonnull streamType1, NSNumber * _Nonnull streamType2) {
// Don't simply compare enum values as integers since their order might change.
NSUInteger index1 = [orderedStreamTypes indexOfObject:streamType1];
NSUInteger index2 = [orderedStreamTypes indexOfObject:streamType2];
if (index1 == index2) {
return NSOrderedSame;
}
else if (index1 < index2) {
return NSOrderedAscending;
}
else {
return NSOrderedDescending;
}
}];

NSSortDescriptor *URLSchemeSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@keypath(SRGResource.new, URL) ascending:NO comparator:^NSComparisonResult(NSURL * _Nonnull URL1, NSURL * _Nonnull URL2) {
// Only declare ordering for important URL schemes. For other schemes the initial order will be preserved
NSArray<NSString *> *orderedURLSchemes = @[@"http", @"https"];

NSUInteger index1 = [orderedURLSchemes indexOfObject:URL1.scheme];
NSUInteger index2 = [orderedURLSchemes indexOfObject:URL2.scheme];
if (index1 == index2) {
return NSOrderedSame;
}
// Unknown scheme < known scheme
else if (index1 == NSNotFound) {
return NSOrderedAscending;
}
// Known scheme > unknown scheme
else if (index2 == NSNotFound) {
return NSOrderedDescending;
}
else if (index1 < index2) {
return NSOrderedAscending;
}
else {
return NSOrderedDescending;
}
}];
resources = [resources sortedArrayUsingDescriptors:@[streamTypeSortDescriptor, URLSchemeSortDescriptor]];

// Resources are initially ordered by quality (see `-resourcesForStreamingMethod:` documentation), and this order
// is kept stable by the stream type sort descriptor above. We therefore attempt to find a proper match for the specified
// quality, otherwise we just use the first resource available.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @keypath(SRGResource.new, quality), @(quality)];
SRGResource *resource = [resources filteredArrayUsingPredicate:predicate].firstObject ?: resources.firstObject;
if (! resource) {
SRGAnalyticsMediaPlayerLogError(@"mediaplayer", @"No valid resource could be retrieved");
return nil;
}

// Use the preferrred start bit rate is set. Currrently only supported by Akamai via a __b__ parameter (the actual
// bitrate will be rounded to the nearest available quality)
NSURL *URL = resource.URL;
if (startBitRate != 0 && [URL.host containsString:@"akamai"]) {
NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];

NSMutableArray<NSURLQueryItem *> *queryItems = [URLComponents.queryItems mutableCopy] ?: [NSMutableArray array];
[queryItems addObject:[NSURLQueryItem queryItemWithName:@"__b__" value:@(startBitRate).stringValue]];
URLComponents.queryItems = [queryItems copy];

URL = URLComponents.URL;
}

SRGRequest *request = [SRGDataProvider tokenizeURL:URL withCompletionBlock:^(NSURL * _Nullable URL, NSError * _Nullable error) {
// Bypass token server response, if an error occurred. We don't want to block the media player here
if (error) {
URL = resource.URL;
}

SRGAnalyticsStreamLabels *labels = [self analyticsLabelsForResource:resource];
NSInteger index = [chapter.segments indexOfObject:self.mainSegment];
completionBlock(URL, resource, chapter.segments, index, labels, nil);
}];
return request;
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Copyright (c) SRG SSR. All rights reserved.
//
// License information is available from the LICENSE file.
//

#import <SRGAnalytics/SRGAnalytics.h>
#import <SRGDataProvider/SRGDataProvider.h>

NS_ASSUME_NONNULL_BEGIN

@interface SRGMediaComposition (SRGAnalytics_DataProvider_Private)

/**
* Return the consolidated analytics stream labels associated for with the specified resource of the receiver.
*
* @discussion An exception is thrown in debug builds if the resource is not associated with the receiver.
*/
- (SRGAnalyticsStreamLabels *)analyticsLabelsForResource:(SRGResource *)resource;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, nullable) SRGMediaComposition *mediaComposition;

/**
* The streaming method used for playback, `SRGStreamingMethodNone` if none.
* The resource used for playback, `nil` if none.
*/
@property (nonatomic, readonly) SRGStreamingMethod streamingMethod;

/**
* The quality used for playback, `SRGQualityNone` if none.
*/
@property (nonatomic, readonly) SRGQuality quality;
@property (nonatomic, readonly, nullable) SRGResource *resource;

@end

Expand Down
Loading

0 comments on commit f519c52

Please sign in to comment.