Skip to content

Commit

Permalink
Merge branch 'develop' into feature/touch_manager
Browse files Browse the repository at this point in the history
# Conflicts:
#	SmartDeviceLink/SDLStreamingMediaManager.h
#	SmartDeviceLink/SDLStreamingMediaManager.m
  • Loading branch information
joeljfischer committed Jul 29, 2016
2 parents 10b8220 + 8fd3b1c commit ca91918
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 29 deletions.
16 changes: 13 additions & 3 deletions SmartDeviceLink/SDLProxy.m
Expand Up @@ -29,7 +29,7 @@
#import "SDLProtocolMessage.h"
#import "SDLProtocolMessage.h"
#import "SDLPutFile.h"
#import "SDLRPCPayload.h"
#import "SDLRegisterAppInterfaceResponse.h"
#import "SDLRPCPayload.h"
#import "SDLRPCRequestFactory.h"
#import "SDLRPCResponse.h"
Expand All @@ -56,7 +56,8 @@ @interface SDLProxy () {
}

@property (strong, nonatomic) NSMutableSet *mutableProxyListeners;
@property (nonatomic, strong, readwrite) SDLStreamingMediaManager *streamingMediaManager;
@property (nonatomic, strong, readwrite, nullable) SDLStreamingMediaManager *streamingMediaManager;
@property (nonatomic, strong, nullable) SDLDisplayCapabilities* displayCapabilities;

@end

Expand Down Expand Up @@ -101,6 +102,8 @@ - (void)destructObjects {
_transport = nil;
_protocol = nil;
_mutableProxyListeners = nil;
_streamingMediaManager = nil;
_displayCapabilities = nil;
}
}

Expand Down Expand Up @@ -166,7 +169,10 @@ - (NSString *)proxyVersion {

- (SDLStreamingMediaManager *)streamingMediaManager {
if (_streamingMediaManager == nil) {
_streamingMediaManager = [[SDLStreamingMediaManager alloc] initWithProtocol:self.protocol];
if (self.displayCapabilities == nil) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"SDLStreamingMediaManager must be accessed only after a successful RegisterAppInterfaceResponse" userInfo:nil];
}
_streamingMediaManager = [[SDLStreamingMediaManager alloc] initWithProtocol:self.protocol displayCapabilities:self.displayCapabilities];
[self.protocol.protocolDelegateTable addObject:_streamingMediaManager];
[self.mutableProxyListeners addObject:_streamingMediaManager.touchManager];
}
Expand Down Expand Up @@ -328,6 +334,10 @@ - (void)handleRegisterAppInterfaceResponse:(SDLRPCResponse *)response {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMobileHMIState) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMobileHMIState) name:UIApplicationDidEnterBackgroundNotification object:nil];
}

// Extract the display capabilties to successfully build SDLStreamingMediaManager's video encoder.
SDLRegisterAppInterfaceResponse* registerResponse = (SDLRegisterAppInterfaceResponse*)response;
self.displayCapabilities = registerResponse.displayCapabilities;
}

- (void)handleSyncPData:(SDLRPCMessage *)message {
Expand Down
33 changes: 27 additions & 6 deletions SmartDeviceLink/SDLStreamingMediaManager.h
Expand Up @@ -12,16 +12,19 @@
#import "SDLProtocolListener.h"

@class SDLAbstractProtocol;
@class SDLDisplayCapabilities;
@class SDLTouchManager;


NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, SDLStreamingVideoError) {
SDLStreamingVideoErrorHeadUnitNACK,
SDLSTreamingVideoErrorInvalidOperatingSystemVersion,
SDLStreamingVideoErrorConfigurationCompressionSessionCreationFailure,
SDLStreamingVideoErrorConfigurationAllocationFailure,
SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure
SDLStreamingVideoErrorHeadUnitNACK = 0,
SDLSTreamingVideoErrorInvalidOperatingSystemVersion __deprecated_enum_msg("Use SDLStreamingVideoErrorInvalidOperatingSystemVersion instead") = 1,
SDLStreamingVideoErrorInvalidOperatingSystemVersion = 1,
SDLStreamingVideoErrorConfigurationCompressionSessionCreationFailure = 2,
SDLStreamingVideoErrorConfigurationAllocationFailure = 3,
SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure = 4
};

typedef NS_ENUM(NSInteger, SDLStreamingAudioError) {
Expand All @@ -36,7 +39,9 @@ typedef void (^SDLStreamingStartBlock)(BOOL success, NSError *__nullable error);

@interface SDLStreamingMediaManager : NSObject <SDLProtocolListener>

- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol;
- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol __deprecated_msg(("Please use initWithProtocol:displayCapabilities: instead"));

- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol displayCapabilities:(SDLDisplayCapabilities*)displayCapabilities;

/**
* This method will attempt to start a streaming video session. It will set up iOS's video encoder, and call out to the head unit asking if it will start a video session.
Expand Down Expand Up @@ -90,6 +95,22 @@ typedef void (^SDLStreamingStartBlock)(BOOL success, NSError *__nullable error);
*/
@property (nonatomic, strong, readonly) SDLTouchManager* touchManager;

/**
* The settings used in a VTCompressionSessionRef encoder. These will be verified when the video stream is started. Acceptable properties for this are located in VTCompressionProperties. If set to nil, the defaultVideoEncoderSettings will be used.
*
* @warning Video streaming must not be connected to update the encoder properties. If it is running, issue a stopVideoSession before updating.
*/
@property (strong, nonatomic, null_resettable) NSDictionary* videoEncoderSettings;

/**
* Provides default video encoder settings used.
*/
@property (strong, nonatomic, readonly) NSDictionary* defaultVideoEncoderSettings;

/**
* This is the current screen size of a connected display. This will be the size the video encoder uses to encode the raw image data.
*/
@property (assign, nonatomic, readonly) CGSize screenSize;

@end

Expand Down
119 changes: 99 additions & 20 deletions SmartDeviceLink/SDLStreamingMediaManager.m
Expand Up @@ -11,9 +11,13 @@
@import UIKit;

#import "SDLAbstractProtocol.h"
#import "SDLDisplayCapabilities.h"
#import "SDLGlobals.h"
#import "SDLImageResolution.h"
#import "SDLScreenParams.h"
#import "SDLTouchManager.h"


NSString *const SDLErrorDomainStreamingMediaVideo = @"com.sdl.streamingmediamanager.video";
NSString *const SDLErrorDomainStreamingMediaAudio = @"com.sdl.streamingmediamanager.audio";

Expand Down Expand Up @@ -43,23 +47,57 @@ @implementation SDLStreamingMediaManager

#pragma mark - Class Lifecycle

- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol displayCapabilities:(SDLDisplayCapabilities*)displayCapabilities {
self = [self init];
if (!self) {
return nil;
}

_protocol = protocol;

SDLImageResolution* resolution = displayCapabilities.screenParams.resolution;
if (resolution != nil) {
_screenSize = CGSizeMake(resolution.resolutionWidth.floatValue,
resolution.resolutionHeight.floatValue);
} else {
NSLog(@"Could not retrieve screen size. Defaulting to 640 x 480.");
_screenSize = CGSizeMake(640,
480);
}

return self;

}

- (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol {
self = [super init];
self = [self init];
if (!self) {
return nil;
}

_compressionSession = NULL;
_protocol = protocol;

return self;
}

- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}

_compressionSession = NULL;

_currentFrameNumber = 0;
_videoSessionConnected = NO;
_audioSessionConnected = NO;
_protocol = protocol;


_videoStartBlock = nil;
_audioStartBlock = nil;

_touchManager = [[SDLTouchManager alloc] init];

_screenSize = CGSizeMake(640, 480);
_videoEncoderSettings = self.defaultVideoEncoderSettings;
_touchManager = [[SDLTouchManager alloc] init];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sdl_applicationDidEnterBackground:)
Expand All @@ -80,7 +118,7 @@ - (instancetype)initWithProtocol:(SDLAbstractProtocol *)protocol {
- (void)startVideoSessionWithStartBlock:(SDLStreamingStartBlock)startBlock {
if (SDL_SYSTEM_VERSION_LESS_THAN(@"8.0")) {
NSAssert(NO, @"SDL Video Sessions can only be run on iOS 8+ devices");
startBlock(NO, [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLSTreamingVideoErrorInvalidOperatingSystemVersion userInfo:nil]);
startBlock(NO, [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorInvalidOperatingSystemVersion userInfo:nil]);

return;
}
Expand Down Expand Up @@ -141,6 +179,31 @@ - (BOOL)sendAudioData:(NSData *)pcmAudioData {
return YES;
}

#pragma mark - Update video encoder

- (void)setVideoEncoderSettings:(NSDictionary * _Nullable)videoEncoderSettings {
if (self.videoSessionConnected) {
@throw [NSException exceptionWithName:SDLErrorDomainStreamingMediaVideo reason:@"Cannot update video encoder settings while video session is connected." userInfo:nil];
return;
}

if (videoEncoderSettings) {
_videoEncoderSettings = videoEncoderSettings;
} else {
_videoEncoderSettings = self.defaultVideoEncoderSettings;
}
}

- (NSDictionary*)defaultVideoEncoderSettings {
static NSDictionary* defaultVideoEncoderSettings = nil;
if (defaultVideoEncoderSettings == nil) {
defaultVideoEncoderSettings = @{
(__bridge NSString*)kVTCompressionPropertyKey_ProfileLevel : (__bridge NSString*)kVTProfileLevel_H264_Baseline_AutoLevel,
(__bridge NSString*)kVTCompressionPropertyKey_RealTime : @YES
};
}
return defaultVideoEncoderSettings;
}

#pragma mark - SDLProtocolListener Methods

Expand Down Expand Up @@ -238,8 +301,7 @@ - (BOOL)sdl_configureVideoEncoderWithError:(NSError *__autoreleasing *)error {
OSStatus status;

// Create a compression session
// TODO (Joel F.)[2015-08-18]: Dimensions should be from the Head Unit
status = VTCompressionSessionCreate(NULL, 640, 480, kCMVideoCodecType_H264, NULL, NULL, NULL, &sdl_videoEncoderOutputCallback, (__bridge void *)self, &_compressionSession);
status = VTCompressionSessionCreate(NULL, self.screenSize.width, self.screenSize.height, kCMVideoCodecType_H264, NULL, NULL, NULL, &sdl_videoEncoderOutputCallback, (__bridge void *)self, &_compressionSession);

if (status != noErr) {
// TODO: Log the error
Expand All @@ -250,24 +312,41 @@ - (BOOL)sdl_configureVideoEncoderWithError:(NSError *__autoreleasing *)error {
return NO;
}

// Set the profile level of the video stream
status = VTSessionSetProperty(self.compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Baseline_AutoLevel);
// Validate that the video encoder properties are valid.
CFDictionaryRef supportedProperties;
status = VTSessionCopySupportedPropertyDictionary(self.compressionSession, &supportedProperties);
if (status != noErr) {
if (*error != nil) {
*error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus" : @(status) }];
}

return NO;
}

// Set the session to compress in real time
status = VTSessionSetProperty(self.compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);
if (status != noErr) {
if (*error != nil) {
*error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus" : @(status) }];

for (NSString* key in self.videoEncoderSettings.allKeys) {
if (CFDictionaryContainsKey(supportedProperties, (__bridge CFStringRef)key) == false) {
if (*error != nil) {
NSString* description = [NSString stringWithFormat:@"\"%@\" is not a supported key.", key];
*error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{NSLocalizedDescriptionKey : description}];
}
CFRelease(supportedProperties);
return NO;
}
}
CFRelease(supportedProperties);

// Populate the video encoder settings from provided dictionary.
for (NSString* key in self.videoEncoderSettings.allKeys) {
id value = self.videoEncoderSettings[key];

status = VTSessionSetProperty(self.compressionSession, (__bridge CFStringRef)key, (__bridge CFTypeRef)value);
if (status != noErr) {
if (*error != nil) {
*error = [NSError errorWithDomain:SDLErrorDomainStreamingMediaVideo code:SDLStreamingVideoErrorConfigurationCompressionSessionSetPropertyFailure userInfo:@{ @"OSStatus" : @(status) }];
}

return NO;
}

return NO;
}

return YES;
Expand Down

0 comments on commit ca91918

Please sign in to comment.