summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2017-09-06 13:24:27 -0400
committerJoel Fischer <joeljfischer@gmail.com>2017-09-06 13:24:27 -0400
commit35fb42227aaddce894016e0315fd4c0a6f9df1e7 (patch)
tree9fe42532cd6751df44b09ba8b0406ab9412ca8af
parent1c30d20f2fb31bf7b5d229437fcc0eb6f6b378eb (diff)
parent39b01057a545aa95e8048c941df7c5a8d54744ff (diff)
downloadsdl_ios-35fb42227aaddce894016e0315fd4c0a6f9df1e7.tar.gz
Merge branch 'release/5.0.0' into bugfix/issue_636_proxylistener_deprecatedbugfix/issue_636_proxylistener_deprecated
# Conflicts: # SmartDeviceLink-iOS.xcodeproj/project.pbxproj # SmartDeviceLinkTests/ProtocolSpecs/SDLFunctionIDSpec.m
-rw-r--r--SmartDeviceLink-iOS.podspec3
-rw-r--r--SmartDeviceLink-iOS.xcodeproj/project.pbxproj76
-rw-r--r--SmartDeviceLink.podspec3
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadAudioStartServiceAck.m2
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadEndService.m2
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadNak.m2
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadRPCStartService.m2
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadRPCStartServiceAck.m2
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadVideoStartService.m2
-rw-r--r--SmartDeviceLink/SDLControlFramePayloadVideoStartServiceAck.m2
-rw-r--r--SmartDeviceLink/SDLFunctionID.m1
-rw-r--r--SmartDeviceLink/SDLH264ByteStreamPacketizer.h17
-rw-r--r--SmartDeviceLink/SDLH264ByteStreamPacketizer.m51
-rw-r--r--SmartDeviceLink/SDLH264Packetizer.h33
-rw-r--r--SmartDeviceLink/SDLHapticRect.h34
-rw-r--r--SmartDeviceLink/SDLHapticRect.m48
-rw-r--r--SmartDeviceLink/SDLMetadataType.h5
-rw-r--r--SmartDeviceLink/SDLMetadataType.m1
-rw-r--r--SmartDeviceLink/SDLNames.h6
-rw-r--r--SmartDeviceLink/SDLNames.m6
-rw-r--r--SmartDeviceLink/SDLNotificationConstants.h1
-rw-r--r--SmartDeviceLink/SDLNotificationConstants.m2
-rw-r--r--SmartDeviceLink/SDLNotificationDispatcher.m4
-rw-r--r--SmartDeviceLink/SDLProxyListener.h2
-rw-r--r--SmartDeviceLink/SDLRTPH264Packetizer.h43
-rw-r--r--SmartDeviceLink/SDLRTPH264Packetizer.m246
-rw-r--r--SmartDeviceLink/SDLRectangle.h56
-rw-r--r--SmartDeviceLink/SDLRectangle.m63
-rw-r--r--SmartDeviceLink/SDLSendHapticData.h37
-rw-r--r--SmartDeviceLink/SDLSendHapticData.m44
-rw-r--r--SmartDeviceLink/SDLSendHapticDataResponse.h19
-rw-r--r--SmartDeviceLink/SDLSendHapticDataResponse.m25
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.h10
-rw-r--r--SmartDeviceLink/SDLStreamingMediaLifecycleManager.m33
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.h10
-rw-r--r--SmartDeviceLink/SDLStreamingMediaManager.m4
-rw-r--r--SmartDeviceLink/SDLVideoEncoder.h2
-rw-r--r--SmartDeviceLink/SDLVideoEncoder.m58
-rw-r--r--SmartDeviceLink/SDLVideoStreamingCapability.h6
-rw-r--r--SmartDeviceLink/SDLVideoStreamingCapability.m11
-rw-r--r--SmartDeviceLink/SmartDeviceLink.h4
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLH264ByteStreamPacketizerSpec.m89
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLNotificationDispatcherSpec.m1
-rw-r--r--SmartDeviceLinkTests/DevAPISpecs/SDLRTPH264PacketizerSpec.m401
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadNakSpec.m14
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadVideoStartServiceSpec.m13
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFrameVideoStartServiceAckSpec.m13
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadAudioStartServiceAckSpec.m14
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadEndServiceSpec.m14
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m13
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceSpec.m14
-rw-r--r--SmartDeviceLinkTests/ProtocolSpecs/SDLFunctionIDSpec.m4
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMetadataTypeSpec.m1
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSendHapticDataSpec.m62
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLSendHapticDataResponseSpec.m19
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLHapticRectSpec.m69
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRectangleSpec.m58
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLSystemCapabilitySpec.m4
-rw-r--r--SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVideoStreamingCapabilitySpec.m11
-rw-r--r--SmartDeviceLink_Example/Classes/ProxyManager.m7
60 files changed, 1758 insertions, 41 deletions
diff --git a/SmartDeviceLink-iOS.podspec b/SmartDeviceLink-iOS.podspec
index d097938b9..308f5987b 100644
--- a/SmartDeviceLink-iOS.podspec
+++ b/SmartDeviceLink-iOS.podspec
@@ -104,6 +104,7 @@ ss.public_header_files = [
'SmartDeviceLink/SDLGetWaypointsResponse.h',
'SmartDeviceLink/SDLGlobalProperty.h',
'SmartDeviceLink/SDLGPSData.h',
+'SmartDeviceLink/SDLHapticRect.h',
'SmartDeviceLink/SDLHeadLampStatus.h',
'SmartDeviceLink/SDLHMICapabilities.h',
'SmartDeviceLink/SDLHMILevel.h',
@@ -222,6 +223,8 @@ ss.public_header_files = [
'SmartDeviceLink/SDLScrollableMessage.h',
'SmartDeviceLink/SDLScrollableMessageResponse.h',
'SmartDeviceLink/SDLSecurityType.h',
+'SmartDeviceLink/SDLSendHapticData.h',
+'SmartDeviceLink/SDLSendHapticDataResponse.h',
'SmartDeviceLink/SDLSendLocation.h',
'SmartDeviceLink/SDLSendLocationResponse.h',
'SmartDeviceLink/SDLSetAppIcon.h',
diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
index 16b44eda5..a88890f31 100644
--- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
+++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj
@@ -875,6 +875,9 @@
5DA49CE61F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DA49CE41F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.m */; };
5DA8A0E91E955F710039C50D /* SDLStreamingMediaManagerConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8966F31E56977C00413EAB /* SDLStreamingMediaManagerConstants.m */; };
5DA8A0EA1E955FE00039C50D /* SDLLogModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DBF06301E64A9C600A5CF03 /* SDLLogModel.m */; };
+ 5DADA7751F4DFED60084D17D /* SDLRectangle.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DADA7731F4DFED60084D17D /* SDLRectangle.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 5DADA7761F4DFED60084D17D /* SDLRectangle.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DADA7741F4DFED60084D17D /* SDLRectangle.m */; };
+ 5DADA7781F4E059E0084D17D /* SDLRectangleSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DADA7771F4E059E0084D17D /* SDLRectangleSpec.m */; };
5DAE06731BDEC6C000F9B498 /* SDLFileSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAE06721BDEC6C000F9B498 /* SDLFileSpec.m */; };
5DAE06751BDEC6D600F9B498 /* SDLArtworkSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DAE06741BDEC6D600F9B498 /* SDLArtworkSpec.m */; };
5DB1BCD31D243A8E002FFC37 /* SDLDeleteFileOperationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DB1BCD01D243A8E002FFC37 /* SDLDeleteFileOperationSpec.m */; };
@@ -939,6 +942,15 @@
5DE5ABB71B0E38C90067BB02 /* SDLSystemRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D61FBD21A84238B00846EE7 /* SDLSystemRequest.h */; };
5DE5ABB81B0E38C90067BB02 /* SDLSystemRequestResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D61FBD41A84238B00846EE7 /* SDLSystemRequestResponse.h */; };
5DFFB9151BD7C89700DB3F04 /* SDLConnectionManagerType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */; };
+ 8877F5EB1F34A3BE00DC128A /* SDLSendHapticDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */; };
+ 8877F5EE1F34A72200DC128A /* SDLSendHapticDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 8877F5EC1F34A72200DC128A /* SDLSendHapticDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 8877F5EF1F34A72200DC128A /* SDLSendHapticDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5ED1F34A72200DC128A /* SDLSendHapticDataResponse.m */; };
+ 8877F5F11F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */; };
+ 88EED8381F33AE1700E6C42E /* SDLHapticRect.h in Headers */ = {isa = PBXBuildFile; fileRef = 88EED8361F33AE1700E6C42E /* SDLHapticRect.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 88EED8391F33AE1700E6C42E /* SDLHapticRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 88EED8371F33AE1700E6C42E /* SDLHapticRect.m */; };
+ 88EED83B1F33BECB00E6C42E /* SDLHapticRectSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 88EED83A1F33BECB00E6C42E /* SDLHapticRectSpec.m */; };
+ 88EED83E1F33C5A400E6C42E /* SDLSendHapticData.h in Headers */ = {isa = PBXBuildFile; fileRef = 88EED83C1F33C5A400E6C42E /* SDLSendHapticData.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 88EED83F1F33C5A400E6C42E /* SDLSendHapticData.m in Sources */ = {isa = PBXBuildFile; fileRef = 88EED83D1F33C5A400E6C42E /* SDLSendHapticData.m */; };
8B7B319A1F2F7B5700BDC38D /* SDLVideoStreamingCodec.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B7B31981F2F7B5700BDC38D /* SDLVideoStreamingCodec.h */; settings = {ATTRIBUTES = (Public, ); }; };
8B7B319B1F2F7B5700BDC38D /* SDLVideoStreamingCodec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B7B31991F2F7B5700BDC38D /* SDLVideoStreamingCodec.m */; };
8B7B319E1F2F7CF700BDC38D /* SDLVideoStreamingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B7B319C1F2F7CF700BDC38D /* SDLVideoStreamingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1040,6 +1052,13 @@
E9C32B9D1AB20C5900F283AF /* EAAccessory+SDLProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = E9C32B991AB20C5900F283AF /* EAAccessory+SDLProtocols.m */; };
E9C32B9E1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = E9C32B9A1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.h */; };
E9C32B9F1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = E9C32B9B1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.m */; };
+ EED5C9FE1F4D18D100F04000 /* SDLH264Packetizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EED5C9FD1F4D18D100F04000 /* SDLH264Packetizer.h */; };
+ EED5CA001F4D18DC00F04000 /* SDLH264ByteStreamPacketizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EED5C9FF1F4D18DC00F04000 /* SDLH264ByteStreamPacketizer.h */; };
+ EED5CA021F4D18EC00F04000 /* SDLH264ByteStreamPacketizer.m in Sources */ = {isa = PBXBuildFile; fileRef = EED5CA011F4D18EC00F04000 /* SDLH264ByteStreamPacketizer.m */; };
+ EED5CA041F4D1D5E00F04000 /* SDLH264ByteStreamPacketizerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = EED5CA031F4D1D5E00F04000 /* SDLH264ByteStreamPacketizerSpec.m */; };
+ EED5CA061F4D1E2300F04000 /* SDLRTPH264Packetizer.h in Headers */ = {isa = PBXBuildFile; fileRef = EED5CA051F4D1E2300F04000 /* SDLRTPH264Packetizer.h */; };
+ EED5CA081F4D1E2E00F04000 /* SDLRTPH264Packetizer.m in Sources */ = {isa = PBXBuildFile; fileRef = EED5CA071F4D1E2E00F04000 /* SDLRTPH264Packetizer.m */; };
+ EED5CA0A1F4D206800F04000 /* SDLRTPH264PacketizerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = EED5CA091F4D206800F04000 /* SDLRTPH264PacketizerSpec.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -1994,6 +2013,9 @@
5DA3F36F1BC4489A0026F2D0 /* SDLManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLManager.m; sourceTree = "<group>"; };
5DA49CE31F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLControlFramePayloadRPCStartService.h; sourceTree = "<group>"; };
5DA49CE41F1EA83300E65FC5 /* SDLControlFramePayloadRPCStartService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLControlFramePayloadRPCStartService.m; sourceTree = "<group>"; };
+ 5DADA7731F4DFED60084D17D /* SDLRectangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLRectangle.h; sourceTree = "<group>"; };
+ 5DADA7741F4DFED60084D17D /* SDLRectangle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLRectangle.m; sourceTree = "<group>"; };
+ 5DADA7771F4E059E0084D17D /* SDLRectangleSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLRectangleSpec.m; sourceTree = "<group>"; };
5DAE06721BDEC6C000F9B498 /* SDLFileSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLFileSpec.m; path = DevAPISpecs/SDLFileSpec.m; sourceTree = "<group>"; };
5DAE06741BDEC6D600F9B498 /* SDLArtworkSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLArtworkSpec.m; path = DevAPISpecs/SDLArtworkSpec.m; sourceTree = "<group>"; };
5DB1BCD01D243A8E002FFC37 /* SDLDeleteFileOperationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLDeleteFileOperationSpec.m; path = DevAPISpecs/SDLDeleteFileOperationSpec.m; sourceTree = "<group>"; };
@@ -2062,6 +2084,15 @@
5DEE55BF1B8509CB004F0D0F /* SDLURLRequestTaskSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLURLRequestTaskSpec.m; path = "UtilitiesSpecs/HTTP Connection/SDLURLRequestTaskSpec.m"; sourceTree = "<group>"; };
5DF2BB9C1B94E38A00CE5994 /* SDLURLSessionSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLURLSessionSpec.m; path = "UtilitiesSpecs/HTTP Connection/SDLURLSessionSpec.m"; sourceTree = "<group>"; };
5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLConnectionManagerType.h; sourceTree = "<group>"; };
+ 8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataSpec.m; sourceTree = "<group>"; };
+ 8877F5EC1F34A72200DC128A /* SDLSendHapticDataResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSendHapticDataResponse.h; sourceTree = "<group>"; };
+ 8877F5ED1F34A72200DC128A /* SDLSendHapticDataResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataResponse.m; sourceTree = "<group>"; };
+ 8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticDataResponseSpec.m; sourceTree = "<group>"; };
+ 88EED8361F33AE1700E6C42E /* SDLHapticRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLHapticRect.h; sourceTree = "<group>"; };
+ 88EED8371F33AE1700E6C42E /* SDLHapticRect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHapticRect.m; sourceTree = "<group>"; };
+ 88EED83A1F33BECB00E6C42E /* SDLHapticRectSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHapticRectSpec.m; sourceTree = "<group>"; };
+ 88EED83C1F33C5A400E6C42E /* SDLSendHapticData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLSendHapticData.h; sourceTree = "<group>"; };
+ 88EED83D1F33C5A400E6C42E /* SDLSendHapticData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLSendHapticData.m; sourceTree = "<group>"; };
8B7B31981F2F7B5700BDC38D /* SDLVideoStreamingCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLVideoStreamingCodec.h; sourceTree = "<group>"; };
8B7B31991F2F7B5700BDC38D /* SDLVideoStreamingCodec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLVideoStreamingCodec.m; sourceTree = "<group>"; };
8B7B319C1F2F7CF700BDC38D /* SDLVideoStreamingProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLVideoStreamingProtocol.h; sourceTree = "<group>"; };
@@ -2165,6 +2196,13 @@
E9C32B991AB20C5900F283AF /* EAAccessory+SDLProtocols.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EAAccessory+SDLProtocols.m"; sourceTree = "<group>"; };
E9C32B9A1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EAAccessoryManager+SDLProtocols.h"; sourceTree = "<group>"; };
E9C32B9B1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EAAccessoryManager+SDLProtocols.m"; sourceTree = "<group>"; };
+ EED5C9FD1F4D18D100F04000 /* SDLH264Packetizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLH264Packetizer.h; sourceTree = "<group>"; };
+ EED5C9FF1F4D18DC00F04000 /* SDLH264ByteStreamPacketizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLH264ByteStreamPacketizer.h; sourceTree = "<group>"; };
+ EED5CA011F4D18EC00F04000 /* SDLH264ByteStreamPacketizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLH264ByteStreamPacketizer.m; sourceTree = "<group>"; };
+ EED5CA031F4D1D5E00F04000 /* SDLH264ByteStreamPacketizerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLH264ByteStreamPacketizerSpec.m; path = DevAPISpecs/SDLH264ByteStreamPacketizerSpec.m; sourceTree = "<group>"; };
+ EED5CA051F4D1E2300F04000 /* SDLRTPH264Packetizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLRTPH264Packetizer.h; sourceTree = "<group>"; };
+ EED5CA071F4D1E2E00F04000 /* SDLRTPH264Packetizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLRTPH264Packetizer.m; sourceTree = "<group>"; };
+ EED5CA091F4D206800F04000 /* SDLRTPH264PacketizerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLRTPH264PacketizerSpec.m; path = DevAPISpecs/SDLRTPH264PacketizerSpec.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -2382,6 +2420,7 @@
162E82631A9BDE8A00906325 /* SDLUnsubscribeVehicleDataSpec.m */,
DA9F7EA51DCC05F500ACAE48 /* SDLUnsubscribeWaypointsSpec.m */,
162E82641A9BDE8A00906325 /* SDLUpdateTurnListSpec.m */,
+ 8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */,
);
path = RequestSpecs;
sourceTree = "<group>";
@@ -2435,6 +2474,7 @@
162E828C1A9BDE8A00906325 /* SDLUnsubscribeVehicleDataResponseSpec.m */,
DA9F7EAB1DCC062400ACAE48 /* SDLUnsubscribeWaypointsResponseSpec.m */,
162E828D1A9BDE8A00906325 /* SDLUpdateTurnListResponseSpec.m */,
+ 8877F5F01F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m */,
);
path = ResponseSpecs;
sourceTree = "<group>";
@@ -2458,6 +2498,7 @@
162E829A1A9BDE8A00906325 /* SDLECallInfoSpec.m */,
162E829B1A9BDE8A00906325 /* SDLEmergencyEventSpec.m */,
162E829C1A9BDE8A00906325 /* SDLGPSDataSpec.m */,
+ 88EED83A1F33BECB00E6C42E /* SDLHapticRectSpec.m */,
162E829D1A9BDE8A00906325 /* SDLHeadLampStatusSpec.m */,
5DE372A31ACB336600849FAA /* SDLHMICapabilitiesSpec.m */,
162E829E1A9BDE8A00906325 /* SDLHMIPermissionsSpec.m */,
@@ -2475,6 +2516,7 @@
162E82A51A9BDE8A00906325 /* SDLPermissionItemSpec.m */,
5D0A9F941F15585B00CC80DD /* SDLPhoneCapabilitySpec.m */,
162E82A61A9BDE8A00906325 /* SDLPresetBankCapabilitiesSpec.m */,
+ 5DADA7771F4E059E0084D17D /* SDLRectangleSpec.m */,
162E82A71A9BDE8A00906325 /* SDLScreenParamsSpec.m */,
162E82A81A9BDE8A00906325 /* SDLSingleTireStatusSpec.m */,
162E82A91A9BDE8A00906325 /* SDLSoftButtonCapabilitiesSpec.m */,
@@ -2915,6 +2957,8 @@
5D61FB771A84238B00846EE7 /* SDLResetGlobalProperties.m */,
5D61FB8E1A84238B00846EE7 /* SDLScrollableMessage.h */,
5D61FB8F1A84238B00846EE7 /* SDLScrollableMessage.m */,
+ 88EED83C1F33C5A400E6C42E /* SDLSendHapticData.h */,
+ 88EED83D1F33C5A400E6C42E /* SDLSendHapticData.m */,
5DCF76F31ACDBAD300BB647B /* SDLSendLocation.h */,
5DCF76F41ACDBAD300BB647B /* SDLSendLocation.m */,
5D61FB921A84238B00846EE7 /* SDLSetAppIcon.h */,
@@ -3014,6 +3058,8 @@
5D61FB791A84238B00846EE7 /* SDLResetGlobalPropertiesResponse.m */,
5D61FB901A84238B00846EE7 /* SDLScrollableMessageResponse.h */,
5D61FB911A84238B00846EE7 /* SDLScrollableMessageResponse.m */,
+ 8877F5EC1F34A72200DC128A /* SDLSendHapticDataResponse.h */,
+ 8877F5ED1F34A72200DC128A /* SDLSendHapticDataResponse.m */,
5DCF76F71ACDD7CD00BB647B /* SDLSendLocationResponse.h */,
5DCF76F81ACDD7CD00BB647B /* SDLSendLocationResponse.m */,
5D61FB941A84238B00846EE7 /* SDLSetAppIconResponse.h */,
@@ -3091,6 +3137,8 @@
5D61FAAE1A84238A00846EE7 /* SDLEmergencyEvent.m */,
5D61FACE1A84238A00846EE7 /* SDLGPSData.h */,
5D61FACF1A84238A00846EE7 /* SDLGPSData.m */,
+ 88EED8361F33AE1700E6C42E /* SDLHapticRect.h */,
+ 88EED8371F33AE1700E6C42E /* SDLHapticRect.m */,
5D61FAD01A84238A00846EE7 /* SDLHeadLampStatus.h */,
5D61FAD11A84238A00846EE7 /* SDLHeadLampStatus.m */,
5DE3729F1ACB2ED300849FAA /* SDLHMICapabilities.h */,
@@ -3127,6 +3175,8 @@
5D00AC7A1F15287E004000D9 /* SDLPhoneCapability.m */,
5D61FB4E1A84238B00846EE7 /* SDLPresetBankCapabilities.h */,
5D61FB4F1A84238B00846EE7 /* SDLPresetBankCapabilities.m */,
+ 5DADA7731F4DFED60084D17D /* SDLRectangle.h */,
+ 5DADA7741F4DFED60084D17D /* SDLRectangle.m */,
5D61FB8C1A84238B00846EE7 /* SDLScreenParams.h */,
5D61FB8D1A84238B00846EE7 /* SDLScreenParams.m */,
5D61FBAA1A84238B00846EE7 /* SDLSingleTireStatus.h */,
@@ -4150,6 +4200,8 @@
isa = PBXGroup;
children = (
DA8966EE1E5693E300413EAB /* SDLStreamingMediaLifecycleManagerSpec.m */,
+ EED5CA031F4D1D5E00F04000 /* SDLH264ByteStreamPacketizerSpec.m */,
+ EED5CA091F4D206800F04000 /* SDLRTPH264PacketizerSpec.m */,
);
name = Streaming;
sourceTree = "<group>";
@@ -4171,6 +4223,11 @@
DAA41D531DF66B2000BC7337 /* SDLVideoEncoder.h */,
DAA41D541DF66B2000BC7337 /* SDLVideoEncoder.m */,
5DA23FFC1F312DBA009C0313 /* SDLVideoEncoderDelegate.h */,
+ EED5C9FD1F4D18D100F04000 /* SDLH264Packetizer.h */,
+ EED5C9FF1F4D18DC00F04000 /* SDLH264ByteStreamPacketizer.h */,
+ EED5CA011F4D18EC00F04000 /* SDLH264ByteStreamPacketizer.m */,
+ EED5CA051F4D1E2300F04000 /* SDLRTPH264Packetizer.h */,
+ EED5CA071F4D1E2E00F04000 /* SDLRTPH264Packetizer.m */,
);
name = "Video Encoding";
sourceTree = "<group>";
@@ -4307,6 +4364,7 @@
5D61FD811A84238C00846EE7 /* SDLSetAppIconResponse.h in Headers */,
5D61FC551A84238C00846EE7 /* SDLButtonName.h in Headers */,
5D616B531D59044400553F6B /* SDLErrorConstants.h in Headers */,
+ 5DADA7751F4DFED60084D17D /* SDLRectangle.h in Headers */,
5D61FD9F1A84238C00846EE7 /* SDLSoftButton.h in Headers */,
5DD67CBC1E661C84009CD394 /* SDLLogTargetOSLog.h in Headers */,
5D61FD551A84238C00846EE7 /* SDLPutFile.h in Headers */,
@@ -4354,7 +4412,9 @@
5D61FC761A84238C00846EE7 /* SDLDeleteFile.h in Headers */,
5D61FD211A84238C00846EE7 /* SDLOnVehicleData.h in Headers */,
DA9F7E731DCC004C00ACAE48 /* SDLGetWayPointsResponse.h in Headers */,
+ 88EED8381F33AE1700E6C42E /* SDLHapticRect.h in Headers */,
5DD67CC31E68AE82009CD394 /* SDLLogFileModuleMap.h in Headers */,
+ EED5C9FE1F4D18D100F04000 /* SDLH264Packetizer.h in Headers */,
5D61FD7D1A84238C00846EE7 /* SDLScrollableMessageResponse.h in Headers */,
5D61FD431A84238C00846EE7 /* SDLProtocol.h in Headers */,
5D8B17531AC9E11B006A6E1C /* SDLDialNumberResponse.h in Headers */,
@@ -4441,6 +4501,7 @@
5D4D67B01D2FE2F900468B4A /* SDLResponseDispatcher.h in Headers */,
5D61FCF21A84238C00846EE7 /* SDLLockScreenStatus.h in Headers */,
5D00AC771F15283E004000D9 /* SDLNavigationCapability.h in Headers */,
+ 88EED83E1F33C5A400E6C42E /* SDLSendHapticData.h in Headers */,
5D61FCD31A84238C00846EE7 /* SDLImageResolution.h in Headers */,
8B7B319E1F2F7CF700BDC38D /* SDLVideoStreamingProtocol.h in Headers */,
5D61FD541A84238C00846EE7 /* SDLProxyListener.h in Headers */,
@@ -4466,6 +4527,7 @@
5D61FC721A84238C00846EE7 /* SDLDeleteCommand.h in Headers */,
5D61FC821A84238C00846EE7 /* SDLDeviceInfo.h in Headers */,
5D61FCA91A84238C00846EE7 /* SDLFileType.h in Headers */,
+ 8877F5EE1F34A72200DC128A /* SDLSendHapticDataResponse.h in Headers */,
DA8966F21E56973700413EAB /* SDLStreamingMediaManagerConstants.h in Headers */,
5DD67CB81E661C4A009CD394 /* SDLLogTargetFile.h in Headers */,
5D61FD591A84238C00846EE7 /* SDLReadDID.h in Headers */,
@@ -4491,6 +4553,7 @@
5D61FCE41A84238C00846EE7 /* SDLKeyboardProperties.h in Headers */,
5D61FDED1A84238C00846EE7 /* SDLUnsubscribeVehicleDataResponse.h in Headers */,
5D4631041F2120A30092EFDC /* SDLControlFramePayloadType.h in Headers */,
+ EED5CA061F4D1E2300F04000 /* SDLRTPH264Packetizer.h in Headers */,
5D61FCCF1A84238C00846EE7 /* SDLImageField.h in Headers */,
5D535DC51B72473800CF7760 /* SDLGlobals.h in Headers */,
5D79A03B1CE36F030035797B /* SDLUploadFileOperation.h in Headers */,
@@ -4529,6 +4592,7 @@
5D61FC5B1A84238C00846EE7 /* SDLChangeRegistration.h in Headers */,
5D61FD5B1A84238C00846EE7 /* SDLReadDIDResponse.h in Headers */,
5D61FDEF1A84238C00846EE7 /* SDLUpdateMode.h in Headers */,
+ EED5CA001F4D18DC00F04000 /* SDLH264ByteStreamPacketizer.h in Headers */,
DA8966EB1E56939F00413EAB /* SDLStreamingMediaLifecycleManager.h in Headers */,
5D61FDDB1A84238C00846EE7 /* SDLTriggerSource.h in Headers */,
5D61FD8F1A84238C00846EE7 /* SDLShow.h in Headers */,
@@ -5030,6 +5094,8 @@
5D1665C91CF8CA3D00CC4CA1 /* SDLPermissionFilter.m in Sources */,
5D61FDBA1A84238C00846EE7 /* SDLSyncPDataResponse.m in Sources */,
5D61FDDC1A84238C00846EE7 /* SDLTriggerSource.m in Sources */,
+ 5DADA7761F4DFED60084D17D /* SDLRectangle.m in Sources */,
+ 88EED83F1F33C5A400E6C42E /* SDLSendHapticData.m in Sources */,
5D16545B1D3E7A1600554D93 /* SDLLifecycleManager.m in Sources */,
E9C32B971AB20BA200F283AF /* SDLTimer.m in Sources */,
5D61FCB61A84238C00846EE7 /* SDLGetVehicleData.m in Sources */,
@@ -5038,6 +5104,7 @@
5D61FCA41A84238C00846EE7 /* SDLEndAudioPassThru.m in Sources */,
5D8B17541AC9E11B006A6E1C /* SDLDialNumberResponse.m in Sources */,
DA6223BE1E7B088200878689 /* CVPixelBufferRef+SDLUtil.m in Sources */,
+ EED5CA021F4D18EC00F04000 /* SDLH264ByteStreamPacketizer.m in Sources */,
5D61FC851A84238C00846EE7 /* SDLDeviceLevelStatus.m in Sources */,
5D9FDA981F2A7D3F00A495C8 /* emhashmap.c in Sources */,
5D61FD1E1A84238C00846EE7 /* SDLOnTBTClientState.m in Sources */,
@@ -5081,6 +5148,7 @@
5DA3F3551BC448060026F2D0 /* NSMapTable+Subscripting.m in Sources */,
5D61FCD61A84238C00846EE7 /* SDLImageType.m in Sources */,
5D4D67AD1D2ED37A00468B4A /* SDLNotificationDispatcher.m in Sources */,
+ 88EED8391F33AE1700E6C42E /* SDLHapticRect.m in Sources */,
DA9F7E9C1DCC052C00ACAE48 /* SDLLocationDetails.m in Sources */,
5D61FD7A1A84238C00846EE7 /* SDLScreenParams.m in Sources */,
5D61FC831A84238C00846EE7 /* SDLDeviceInfo.m in Sources */,
@@ -5089,6 +5157,7 @@
97E26DED1E807AD70074A3C7 /* SDLMutableDataQueue.m in Sources */,
5D61FD641A84238C00846EE7 /* SDLResetGlobalProperties.m in Sources */,
5D60088B1BE3ED540094A505 /* SDLStateMachine.m in Sources */,
+ 8877F5EF1F34A72200DC128A /* SDLSendHapticDataResponse.m in Sources */,
5D61FD181A84238C00846EE7 /* SDLOnPermissionsChange.m in Sources */,
5D61FD3E1A84238C00846EE7 /* SDLPrimaryAudioSource.m in Sources */,
5D61FC2A1A84238C00846EE7 /* SDLAbstractProtocol.m in Sources */,
@@ -5120,6 +5189,7 @@
5D61FC2C1A84238C00846EE7 /* SDLAbstractTransport.m in Sources */,
5D61FD8E1A84238C00846EE7 /* SDLSetMediaClockTimerResponse.m in Sources */,
5D61FD721A84238C00846EE7 /* SDLRPCRequest.m in Sources */,
+ EED5CA081F4D1E2E00F04000 /* SDLRTPH264Packetizer.m in Sources */,
5D61FDF01A84238C00846EE7 /* SDLUpdateMode.m in Sources */,
5D61FC931A84238C00846EE7 /* SDLDisplayType.m in Sources */,
5D61FCE31A84238C00846EE7 /* SDLKeyboardLayout.m in Sources */,
@@ -5167,6 +5237,7 @@
162E837D1A9BDE8B00906325 /* SDLEmergencyEventSpec.m in Sources */,
162E82D31A9BDE8A00906325 /* SDLCarModeStatusSpec.m in Sources */,
8B7B31A91F2FB8BC00BDC38D /* SDLVideoStreamingProtocolSpec.m in Sources */,
+ 88EED83B1F33BECB00E6C42E /* SDLHapticRectSpec.m in Sources */,
162E82EA1A9BDE8B00906325 /* SDLLanguageSpec.m in Sources */,
5D76E3291D3D0A8800647CFA /* SDLFakeViewControllerPresenter.m in Sources */,
162E83331A9BDE8B00906325 /* SDLPerformInteractionSpec.m in Sources */,
@@ -5210,6 +5281,7 @@
162E83281A9BDE8B00906325 /* SDLDeleteCommandSpec.m in Sources */,
162E83531A9BDE8B00906325 /* SDLDiagnosticMessageResponseSpec.m in Sources */,
162E83671A9BDE8B00906325 /* SDLSliderResponseSpec.m in Sources */,
+ 8877F5F11F34AA2D00DC128A /* SDLSendHapticDataResponseSpec.m in Sources */,
162E836C1A9BDE8B00906325 /* SDLSystemRequestResponseSpec.m in Sources */,
162E833C1A9BDE8B00906325 /* SDLSetMediaClockTimerSpec.m in Sources */,
162E83061A9BDE8B00906325 /* SDLVehicleDataEventStatusSpec.m in Sources */,
@@ -5364,7 +5436,9 @@
162E838C1A9BDE8B00906325 /* SDLSoftButtonSpec.m in Sources */,
5DA23FF81F2FAF2D009C0313 /* SDLControlFramePayloadRPCStartServiceAckSpec.m in Sources */,
162E83191A9BDE8B00906325 /* SDLOnLanguageChangeSpec.m in Sources */,
+ 5DADA7781F4E059E0084D17D /* SDLRectangleSpec.m in Sources */,
5DB1BCDD1D243DC3002FFC37 /* SDLLifecycleConfigurationSpec.m in Sources */,
+ EED5CA0A1F4D206800F04000 /* SDLRTPH264PacketizerSpec.m in Sources */,
162E83611A9BDE8B00906325 /* SDLSetAppIconResponseSpec.m in Sources */,
162E83471A9BDE8B00906325 /* SDLUnsubscribeVehicleDataSpec.m in Sources */,
162E839A1A9BDE8B00906325 /* SDLRPCMessageSpec.m in Sources */,
@@ -5405,6 +5479,7 @@
162E83321A9BDE8B00906325 /* SDLPerformAudioPassThruSpec.m in Sources */,
162E830B1A9BDE8B00906325 /* SDLVrCapabilitiesSpec.m in Sources */,
162E83081A9BDE8B00906325 /* SDLVehicleDataResultCodeSpec.m in Sources */,
+ 8877F5EB1F34A3BE00DC128A /* SDLSendHapticDataSpec.m in Sources */,
162E83621A9BDE8B00906325 /* SDLSetDisplayLayoutResponseSpec.m in Sources */,
162E832E1A9BDE8B00906325 /* SDLEndAudioPassThruSpec.m in Sources */,
1680B1191A9CD7AD00DBD79E /* SDLV2ProtocolMessageSpec.m in Sources */,
@@ -5437,6 +5512,7 @@
5DB1BCD31D243A8E002FFC37 /* SDLDeleteFileOperationSpec.m in Sources */,
5D0A9F971F1559EC00CC80DD /* SDLSystemCapabilitySpec.m in Sources */,
162E82F41A9BDE8B00906325 /* SDLPrimaryAudioSource.m in Sources */,
+ EED5CA041F4D1D5E00F04000 /* SDLH264ByteStreamPacketizerSpec.m in Sources */,
5DBAE0AB1D3588AC00CE00BF /* SDLNotificationDispatcherSpec.m in Sources */,
162E83461A9BDE8B00906325 /* SDLUnsubscribeButtonSpec.m in Sources */,
162E82EB1A9BDE8B00906325 /* SDLLayoutModeSpec.m in Sources */,
diff --git a/SmartDeviceLink.podspec b/SmartDeviceLink.podspec
index dcbcea7f3..3aca1eaeb 100644
--- a/SmartDeviceLink.podspec
+++ b/SmartDeviceLink.podspec
@@ -104,6 +104,7 @@ ss.public_header_files = [
'SmartDeviceLink/SDLGetWaypointsResponse.h',
'SmartDeviceLink/SDLGlobalProperty.h',
'SmartDeviceLink/SDLGPSData.h',
+'SmartDeviceLink/SDLHapticRect.h',
'SmartDeviceLink/SDLHeadLampStatus.h',
'SmartDeviceLink/SDLHMICapabilities.h',
'SmartDeviceLink/SDLHMILevel.h',
@@ -222,6 +223,8 @@ ss.public_header_files = [
'SmartDeviceLink/SDLScrollableMessage.h',
'SmartDeviceLink/SDLScrollableMessageResponse.h',
'SmartDeviceLink/SDLSecurityType.h',
+'SmartDeviceLink/SDLSendHapticData.h',
+'SmartDeviceLink/SDLSendHapticDataResponse.h',
'SmartDeviceLink/SDLSendLocation.h',
'SmartDeviceLink/SDLSendLocationResponse.h',
'SmartDeviceLink/SDLSetAppIcon.h',
diff --git a/SmartDeviceLink/SDLControlFramePayloadAudioStartServiceAck.m b/SmartDeviceLink/SDLControlFramePayloadAudioStartServiceAck.m
index ac969d07b..be5460bb4 100644
--- a/SmartDeviceLink/SDLControlFramePayloadAudioStartServiceAck.m
+++ b/SmartDeviceLink/SDLControlFramePayloadAudioStartServiceAck.m
@@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
_mtu = SDLControlFrameInt64NotFound;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLControlFramePayloadEndService.m b/SmartDeviceLink/SDLControlFramePayloadEndService.m
index 8399da517..372400e7d 100644
--- a/SmartDeviceLink/SDLControlFramePayloadEndService.m
+++ b/SmartDeviceLink/SDLControlFramePayloadEndService.m
@@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
_hashId = SDLControlFrameInt32NotFound;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLControlFramePayloadNak.m b/SmartDeviceLink/SDLControlFramePayloadNak.m
index 4402dea47..15f5c517c 100644
--- a/SmartDeviceLink/SDLControlFramePayloadNak.m
+++ b/SmartDeviceLink/SDLControlFramePayloadNak.m
@@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
self = [super init];
if (!self) return nil;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLControlFramePayloadRPCStartService.m b/SmartDeviceLink/SDLControlFramePayloadRPCStartService.m
index 222370d24..95245e93e 100644
--- a/SmartDeviceLink/SDLControlFramePayloadRPCStartService.m
+++ b/SmartDeviceLink/SDLControlFramePayloadRPCStartService.m
@@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
self = [super init];
if (!self) return nil;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLControlFramePayloadRPCStartServiceAck.m b/SmartDeviceLink/SDLControlFramePayloadRPCStartServiceAck.m
index e4b8347fa..cc2c2c3a5 100644
--- a/SmartDeviceLink/SDLControlFramePayloadRPCStartServiceAck.m
+++ b/SmartDeviceLink/SDLControlFramePayloadRPCStartServiceAck.m
@@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
_hashId = SDLControlFrameInt32NotFound;
_mtu = SDLControlFrameInt64NotFound;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLControlFramePayloadVideoStartService.m b/SmartDeviceLink/SDLControlFramePayloadVideoStartService.m
index 800c3ace8..d33698ebb 100644
--- a/SmartDeviceLink/SDLControlFramePayloadVideoStartService.m
+++ b/SmartDeviceLink/SDLControlFramePayloadVideoStartService.m
@@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
_height = SDLControlFrameInt32NotFound;
_width = SDLControlFrameInt32NotFound;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLControlFramePayloadVideoStartServiceAck.m b/SmartDeviceLink/SDLControlFramePayloadVideoStartServiceAck.m
index d74d1c68c..f16f4b108 100644
--- a/SmartDeviceLink/SDLControlFramePayloadVideoStartServiceAck.m
+++ b/SmartDeviceLink/SDLControlFramePayloadVideoStartServiceAck.m
@@ -45,7 +45,7 @@
_height = SDLControlFrameInt32NotFound;
_width = SDLControlFrameInt32NotFound;
- if (data != nil) {
+ if (data.length > 0) {
[self sdl_parse:data];
}
diff --git a/SmartDeviceLink/SDLFunctionID.m b/SmartDeviceLink/SDLFunctionID.m
index 147706405..c18cdc2cb 100644
--- a/SmartDeviceLink/SDLFunctionID.m
+++ b/SmartDeviceLink/SDLFunctionID.m
@@ -75,6 +75,7 @@ NS_ASSUME_NONNULL_BEGIN
@46: SDLNameSubscribeWayPoints,
@47: SDLNameUnsubscribeWayPoints,
@48: SDLNameGetSystemCapability,
+ @49: SDLNameSendHapticData,
@32768: SDLNameOnHMIStatus,
@32769: SDLNameOnAppInterfaceUnregistered,
@32770: SDLNameOnButtonEvent,
diff --git a/SmartDeviceLink/SDLH264ByteStreamPacketizer.h b/SmartDeviceLink/SDLH264ByteStreamPacketizer.h
new file mode 100644
index 000000000..5b6d57928
--- /dev/null
+++ b/SmartDeviceLink/SDLH264ByteStreamPacketizer.h
@@ -0,0 +1,17 @@
+//
+// SDLH264ByteStreamPacketizer.h
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/11/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SDLH264Packetizer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLH264ByteStreamPacketizer : NSObject <SDLH264Packetizer>
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLH264ByteStreamPacketizer.m b/SmartDeviceLink/SDLH264ByteStreamPacketizer.m
new file mode 100644
index 000000000..c229b0438
--- /dev/null
+++ b/SmartDeviceLink/SDLH264ByteStreamPacketizer.m
@@ -0,0 +1,51 @@
+//
+// SDLH264ByteStreamPacketizer.m
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/11/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SDLH264ByteStreamPacketizer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLH264ByteStreamPacketizer ()
+@property (nonatomic) NSData *startCode;
+@end
+
+@implementation SDLH264ByteStreamPacketizer
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ // This is the start code that we will write to the elementary stream before every NAL unit
+ UInt8 startCode[] = {0x00, 0x00, 0x00, 0x01};
+ _startCode = [[NSData alloc] initWithBytes:startCode length:4];
+
+ return self;
+}
+
+- (nullable NSArray<NSData *> *)createPackets:(NSArray<NSData *> *)nalUnits
+ presentationTimestamp:(double)presentationTimestamp {
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:1];
+ NSMutableData *elementaryStream = [NSMutableData data];
+
+ // Note: this packetizer consolidates all NAL units into one NSData object
+ // to keep compatibility with previous implementation.
+ for (NSData *nalUnit in nalUnits) {
+ [elementaryStream appendData:self.startCode];
+ [elementaryStream appendData:nalUnit];
+ }
+
+ [array addObject:elementaryStream];
+ return [array copy];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLH264Packetizer.h b/SmartDeviceLink/SDLH264Packetizer.h
new file mode 100644
index 000000000..45c5e8d5c
--- /dev/null
+++ b/SmartDeviceLink/SDLH264Packetizer.h
@@ -0,0 +1,33 @@
+//
+// SDLH264Packetizer.h
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/11/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol SDLH264Packetizer
+
+/**
+ * Creates packets from given H.264 NAL units and presentation timestamp.
+ *
+ * @param nalUnits List of NAL units to create packets.
+ * @param presentationTimestamp Presentation timestamp associated to
+ * the NAL units, in seconds.
+ *
+ * @return List of NSData. Each NSData holds a packet.
+ *
+ * @warning This method cannot be called more than once with same pts value.
+ * All NAL units that belongs to a frame should be included in
+ * nalUnits array.
+ */
+- (nullable NSArray<NSData *> *)createPackets:(NSArray<NSData *> *)nalUnits
+ presentationTimestamp:(double)presentationTimestamp;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLHapticRect.h b/SmartDeviceLink/SDLHapticRect.h
new file mode 100644
index 000000000..295ea55af
--- /dev/null
+++ b/SmartDeviceLink/SDLHapticRect.h
@@ -0,0 +1,34 @@
+//
+// SDLHapticRect.h
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/3/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "SDLRPCStruct.h"
+
+@class SDLRectangle;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Defines spatial for each user control object for video streaming application
+ */
+@interface SDLHapticRect : SDLRPCStruct
+
+- (instancetype)initWithId:(UInt32)id rect:(SDLRectangle *)rect;
+
+/**
+ * A user control spatial identifier
+ * Required, Integer, 0 - 2,000,000,000
+ */
+@property (strong, nonatomic) NSNumber<SDLUInt> *id;
+
+@property (strong, nonatomic) SDLRectangle *rect;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLHapticRect.m b/SmartDeviceLink/SDLHapticRect.m
new file mode 100644
index 000000000..330756d4c
--- /dev/null
+++ b/SmartDeviceLink/SDLHapticRect.m
@@ -0,0 +1,48 @@
+//
+// SDLHapticRect.m
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/3/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import "NSMutableDictionary+Store.h"
+#import "SDLHapticRect.h"
+#import "SDLNames.h"
+#import "SDLRectangle.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLHapticRect
+
+- (instancetype)initWithId:(UInt32)id rect:(nonnull SDLRectangle *)rect {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+
+ self.id = @(id);
+ self.rect = rect;
+
+ return self;
+}
+
+- (void)setId:(NSNumber<SDLInt> *)id {
+ [store sdl_setObject:id forName:SDLNameId];
+}
+
+- (NSNumber<SDLInt> *)id {
+ return [store sdl_objectForName:SDLNameId];
+}
+
+- (void)setRect:(SDLRectangle *)rect {
+ [store sdl_setObject:rect forName:SDLNameRect];
+}
+
+- (SDLRectangle *)rect {
+ return [store sdl_objectForName:SDLNameRect ofClass:SDLRectangle.class];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLMetadataType.h b/SmartDeviceLink/SDLMetadataType.h
index cc6518b1c..c5a309412 100644
--- a/SmartDeviceLink/SDLMetadataType.h
+++ b/SmartDeviceLink/SDLMetadataType.h
@@ -73,8 +73,3 @@ extern SDLMetadataType const SDLMetadataTypeWeatherTerm;
*/
extern SDLMetadataType const SDLMetadataTypeHumidity;
-/**
- The data in this field is not of a common type or should not be processed. Any time a field does not have a type parameter it is considered as the none type.
- */
-extern SDLMetadataType const SDLMetadataTypeNone;
-
diff --git a/SmartDeviceLink/SDLMetadataType.m b/SmartDeviceLink/SDLMetadataType.m
index ad032569b..22e846ccc 100644
--- a/SmartDeviceLink/SDLMetadataType.m
+++ b/SmartDeviceLink/SDLMetadataType.m
@@ -20,4 +20,3 @@ SDLMetadataType const SDLMetadataTypeMaximumTemperature = @"maximumTemperature";
SDLMetadataType const SDLMetadataTypeMinimumTemperature = @"minimumTemperature";
SDLMetadataType const SDLMetadataTypeWeatherTerm = @"weatherTerm";
SDLMetadataType const SDLMetadataTypeHumidity = @"humidity";
-SDLMetadataType const SDLMetadataTypeNone = @"none";
diff --git a/SmartDeviceLink/SDLNames.h b/SmartDeviceLink/SDLNames.h
index 0e0165755..91bdbab8c 100644
--- a/SmartDeviceLink/SDLNames.h
+++ b/SmartDeviceLink/SDLNames.h
@@ -138,11 +138,14 @@ extern SDLName const SDLNameGetWayPointsEnabled;
extern SDLName const SDLNameGPS;
extern SDLName const SDLNameGraphic;
extern SDLName const SDLNameGraphicSupported;
+extern SDLName const SDLNameHapticRectData;
+extern SDLName const SDLNameHapticSpatialDataSupported;
extern SDLName const SDLNameHardware;
extern SDLName const SDLNameHashId;
extern SDLName const SDLNameHDOP;
extern SDLName const SDLNameHeading;
extern SDLName const SDLNameHeadLampStatus;
+extern SDLName const SDLNameHeight;
extern SDLName const SDLNameHelpPrompt;
extern SDLName const SDLNameHighBeamsOn;
extern SDLName const SDLNameHMIDisplayLanguage;
@@ -322,6 +325,7 @@ extern SDLName const SDLNameReadDID;
extern SDLName const SDLNameRearLeftDoorAjar;
extern SDLName const SDLNameRearRightDoorAjar;
extern SDLName const SDLNameReason;
+extern SDLName const SDLNameRect;
extern SDLName const SDLNameRegisterAppInterface;
extern SDLName const SDLNameRequest;
extern SDLName const SDLNameRequestType;
@@ -354,6 +358,8 @@ extern SDLName const SDLNameSecondaryImage;
extern SDLName const SDLNameSecondaryText;
extern SDLName const SDLNameSecond;
extern SDLName const SDLNameSeconds;
+extern SDLName const SDLNameSendHapticData;
+extern SDLName const SDLNameSendHapticDataResponse;
extern SDLName const SDLNameSendLocation;
extern SDLName const SDLNameSendLocationEnabled;
extern SDLName const SDLNameSetAppIcon;
diff --git a/SmartDeviceLink/SDLNames.m b/SmartDeviceLink/SDLNames.m
index 79cbaf797..084d3397f 100644
--- a/SmartDeviceLink/SDLNames.m
+++ b/SmartDeviceLink/SDLNames.m
@@ -135,11 +135,14 @@ SDLName const SDLNameGetWayPointsEnabled = @"getWayPointsEnabled";
SDLName const SDLNameGPS = @"gps";
SDLName const SDLNameGraphic = @"graphic";
SDLName const SDLNameGraphicSupported = @"graphicSupported";
+SDLName const SDLNameHapticRectData = @"hapticRectData";
+SDLName const SDLNameHapticSpatialDataSupported = @"hapticSpatialDataSupported";
SDLName const SDLNameHardware = @"hardware";
SDLName const SDLNameHashId = @"hashID";
SDLName const SDLNameHDOP = @"hdop";
SDLName const SDLNameHeading = @"heading";
SDLName const SDLNameHeadLampStatus = @"headLampStatus";
+SDLName const SDLNameHeight = @"height";
SDLName const SDLNameHelpPrompt = @"helpPrompt";
SDLName const SDLNameHighBeamsOn = @"highBeamsOn";
SDLName const SDLNameHMIDisplayLanguage = @"hmiDisplayLanguage";
@@ -316,6 +319,7 @@ SDLName const SDLNameReadDID = @"ReadDID";
SDLName const SDLNameRearLeftDoorAjar = @"rearLeftDoorAjar";
SDLName const SDLNameRearRightDoorAjar = @"rearRightDoorAjar";
SDLName const SDLNameReason = @"reason";
+SDLName const SDLNameRect = @"rect";
SDLName const SDLNameRegisterAppInterface = @"RegisterAppInterface";
SDLName const SDLNameRequest = @"request";
SDLName const SDLNameRequestType = @"requestType";
@@ -348,6 +352,8 @@ SDLName const SDLNameSecondaryImage = @"secondaryImage";
SDLName const SDLNameSecondaryText = @"secondaryText";
SDLName const SDLNameSecond = @"second";
SDLName const SDLNameSeconds = @"seconds";
+SDLName const SDLNameSendHapticData = @"SendHapticData";
+SDLName const SDLNameSendHapticDataResponse = @"SendHapticDataResponse";
SDLName const SDLNameSendLocation = @"SendLocation";
SDLName const SDLNameSendLocationEnabled = @"sendLocationEnabled";
SDLName const SDLNameSetAppIcon = @"SetAppIcon";
diff --git a/SmartDeviceLink/SDLNotificationConstants.h b/SmartDeviceLink/SDLNotificationConstants.h
index 9c9edca13..d313edb39 100644
--- a/SmartDeviceLink/SDLNotificationConstants.h
+++ b/SmartDeviceLink/SDLNotificationConstants.h
@@ -114,6 +114,7 @@ extern SDLNotificationName const SDLDidReceiveReadDIDResponse;
extern SDLNotificationName const SDLDidReceiveRegisterAppInterfaceResponse;
extern SDLNotificationName const SDLDidReceiveResetGlobalPropertiesResponse;
extern SDLNotificationName const SDLDidReceiveScrollableMessageResponse;
+extern SDLNotificationName const SDLDidReceiveSendHapticDataResponse;
extern SDLNotificationName const SDLDidReceiveSendLocationResponse;
extern SDLNotificationName const SDLDidReceiveSetAppIconResponse;
extern SDLNotificationName const SDLDidReceiveSetDisplayLayoutResponse;
diff --git a/SmartDeviceLink/SDLNotificationConstants.m b/SmartDeviceLink/SDLNotificationConstants.m
index b444a8857..1952f397b 100644
--- a/SmartDeviceLink/SDLNotificationConstants.m
+++ b/SmartDeviceLink/SDLNotificationConstants.m
@@ -47,6 +47,7 @@ SDLNotificationName const SDLDidReceiveReadDIDResponse = @"com.sdl.response.read
SDLNotificationName const SDLDidReceiveRegisterAppInterfaceResponse = @"com.sdl.response.registerAppInterface";
SDLNotificationName const SDLDidReceiveResetGlobalPropertiesResponse = @"com.sdl.response.resetGlobalProperties";
SDLNotificationName const SDLDidReceiveScrollableMessageResponse = @"com.sdl.response.scrollableMessage";
+SDLNotificationName const SDLDidReceiveSendHapticDataResponse = @"com.sdl.response.sendHapticData";
SDLNotificationName const SDLDidReceiveSendLocationResponse = @"com.sdl.response.sendLocation";
SDLNotificationName const SDLDidReceiveSetAppIconResponse = @"com.sdl.response.setAppIcon";
SDLNotificationName const SDLDidReceiveSetDisplayLayoutResponse = @"com.sdl.response.setDisplayLayout";
@@ -117,6 +118,7 @@ SDLNotificationName const SDLDidReceiveWaypointNotification = @"com.sdl.notifica
SDLDidReceiveRegisterAppInterfaceResponse,
SDLDidReceiveResetGlobalPropertiesResponse,
SDLDidReceiveScrollableMessageResponse,
+ SDLDidReceiveSendHapticDataResponse,
SDLDidReceiveSendLocationResponse,
SDLDidReceiveSetAppIconResponse,
SDLDidReceiveSetDisplayLayoutResponse,
diff --git a/SmartDeviceLink/SDLNotificationDispatcher.m b/SmartDeviceLink/SDLNotificationDispatcher.m
index a26e46a4a..3da6e790a 100644
--- a/SmartDeviceLink/SDLNotificationDispatcher.m
+++ b/SmartDeviceLink/SDLNotificationDispatcher.m
@@ -186,6 +186,10 @@ NS_ASSUME_NONNULL_BEGIN
[self postRPCResponseNotification:SDLDidReceiveScrollableMessageResponse response:response];
}
+- (void)onSendHapticDataResponse:(SDLSendHapticDataResponse *)response {
+ [self postRPCResponseNotification:SDLDidReceiveSendHapticDataResponse response:response];
+}
+
- (void)onSendLocationResponse:(SDLSendLocationResponse *)response {
[self postRPCResponseNotification:SDLDidReceiveSendLocationResponse response:response];
}
diff --git a/SmartDeviceLink/SDLProxyListener.h b/SmartDeviceLink/SDLProxyListener.h
index 42c6782bf..64c177579 100644
--- a/SmartDeviceLink/SDLProxyListener.h
+++ b/SmartDeviceLink/SDLProxyListener.h
@@ -50,6 +50,7 @@
@class SDLRegisterAppInterfaceResponse;
@class SDLResetGlobalPropertiesResponse;
@class SDLScrollableMessageResponse;
+@class SDLSendHapticDataResponse;
@class SDLSendLocationResponse;
@class SDLSetAppIconResponse;
@class SDLSetDisplayLayoutResponse;
@@ -126,6 +127,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)onRegisterAppInterfaceResponse:(SDLRegisterAppInterfaceResponse *)response;
- (void)onResetGlobalPropertiesResponse:(SDLResetGlobalPropertiesResponse *)response;
- (void)onScrollableMessageResponse:(SDLScrollableMessageResponse *)response;
+- (void)onSendHapticDataResponse:(SDLSendHapticDataResponse *)response;
- (void)onSendLocationResponse:(SDLSendLocationResponse *)response;
- (void)onSetAppIconResponse:(SDLSetAppIconResponse *)response;
- (void)onSetDisplayLayoutResponse:(SDLSetDisplayLayoutResponse *)response;
diff --git a/SmartDeviceLink/SDLRTPH264Packetizer.h b/SmartDeviceLink/SDLRTPH264Packetizer.h
new file mode 100644
index 000000000..b909fa1d1
--- /dev/null
+++ b/SmartDeviceLink/SDLRTPH264Packetizer.h
@@ -0,0 +1,43 @@
+//
+// SDLRTPH264Packetizer.h
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/11/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SDLH264Packetizer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLRTPH264Packetizer : NSObject <SDLH264Packetizer>
+
+/**
+ * Payload Type (PT) of RTP header field.
+ *
+ * PT field identifies the format of the RTP payload ([5.1] in RFC 3550).
+ * RFC 6184 doesn’t specify this value and says it "has to be performed
+ * either through the profile used or in a dynamic way" in [5.1].
+ *
+ * In our spec, this value is chosen from range 96-127 (which are for
+ * dynamic assignment) and will be ignored by HMI. Refer to the proposal:
+ * https://github.com/smartdevicelink/sdl_evolution/blob/master/proposals/0048-H264-over-RTP-support-for-video-streaming.md
+ *
+ * @note Default value is 96.
+ */
+@property (assign, nonatomic) UInt8 payloadType;
+
+/**
+ * SSRC of RTP header field.
+ *
+ * SSRC field identifies the source of a stream and it should be
+ * chosen randomly (see section 3 and 5.1 in RFC 3550).
+ *
+ * @note A random value is generated and used as default.
+ */
+@property (assign, nonatomic) UInt32 ssrc;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLRTPH264Packetizer.m b/SmartDeviceLink/SDLRTPH264Packetizer.m
new file mode 100644
index 000000000..06fc645ad
--- /dev/null
+++ b/SmartDeviceLink/SDLRTPH264Packetizer.m
@@ -0,0 +1,246 @@
+//
+// SDLRTPH264Packetizer.m
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/11/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+/*
+ * Note for testing.
+ * The RTP stream generated by this packetizer can be tested with GStreamer (1.4 or later).
+ * Assuming that "VideoStreamPort" is configured as 5050 in smartDeviceLink.ini, here is the
+ * GStreamer pipeline that receives the stream, decode it and render it:
+ *
+ * $ gst-launch-1.0 souphttpsrc location=http://127.0.0.1:5050 ! "application/x-rtp-stream" ! rtpstreamdepay ! "application/x-rtp,media=(string)video,clock-rate=90000,encoding-name=(string)H264" ! rtph264depay ! "video/x-h264, stream-format=(string)avc, alignment=(string)au" ! avdec_h264 ! videoconvert ! ximagesink sync=false
+ */
+
+#import <Foundation/Foundation.h>
+#import "SDLRTPH264Packetizer.h"
+#import "SDLLogMacros.h"
+
+const NSUInteger FrameLengthLen = 2;
+const NSUInteger MaxRTPPacketSize = 65535; // because length field is two bytes (RFC 4571)
+const NSUInteger RTPHeaderLen = 12;
+const UInt8 DefaultPayloadType = 96;
+const NSUInteger FragmentationUnitIndicatorLen = 1;
+const NSUInteger FragmentationUnitHeaderLen = 1;
+const UInt8 FragmentationUnitVersionA = 0x1C;
+const NSUInteger ClockRate = 90000; // we use 90 kHz clock rate ([5.1] in RFC 6184)
+
+/**
+ * write 2-byte value into buffer in network byte order
+ *
+ * @param buffer buffer to write the value
+ * @param value value to write
+ */
+static inline void sdl_writeShortInNetworkByteOrder(UInt8 *buffer, UInt16 value) {
+ buffer[0] = (value >> 8) & 0xFF;
+ buffer[1] = value & 0xFF;
+}
+
+/**
+ * write 4-byte value into buffer in network byte order
+ *
+ * @param buffer buffer to write the value
+ * @param value value to write
+ */
+static inline void sdl_writeLongInNetworkByteOrder(UInt8 *buffer, UInt32 value) {
+ buffer[0] = (value >> 24) & 0xFF;
+ buffer[1] = (value >> 16) & 0xFF;
+ buffer[2] = (value >> 8) & 0xFF;
+ buffer[3] = value & 0xFF;
+}
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SDLRTPH264Packetizer ()
+@property (assign, nonatomic) UInt32 initialTimestamp;
+@property (assign, nonatomic) UInt16 sequenceNum;
+@end
+
+@implementation SDLRTPH264Packetizer
+
+- (instancetype)init {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ _payloadType = DefaultPayloadType;
+ // initial value of the sequence number and timestamp should be random ([5.1] in RFC3550)
+ _initialTimestamp = arc4random_uniform(UINT32_MAX);
+ _sequenceNum = (UInt16)arc4random_uniform(UINT16_MAX);
+ _ssrc = arc4random_uniform(UINT32_MAX);
+
+ return self;
+}
+
+- (void)setPayloadType:(UInt8)payloadType {
+ if (payloadType <= 127) {
+ _payloadType = payloadType;
+ } else {
+ _payloadType = DefaultPayloadType;
+ }
+}
+
+- (nullable NSArray<NSData *> *)createPackets:(NSArray<NSData *> *)nalUnits
+ presentationTimestamp:(double)presentationTimestamp {
+ NSMutableArray *rtpFrames = [NSMutableArray array];
+ NSUInteger nalUnitsCount = nalUnits.count;
+
+ for (NSUInteger i = 0; i < nalUnitsCount; i++) {
+ NSData *nalUnit = nalUnits[i];
+ BOOL isLast = ((i + 1) == nalUnitsCount);
+
+ if (RTPHeaderLen + nalUnit.length > MaxRTPPacketSize) {
+ // Split into multiple Fragmentation Units ([5.8] in RFC 6184)
+ if (![self sdl_addRTPFramesWithFragmentationUnits:rtpFrames nalUnit:nalUnit presentationTimestamp:presentationTimestamp isLast:isLast]) {
+ return nil;
+ }
+ } else {
+ // Use Single NAL Unit Packet ([5.6] in RFC 6184)
+ if (![self sdl_addRTPFrameWithSingleNALUnit:rtpFrames nalUnit:nalUnit presentationTimestamp:presentationTimestamp isLast:isLast]) {
+ return nil;
+ }
+ }
+ }
+
+ return [rtpFrames copy];
+}
+
+/**
+ * Create and add a RTP frame from a NAL unit without splitting
+ *
+ * @param rtpFrames the array to which created RTP frame is added
+ * @param nalUnit NAL unit to create RTP frame from
+ * @param presentationTimestamp presentation timestamp in seconds
+ * @param isLast mark YES if this is the last NAL unit of a video frame
+ *
+ * @return YES if successful, NO if memory error occurred
+ */
+- (BOOL)sdl_addRTPFrameWithSingleNALUnit:(NSMutableArray<NSData *> *)rtpFrames
+ nalUnit:(NSData *)nalUnit
+ presentationTimestamp:(double)presentationTimestamp
+ isLast:(BOOL)isLast {
+ NSUInteger nalUnitLength = nalUnit.length;
+ NSUInteger packetSize = RTPHeaderLen + nalUnitLength;
+ NSUInteger frameSize = FrameLengthLen + packetSize;
+
+ NSAssert(RTPHeaderLen + nalUnitLength <= MaxRTPPacketSize, @"This NAL unit doesn't fit into single RTP packet");
+
+ UInt8 *buffer = malloc(frameSize);
+ if (buffer == NULL) {
+ SDLLogE(@"malloc() error");
+ return NO;
+ }
+ UInt8 *writePointer = buffer;
+
+ writePointer += [self sdl_writeFrameHeader:writePointer packetSize:packetSize];
+ writePointer += [self sdl_writeRTPHeader:writePointer marker:isLast presentationTimestamp:presentationTimestamp];
+ [nalUnit getBytes:writePointer length:nalUnitLength];
+
+ NSData *rtpFrame = [NSData dataWithBytesNoCopy:buffer length:frameSize];
+ [rtpFrames addObject:rtpFrame];
+
+ return YES;
+}
+
+/**
+ * Create and add a RTP frames by splitting a NAL unit into multiple Fragmentation Units
+ *
+ * @param rtpFrames the array to which created RTP frames are added
+ * @param nalUnit NAL unit to create RTP frames from
+ * @param presentationTimestamp presentation timestamp in seconds
+ * @param isLast mark YES if this is the last NAL unit of a video frame
+ *
+ * @return YES if successful, NO if memory error occurred
+ */
+- (BOOL)sdl_addRTPFramesWithFragmentationUnits:(NSMutableArray<NSData *> *)rtpFrames
+ nalUnit:(NSData *)nalUnit
+ presentationTimestamp:(double)presentationTimestamp
+ isLast:(BOOL)isLast {
+ UInt8 firstByte;
+ [nalUnit getBytes:&firstByte length:1];
+ BOOL isFirstFragment = YES;
+ BOOL isLastFragment = NO;
+ NSUInteger nalUnitLength = nalUnit.length;
+ NSUInteger offset = 1; // we have already read the first byte
+
+ while (offset < nalUnitLength) {
+ NSUInteger payloadLength = MaxRTPPacketSize - (RTPHeaderLen + FragmentationUnitIndicatorLen + FragmentationUnitHeaderLen);
+ if (nalUnitLength - offset <= payloadLength) {
+ payloadLength = nalUnitLength - offset;
+ isLastFragment = YES;
+ }
+ NSUInteger packetSize = RTPHeaderLen + FragmentationUnitIndicatorLen + FragmentationUnitHeaderLen + payloadLength;
+ NSUInteger frameSize = FrameLengthLen + packetSize;
+
+ UInt8 *buffer = malloc(frameSize);
+ if (buffer == NULL) {
+ SDLLogE(@"malloc() error");
+ return NO;
+ }
+ UInt8 *writePointer = buffer;
+
+ writePointer += [self sdl_writeFrameHeader:writePointer packetSize:packetSize];
+ writePointer += [self sdl_writeRTPHeader:writePointer marker:isLast presentationTimestamp:presentationTimestamp];
+
+ // Fragmentation Unit indicator
+ *writePointer++ = (firstByte & 0xE0) | FragmentationUnitVersionA;
+ // Fragmentation Unit header
+ *writePointer++ = (isFirstFragment ? 0x80 : isLastFragment ? 0x40 : 0) | (firstByte & 0x1F);
+ // Fragmentation Unit payload
+ [nalUnit getBytes:writePointer range:NSMakeRange(offset, payloadLength)];
+ offset += payloadLength;
+
+ NSData *rtpFrame = [NSData dataWithBytesNoCopy:buffer length:frameSize];
+ [rtpFrames addObject:rtpFrame];
+
+ isFirstFragment = NO;
+ }
+
+ return YES;
+}
+
+/**
+ * Write RTP Frame header (length field) to supplied buffer.
+ *
+ * @param frameHeaderBuffer the buffer in which a header is written.
+ * @param packetSize size of a RTP packet that follows to this frame header.
+ *
+ * @return number of bytes written, which is always 2.
+ */
+- (NSUInteger)sdl_writeFrameHeader:(UInt8 *)frameHeaderBuffer packetSize:(NSUInteger)packetSize {
+ NSAssert(packetSize <= MaxRTPPacketSize, @"RTP packet is too big");
+ sdl_writeShortInNetworkByteOrder(frameHeaderBuffer, (UInt16)packetSize);
+ return FrameLengthLen;
+}
+
+/**
+ * Write RTP header to supplied buffer.
+ *
+ * @param rtpHeaderBuffer the buffer in which a header is written.
+ * @param isLast whether this is the last packet of an access unit.
+ * @param presentationTimestamp presentation timestamp in seconds.
+ *
+ * @return number of bytes written, which is always 12.
+ */
+- (NSUInteger)sdl_writeRTPHeader:(UInt8 *)rtpHeaderBuffer marker:(BOOL)isLast presentationTimestamp:(double)presentationTimestamp {
+ UInt32 presentationTimestampIn90kHz = presentationTimestamp * ClockRate;
+
+ // Version = 2, Padding = 0, Extension = 0, CSRC count = 0
+ rtpHeaderBuffer[0] = 0x80;
+ // Marker = isLast, Payload type = self.payloadType
+ rtpHeaderBuffer[1] = (isLast ? 0x80 : 0) | (self.payloadType & 0x7F);
+ sdl_writeShortInNetworkByteOrder(rtpHeaderBuffer + 2, self.sequenceNum);
+ sdl_writeLongInNetworkByteOrder(rtpHeaderBuffer + 4, self.initialTimestamp + presentationTimestampIn90kHz);
+ sdl_writeLongInNetworkByteOrder(rtpHeaderBuffer + 8, self.ssrc);
+
+ self.sequenceNum++;
+ return RTPHeaderLen;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLRectangle.h b/SmartDeviceLink/SDLRectangle.h
new file mode 100644
index 000000000..5395f6315
--- /dev/null
+++ b/SmartDeviceLink/SDLRectangle.h
@@ -0,0 +1,56 @@
+//
+// SDLRectangle.h
+// SmartDeviceLink-iOS
+//
+// Created by Joel Fischer on 8/23/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <SmartDeviceLink/SmartDeviceLink.h>
+
+@interface SDLRectangle : SDLRPCStruct
+
+/**
+ Create a Rectangle
+
+ @param x The top-left x value
+ @param y The top-left y value
+ @param width The width
+ @param height The height
+ @return An new SDLRectangle object
+ */
+- (instancetype)initWithX:(float)x y:(float)y width:(float)width height:(float)height;
+
+/**
+ Create a Rectangle from a CGRect
+
+ @param rect The rectangle to use
+ @return An new SDLRectangle object
+ */
+- (instancetype)initWithCGRect:(CGRect)rect;
+
+/**
+ * The X-coordinate of the user control
+ * Required, Float
+ */
+@property (strong, nonatomic) NSNumber<SDLFloat> *x;
+
+/**
+ * The Y-coordinate of the user control
+ * Required, Float
+ */
+@property (strong, nonatomic) NSNumber<SDLFloat> *y;
+
+/**
+ * The width of the user control's bounding rectangle
+ * Required, Float
+ */
+@property (strong, nonatomic) NSNumber<SDLFloat> *width;
+
+/**
+ * The height of the user control's bounding rectangle
+ * Required, Float
+ */
+@property (strong, nonatomic) NSNumber<SDLFloat> *height;
+
+@end
diff --git a/SmartDeviceLink/SDLRectangle.m b/SmartDeviceLink/SDLRectangle.m
new file mode 100644
index 000000000..6a82312b9
--- /dev/null
+++ b/SmartDeviceLink/SDLRectangle.m
@@ -0,0 +1,63 @@
+//
+// SDLRectangle.m
+// SmartDeviceLink-iOS
+//
+// Created by Joel Fischer on 8/23/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import "NSMutableDictionary+Store.h"
+#import "SDLRectangle.h"
+#import "SDLNames.h"
+
+@implementation SDLRectangle
+
+- (instancetype)initWithX:(float)x y:(float)y width:(float)width height:(float)height {
+ self = [self init];
+ if (!self) { return nil; }
+
+ self.x = @(x);
+ self.y = @(y);
+ self.width = @(width);
+ self.height = @(height);
+
+ return self;
+}
+
+- (instancetype)initWithCGRect:(CGRect)rect {
+ return [self initWithX:rect.origin.x y:rect.origin.y width:rect.size.width height:rect.size.height];
+}
+
+- (void)setX:(NSNumber<SDLFloat> *)x {
+ [store sdl_setObject:x forName:SDLNameX];
+}
+
+- (NSNumber<SDLFloat> *)x {
+ return [store sdl_objectForName:SDLNameX];
+}
+
+- (void)setY:(NSNumber<SDLFloat> *)y {
+ [store sdl_setObject:y forName:SDLNameY];
+}
+
+- (NSNumber<SDLFloat> *)y {
+ return [store sdl_objectForName:SDLNameY];
+}
+
+- (void)setWidth:(NSNumber<SDLFloat> *)width {
+ [store sdl_setObject:width forName:SDLNameWidth];
+}
+
+- (NSNumber<SDLFloat> *)width {
+ return [store sdl_objectForName:SDLNameWidth];
+}
+
+- (void)setHeight:(NSNumber<SDLFloat> *)height {
+ [store sdl_setObject:height forName:SDLNameHeight];
+}
+
+- (NSNumber<SDLFloat> *)height {
+ return [store sdl_objectForName:SDLNameHeight];
+}
+
+@end
diff --git a/SmartDeviceLink/SDLSendHapticData.h b/SmartDeviceLink/SDLSendHapticData.h
new file mode 100644
index 000000000..c4c0f237c
--- /dev/null
+++ b/SmartDeviceLink/SDLSendHapticData.h
@@ -0,0 +1,37 @@
+//
+// SDLSendHapticData.h
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/3/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "SDLRPCRequest.h"
+
+@class SDLHapticRect;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Sends the spatial data gathered from SDLCarWindow or VirtualDisplayEncoder to the HMI. This data will be utilized by the HMI to determine how and when haptic events should occur.
+ */
+@interface SDLSendHapticData : SDLRPCRequest
+
+/**
+ * Constructs a new SDLSendHapticData object indicated by the hapticSpatialData parameter
+ *
+ * @param hapticRectData Array of spatial data structures
+ */
+- (instancetype)initWithHapticRectData:(NSArray<SDLHapticRect *> *)hapticRectData;
+
+/**
+ * Array of spatial data structures that represent the locations of all user controls present on the HMI. This data should be updated if/when the application presents a new screen. When a request is sent, if successful, it will replace all spatial data previously sent through RPC. If an empty array is sent, the existing spatial data will be cleared
+ *
+ * Optional, Array of SDLHapticRect, Array size 0 - 1,000
+ */
+@property (strong, nonatomic, nullable) NSArray<SDLHapticRect *> *hapticRectData;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLSendHapticData.m b/SmartDeviceLink/SDLSendHapticData.m
new file mode 100644
index 000000000..d1f85988a
--- /dev/null
+++ b/SmartDeviceLink/SDLSendHapticData.m
@@ -0,0 +1,44 @@
+//
+// SDLSendHapticData.m
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/3/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import "NSMutableDictionary+Store.h"
+#import "SDLNames.h"
+#import "SDLSendHapticData.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLSendHapticData
+
+- (instancetype)init {
+ if (self = [super initWithName:SDLNameSendHapticData]) {
+ }
+ return self;
+}
+
+- (instancetype)initWithHapticRectData:(NSArray<SDLHapticRect *> *)hapticRectData {
+ self = [self init];
+ if (!self) {
+ return nil;
+ }
+
+ self.hapticRectData = [hapticRectData mutableCopy];
+
+ return self;
+}
+
+- (void)setHapticRectData:(nullable NSArray<SDLHapticRect *> *)hapticRectData {
+ [parameters sdl_setObject:hapticRectData forName:SDLNameHapticRectData];
+}
+
+- (nullable NSArray<SDLHapticRect *> *)hapticRectData {
+ return [parameters sdl_objectForName:SDLNameHapticRectData];
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLSendHapticDataResponse.h b/SmartDeviceLink/SDLSendHapticDataResponse.h
new file mode 100644
index 000000000..c811c0e22
--- /dev/null
+++ b/SmartDeviceLink/SDLSendHapticDataResponse.h
@@ -0,0 +1,19 @@
+//
+// SDLSendHapticDataResponse.h
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/4/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import "SDLRPCResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+/**
+ * SDLSendHapticDataResponse is sent when SDLSendHapticData has been called
+ */
+@interface SDLSendHapticDataResponse : SDLRPCResponse
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLSendHapticDataResponse.m b/SmartDeviceLink/SDLSendHapticDataResponse.m
new file mode 100644
index 000000000..b1fa03607
--- /dev/null
+++ b/SmartDeviceLink/SDLSendHapticDataResponse.m
@@ -0,0 +1,25 @@
+
+//
+// SDLSendHapticDataResponse.m
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/4/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import "SDLNames.h"
+#import "SDLSendHapticDataResponse.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation SDLSendHapticDataResponse
+
+- (instancetype)init {
+ if (self = [super initWithName:SDLNameSendHapticDataResponse]) {
+ }
+ return self;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
index d1b0e446a..1dcbcd09f 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
@@ -146,6 +146,16 @@ extern SDLAudioStreamState *const SDLAudioStreamStateShuttingDown;
- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer;
/**
+ * This method receives raw image data and will run iOS8+'s hardware video encoder to turn the data into a video stream, which will then be passed to the connected head unit.
+ *
+ * @param imageBuffer A CVImageBufferRef to be encoded by Video Toolbox
+ * @param presentationTimestamp A presentation timestamp for the frame, or kCMTimeInvalid if timestamp is unknown. If it's valid, it must be greater than the previous one.
+ *
+ * @return Whether or not the data was successfully encoded and sent.
+ */
+- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp;
+
+/**
* This method receives PCM audio data and will attempt to send that data across to the head unit for immediate playback
*
* @param audioData The data in PCM audio format, to be played
diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
index b56313eba..53a813551 100644
--- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
@@ -64,6 +64,8 @@ static NSUInteger const SDLFramesToSendOnBackground = 30;
@property (assign, nonatomic) CV_NULLABLE CVPixelBufferRef backgroundingPixelBuffer;
+@property (assign, nonatomic) CMTime lastPresentationTimestamp;
+
@end
@@ -114,6 +116,8 @@ static NSUInteger const SDLFramesToSendOnBackground = 30;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_appStateDidUpdate:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sdl_appStateDidUpdate:) name:UIApplicationWillResignActiveNotification object:nil];
+ _lastPresentationTimestamp = kCMTimeInvalid;
+
return self;
}
@@ -136,6 +140,10 @@ static NSUInteger const SDLFramesToSendOnBackground = 30;
}
- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer {
+ return [self sendVideoData:imageBuffer presentationTimestamp:kCMTimeInvalid];
+}
+
+- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp {
if (!self.isVideoConnected) {
SDLLogW(@"Attempted to send video data, but not connected");
return NO;
@@ -146,8 +154,20 @@ static NSUInteger const SDLFramesToSendOnBackground = 30;
SDLLogW(@"Attempted to send video data, but the app is not in LIMITED or FULL HMI state");
return NO;
}
-
- return [self.videoEncoder encodeFrame:imageBuffer];
+
+ /*
+ * reject input image for following cases:
+ * - presentation timestamp is not increasing
+ * - app tries to send images while background images are shown
+ */
+ if (CMTIME_IS_VALID(self.lastPresentationTimestamp) && CMTIME_IS_VALID(presentationTimestamp)
+ && CMTIME_COMPARE_INLINE(presentationTimestamp, <=, self.lastPresentationTimestamp)) {
+ SDLLogW(@"The video data is out of date");
+ return NO;
+ }
+ self.lastPresentationTimestamp = presentationTimestamp;
+
+ return [self.videoEncoder encodeFrame:imageBuffer presentationTimestamp:presentationTimestamp];
}
- (BOOL)sendAudioData:(NSData*)audioData {
@@ -297,6 +317,7 @@ static NSUInteger const SDLFramesToSendOnBackground = 30;
self.backgroundingPixelBuffer = backgroundingPixelBuffer;
}
+ self.lastPresentationTimestamp = kCMTimeInvalid;
}
[[NSNotificationCenter defaultCenter] postNotificationName:SDLVideoStreamDidStartNotification object:nil];
@@ -517,8 +538,14 @@ static NSUInteger const SDLFramesToSendOnBackground = 30;
return;
}
+ const CMTime interval = CMTimeMake(1, 30);
for (int frameCount = 0; frameCount < SDLFramesToSendOnBackground; frameCount++) {
- [self.videoEncoder encodeFrame:self.backgroundingPixelBuffer];
+ if (CMTIME_IS_VALID(self.lastPresentationTimestamp)) {
+ self.lastPresentationTimestamp = CMTimeAdd(self.lastPresentationTimestamp, interval);
+ [self.videoEncoder encodeFrame:self.backgroundingPixelBuffer presentationTimestamp:self.lastPresentationTimestamp];
+ } else {
+ [self.videoEncoder encodeFrame:self.backgroundingPixelBuffer];
+ }
}
}
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h
index 232856d40..46169484b 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.h
+++ b/SmartDeviceLink/SDLStreamingMediaManager.h
@@ -114,6 +114,16 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer;
/**
+ * This method receives raw image data and will run iOS8+'s hardware video encoder to turn the data into a video stream, which will then be passed to the connected head unit.
+ *
+ * @param imageBuffer A CVImageBufferRef to be encoded by Video Toolbox
+ * @param presentationTimestamp A presentation timestamp for the frame, or kCMTimeInvalid if timestamp is unknown. If it's valid, it must be greater than the previous one.
+ *
+ * @return Whether or not the data was successfully encoded and sent.
+ */
+- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp;
+
+/**
* This method receives PCM audio data and will attempt to send that data across to the head unit for immediate playback
*
* @param audioData The data in PCM audio format, to be played
diff --git a/SmartDeviceLink/SDLStreamingMediaManager.m b/SmartDeviceLink/SDLStreamingMediaManager.m
index 1c4291931..72bbf9691 100644
--- a/SmartDeviceLink/SDLStreamingMediaManager.m
+++ b/SmartDeviceLink/SDLStreamingMediaManager.m
@@ -53,6 +53,10 @@ NS_ASSUME_NONNULL_BEGIN
return [self.lifecycleManager sendVideoData:imageBuffer];
}
+- (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp {
+ return [self.lifecycleManager sendVideoData:imageBuffer presentationTimestamp:presentationTimestamp];
+}
+
- (BOOL)sendAudioData:(NSData*)audioData {
return [self.lifecycleManager sendAudioData:audioData];
}
diff --git a/SmartDeviceLink/SDLVideoEncoder.h b/SmartDeviceLink/SDLVideoEncoder.h
index e48f8c311..53816452b 100644
--- a/SmartDeviceLink/SDLVideoEncoder.h
+++ b/SmartDeviceLink/SDLVideoEncoder.h
@@ -60,6 +60,8 @@ extern NSString *const SDLErrorDomainVideoEncoder;
- (BOOL)encodeFrame:(CVImageBufferRef)imageBuffer;
+- (BOOL)encodeFrame:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp;
+
/**
* Creates a new pixel buffer using the pixelBufferPool property.
*/
diff --git a/SmartDeviceLink/SDLVideoEncoder.m b/SmartDeviceLink/SDLVideoEncoder.m
index 91eed8631..f3216d851 100644
--- a/SmartDeviceLink/SDLVideoEncoder.m
+++ b/SmartDeviceLink/SDLVideoEncoder.m
@@ -8,6 +8,7 @@
#import "SDLVideoEncoder.h"
+#import "SDLH264ByteStreamPacketizer.h"
#import "SDLLogMacros.h"
@@ -22,6 +23,8 @@ static NSDictionary<NSString *, id>* _defaultVideoEncoderSettings;
@property (assign, nonatomic, nullable) VTCompressionSessionRef compressionSession;
@property (assign, nonatomic, nullable) CFDictionaryRef sdl_pixelBufferOptions;
@property (assign, nonatomic) NSUInteger currentFrameNumber;
+@property (nonatomic) id<SDLH264Packetizer> packetizer;
+@property (assign, nonatomic) double timestampOffset;
@end
@@ -106,7 +109,10 @@ static NSDictionary<NSString *, id>* _defaultVideoEncoderSettings;
return nil;
}
}
-
+
+ _packetizer = [[SDLH264ByteStreamPacketizer alloc] init];
+ _timestampOffset = 0.0;
+
return self;
}
@@ -119,7 +125,16 @@ static NSDictionary<NSString *, id>* _defaultVideoEncoderSettings;
}
- (BOOL)encodeFrame:(CVImageBufferRef)imageBuffer {
- OSStatus status = VTCompressionSessionEncodeFrame(_compressionSession, imageBuffer, CMTimeMake(self.currentFrameNumber++, 30), kCMTimeInvalid, NULL, (__bridge void *)self, NULL);
+ return [self encodeFrame:imageBuffer presentationTimestamp:kCMTimeInvalid];
+}
+
+- (BOOL)encodeFrame:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp {
+ if (!CMTIME_IS_VALID(presentationTimestamp)) {
+ presentationTimestamp = CMTimeMake(self.currentFrameNumber, 30);
+ }
+ self.currentFrameNumber++;
+
+ OSStatus status = VTCompressionSessionEncodeFrame(_compressionSession, imageBuffer, presentationTimestamp, kCMTimeInvalid, NULL, (__bridge void *)self, NULL);
return (status == noErr);
}
@@ -161,10 +176,25 @@ void sdl_videoEncoderOutputCallback(void * CM_NULLABLE outputCallbackRefCon, voi
}
SDLVideoEncoder *encoder = (__bridge SDLVideoEncoder *)sourceFrameRefCon;
- NSData *elementaryStreamData = [encoder.class sdl_encodeElementaryStreamWithSampleBuffer:sampleBuffer];
+ NSArray *nalUnits = [encoder.class sdl_extractNalUnitsFromSampleBuffer:sampleBuffer];
+
+ const CMTime presentationTimestampInCMTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
+ double presentationTimestamp = 0.0;
+ if (CMTIME_IS_VALID(presentationTimestampInCMTime)) {
+ presentationTimestamp = CMTimeGetSeconds(presentationTimestampInCMTime);
+ }
+ if (encoder.timestampOffset == 0.0) {
+ // remember this first timestamp as the offset
+ encoder.timestampOffset = presentationTimestamp;
+ }
+
+ NSArray *packets = [encoder.packetizer createPackets:nalUnits
+ presentationTimestamp:(presentationTimestamp - encoder.timestampOffset)];
if ([encoder.delegate respondsToSelector:@selector(videoEncoder:hasEncodedFrame:)]) {
- [encoder.delegate videoEncoder:encoder hasEncodedFrame:elementaryStreamData];
+ for (NSData *packet in packets) {
+ [encoder.delegate videoEncoder:encoder hasEncodedFrame:packet];
+ }
}
}
@@ -190,9 +220,9 @@ void sdl_videoEncoderOutputCallback(void * CM_NULLABLE outputCallbackRefCon, voi
}
#pragma mark Helpers
-+ (NSData *)sdl_encodeElementaryStreamWithSampleBuffer:(CMSampleBufferRef)sampleBuffer {
++ (NSArray *)sdl_extractNalUnitsFromSampleBuffer:(CMSampleBufferRef)sampleBuffer {
// Creating an elementaryStream: http://stackoverflow.com/questions/28396622/extracting-h264-from-cmblockbuffer
- NSMutableData *elementaryStream = [NSMutableData data];
+ NSMutableArray *nalUnits = [NSMutableArray array];
BOOL isIFrame = NO;
CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, 0);
@@ -205,10 +235,6 @@ void sdl_videoEncoderOutputCallback(void * CM_NULLABLE outputCallbackRefCon, voi
isIFrame = !keyExists || !CFBooleanGetValue(notSync);
}
- // This is the start code that we will write to the elementary stream before every NAL unit
- static const size_t startCodeLength = 4;
- static const uint8_t startCode[] = {0x00, 0x00, 0x00, 0x01};
-
// Write the SPS and PPS NAL units to the elementary stream before every I-Frame
if (isIFrame) {
CMFormatDescriptionRef description = CMSampleBufferGetFormatDescription(sampleBuffer);
@@ -233,9 +259,9 @@ void sdl_videoEncoderOutputCallback(void * CM_NULLABLE outputCallbackRefCon, voi
NULL,
NULL);
- // Write the parameter set to the elementary stream
- [elementaryStream appendBytes:startCode length:startCodeLength];
- [elementaryStream appendBytes:parameterSetPointer length:parameterSetLength];
+ // Output the parameter set
+ NSData *nalUnit = [NSData dataWithBytesNoCopy:(uint8_t *)parameterSetPointer length:parameterSetLength freeWhenDone:NO];
+ [nalUnits addObject:nalUnit];
}
}
@@ -256,17 +282,17 @@ void sdl_videoEncoderOutputCallback(void * CM_NULLABLE outputCallbackRefCon, voi
// Convert the length value from Big-endian to Little-endian
NALUnitLength = CFSwapInt32BigToHost(NALUnitLength);
- [elementaryStream appendBytes:startCode length:startCodeLength];
// Write the NAL unit without the AVCC length header to the elementary stream
- [elementaryStream appendBytes:bufferDataPointer + bufferOffset + AVCCHeaderLength length:NALUnitLength];
+ NSData *nalUnit = [NSData dataWithBytesNoCopy:bufferDataPointer + bufferOffset + AVCCHeaderLength length:NALUnitLength freeWhenDone:NO];
+ [nalUnits addObject:nalUnit];
// Move to the next NAL unit in the block buffer
bufferOffset += AVCCHeaderLength + NALUnitLength;
}
- return elementaryStream;
+ return nalUnits;
}
@end
diff --git a/SmartDeviceLink/SDLVideoStreamingCapability.h b/SmartDeviceLink/SDLVideoStreamingCapability.h
index a19ec1a68..86de1f1ac 100644
--- a/SmartDeviceLink/SDLVideoStreamingCapability.h
+++ b/SmartDeviceLink/SDLVideoStreamingCapability.h
@@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLVideoStreamingCapability : SDLRPCStruct
-- (instancetype)initWithVideoStreaming:(nullable SDLImageResolution *)preferredResolution maxBitrate:(nullable NSNumber *)maxBitrate supportedFormats:(nullable NSArray<SDLVideoStreamingFormat *> *)supportedFormats;
+- (instancetype)initWithVideoStreaming:(nullable SDLImageResolution *)preferredResolution maxBitrate:(nullable NSNumber<SDLInt> *)maxBitrate supportedFormats:(nullable NSArray<SDLVideoStreamingFormat *> *)supportedFormats hapticDataSupported:(nullable NSNumber<SDLBool> *)hapticDataSupported;
/**
* @abstract The preferred resolution of a video stream for decoding and rendering on HMI, optional
*/
@@ -35,6 +35,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nullable, strong, nonatomic) NSArray<SDLVideoStreamingFormat *> *supportedFormats;
+/**
+ True if the system can utilize the haptic spatial data from the source being streamed.
+ */
+@property (nullable, strong, nonatomic) NSNumber<SDLBool> *hapticSpatialDataSupported;
@end
diff --git a/SmartDeviceLink/SDLVideoStreamingCapability.m b/SmartDeviceLink/SDLVideoStreamingCapability.m
index cf4d33e98..75873a710 100644
--- a/SmartDeviceLink/SDLVideoStreamingCapability.m
+++ b/SmartDeviceLink/SDLVideoStreamingCapability.m
@@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation SDLVideoStreamingCapability
-- (instancetype)initWithVideoStreaming:(nullable SDLImageResolution *)preferredResolution maxBitrate:(nullable NSNumber *)maxBitrate supportedFormats:(nullable NSArray<SDLVideoStreamingFormat *> *)supportedFormats {
+- (instancetype)initWithVideoStreaming:(nullable SDLImageResolution *)preferredResolution maxBitrate:(nullable NSNumber<SDLInt> *)maxBitrate supportedFormats:(nullable NSArray<SDLVideoStreamingFormat *> *)supportedFormats hapticDataSupported:(nullable NSNumber<SDLBool> *)hapticDataSupported {
self = [self init];
if (!self) {
return self;
@@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
self.maxBitrate = maxBitrate;
self.preferredResolution = preferredResolution;
self.supportedFormats = supportedFormats;
+ self.hapticSpatialDataSupported = hapticDataSupported;
return self;
}
@@ -54,6 +55,14 @@ NS_ASSUME_NONNULL_BEGIN
return [store sdl_objectsForName:SDLNameSupportedFormats ofClass:SDLVideoStreamingFormat.class];
}
+- (void)setHapticSpatialDataSupported:(nullable NSNumber<SDLBool> *)hapticSpatialDataSupported {
+ [store sdl_setObject:hapticSpatialDataSupported forName:SDLNameHapticSpatialDataSupported];
+}
+
+- (nullable NSNumber<SDLBool> *)hapticSpatialDataSupported {
+ return [store sdl_objectForName:SDLNameHapticSpatialDataSupported];
+}
+
@end
NS_ASSUME_NONNULL_END
diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h
index 5ef93ec4a..3f72f59ff 100644
--- a/SmartDeviceLink/SmartDeviceLink.h
+++ b/SmartDeviceLink/SmartDeviceLink.h
@@ -72,6 +72,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLRegisterAppInterface.h"
#import "SDLResetGlobalProperties.h"
#import "SDLScrollableMessage.h"
+#import "SDLSendHapticData.h"
#import "SDLSendLocation.h"
#import "SDLSetAppIcon.h"
#import "SDLSetDisplayLayout.h"
@@ -119,6 +120,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLRegisterAppInterfaceResponse.h"
#import "SDLResetGlobalPropertiesResponse.h"
#import "SDLScrollableMessageResponse.h"
+#import "SDLSendHapticDataResponse.h"
#import "SDLSendLocationResponse.h"
#import "SDLSetAppIconResponse.h"
#import "SDLSetDisplayLayoutResponse.h"
@@ -176,6 +178,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLECallInfo.h"
#import "SDLEmergencyEvent.h"
#import "SDLGPSData.h"
+#import "SDLHapticRect.h"
#import "SDLHMICapabilities.h"
#import "SDLHMIPermissions.h"
#import "SDLHeadLampStatus.h"
@@ -194,6 +197,7 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[];
#import "SDLPermissionItem.h"
#import "SDLPhoneCapability.h"
#import "SDLPresetBankCapabilities.h"
+#import "SDLRectangle.h"
#import "SDLScreenParams.h"
#import "SDLSingleTireStatus.h"
#import "SDLSoftButton.h"
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLH264ByteStreamPacketizerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLH264ByteStreamPacketizerSpec.m
new file mode 100644
index 000000000..59a3529bf
--- /dev/null
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLH264ByteStreamPacketizerSpec.m
@@ -0,0 +1,89 @@
+//
+// SDLH264ByteStreamPacketizerSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/13/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import "SDLH264ByteStreamPacketizer.h"
+
+QuickSpecBegin(SDLH264ByteStreamPacketizerSpec)
+
+describe(@"a H264 byte stream packetizer", ^{
+ // sample NAL units (SPS, PPS, I-frame, P-frame)
+ const UInt8 spsData[] = {0x67, 0x42, 0xC0, 0x0A, 0xA6, 0x11, 0x11, 0xE8, 0x40, 0x00, 0x00, 0xFA, 0x40, 0x00, 0x3A, 0x98, 0x23, 0xC4, 0x89, 0x84, 0x60};
+ const UInt8 ppsData[] = {0x68, 0xC8, 0x42, 0x0F, 0x13, 0x20};
+ const UInt8 iframeData[] = {0x65, 0x88, 0x82, 0x07, 0x67, 0x39, 0x31, 0x40, 0x00, 0x5E, 0x0A, 0xFB, 0xEF, 0xAE, 0xBA, 0xEB, 0xAE, 0xBA, 0xEB, 0xC0};
+ const UInt8 pframeData[] = {0x41, 0x9A, 0x1C, 0x0E, 0xCE, 0x71, 0xB0};
+
+ NSData *sps = [NSData dataWithBytes:spsData length:sizeof(spsData)];
+ NSData *pps = [NSData dataWithBytes:ppsData length:sizeof(ppsData)];
+ NSData *iframe = [NSData dataWithBytes:iframeData length:sizeof(iframeData)];
+ NSData *pframe = [NSData dataWithBytes:pframeData length:sizeof(pframeData)];
+
+ __block SDLH264ByteStreamPacketizer *packetizer = nil;
+
+ beforeEach(^{
+ packetizer = [[SDLH264ByteStreamPacketizer alloc] init];
+ });
+
+ describe(@"its output array", ^{
+ it(@"always has one packet", ^{
+ NSArray *nalUnits1 = @[sps, pps, iframe];
+ NSArray *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ expect(@(results.count)).to(equal(@1));
+
+ NSArray *nalUnits2 = @[pframe];
+ results = [packetizer createPackets:nalUnits2 presentationTimestamp:1.0/30];
+ expect(@(results.count)).to(equal(@1));
+ });
+ });
+
+ describe(@"its output packet", ^{
+ it(@"starts with a start code of 0x00 0x00 0x00 0x01", ^{
+ const UInt8 startCode[] = {0x00, 0x00, 0x00, 0x01};
+
+ NSArray<NSData *> *nalUnits = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ const UInt8 *p = results[0].bytes;
+
+ int ret = memcmp(p, startCode, sizeof(startCode));
+ expect(@(ret)).to(equal(@0));
+ });
+
+ it(@"then duplicates original H.264 NAL unit", ^{
+ NSData *nalUnit = iframe;
+
+ NSArray<NSData *> *nalUnits = @[nalUnit];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ const UInt8 *p = results[0].bytes;
+
+ int ret = memcmp(p + 4, nalUnit.bytes, nalUnit.length);
+ expect(@(ret)).to(equal(@0));
+ });
+
+ it(@"repeats for all given NAL units", ^{
+ const UInt8 startCode[] = {0x00, 0x00, 0x00, 0x01};
+
+ NSArray<NSData *> *nalUnits = @[sps, pps, iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ const UInt8 *p = results[0].bytes;
+
+ for (NSData *nalUnit in nalUnits) {
+ int ret = memcmp(p, startCode, sizeof(startCode));
+ expect(@(ret)).to(equal(@0));
+ p += sizeof(startCode);
+
+ ret = memcmp(p, nalUnit.bytes, nalUnit.length);
+ expect(@(ret)).to(equal(@0));
+ p += nalUnit.length;
+ }
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLNotificationDispatcherSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLNotificationDispatcherSpec.m
index 3dff5dc9e..7c39d7b46 100644
--- a/SmartDeviceLinkTests/DevAPISpecs/SDLNotificationDispatcherSpec.m
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLNotificationDispatcherSpec.m
@@ -63,6 +63,7 @@ describe(@"a notification dispatcher", ^{
expect(@([testDispatcher respondsToSelector:@selector(onRegisterAppInterfaceResponse:)])).to(beTruthy());
expect(@([testDispatcher respondsToSelector:@selector(onResetGlobalPropertiesResponse:)])).to(beTruthy());
expect(@([testDispatcher respondsToSelector:@selector(onScrollableMessageResponse:)])).to(beTruthy());
+ expect(@([testDispatcher respondsToSelector:@selector(onSendHapticDataResponse:)])).to(beTruthy());
expect(@([testDispatcher respondsToSelector:@selector(onSendLocationResponse:)])).to(beTruthy());
expect(@([testDispatcher respondsToSelector:@selector(onSetAppIconResponse:)])).to(beTruthy());
expect(@([testDispatcher respondsToSelector:@selector(onSetDisplayLayoutResponse:)])).to(beTruthy());
diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLRTPH264PacketizerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLRTPH264PacketizerSpec.m
new file mode 100644
index 000000000..a82e2ef65
--- /dev/null
+++ b/SmartDeviceLinkTests/DevAPISpecs/SDLRTPH264PacketizerSpec.m
@@ -0,0 +1,401 @@
+//
+// SDLRTPH264PacketizerSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Sho Amano on 4/13/17.
+// Copyright © 2017 Xevo Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+#import "SDLRTPH264Packetizer.h"
+
+// read 2-byte in network byte order and convert it to a UInt16
+static inline UInt16 sdl_readShortInNetworkByteOrder(const UInt8 *buffer) {
+ return (buffer[0] << 8) | buffer[1];
+}
+
+// read 4-byte in network byte order and convert it to a UInt32
+static inline UInt32 sdl_readLongInNetworkByteOrder(const UInt8 *buffer) {
+ return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+}
+
+QuickSpecBegin(SDLRTPH264PacketizerSpec)
+
+describe(@"a RTP H264 packetizer", ^{
+ // sample NAL units (SPS, PPS, I-frame, P-frame)
+ const UInt8 spsData[] = {0x67, 0x42, 0xC0, 0x0A, 0xA6, 0x11, 0x11, 0xE8, 0x40, 0x00, 0x00, 0xFA, 0x40, 0x00, 0x3A, 0x98, 0x23, 0xC4, 0x89, 0x84, 0x60};
+ const UInt8 ppsData[] = {0x68, 0xC8, 0x42, 0x0F, 0x13, 0x20};
+ const UInt8 iframeData[] = {0x65, 0x88, 0x82, 0x07, 0x67, 0x39, 0x31, 0x40, 0x00, 0x5E, 0x0A, 0xFB, 0xEF, 0xAE, 0xBA, 0xEB, 0xAE, 0xBA, 0xEB, 0xC0};
+ const UInt8 pframeData[] = {0x41, 0x9A, 0x1C, 0x0E, 0xCE, 0x71, 0xB0};
+
+ NSData *sps = [NSData dataWithBytes:spsData length:sizeof(spsData)];
+ NSData *pps = [NSData dataWithBytes:ppsData length:sizeof(ppsData)];
+ NSData *iframe = [NSData dataWithBytes:iframeData length:sizeof(iframeData)];
+ NSData *pframe = [NSData dataWithBytes:pframeData length:sizeof(pframeData)];
+
+ const NSUInteger FrameLengthLen = 2;
+ const NSUInteger MaxRTPPacketSize = 65535;
+ const NSUInteger RTPHeaderLen = 12;
+ const UInt8 DefaultPayloadType = 96;
+ const UInt8 FragmentationUnitVersionA = 0x1C;
+ const NSUInteger ClockRate = 90000;
+
+ __block SDLRTPH264Packetizer *packetizer = nil;
+
+ beforeEach(^{
+ packetizer = [[SDLRTPH264Packetizer alloc] init];
+ });
+
+ describe(@"its output array", ^{
+ it(@"has same number or more elements compared to the input NAL units", ^{
+ NSArray<NSData *> *nalUnits = @[sps, pps, iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ expect(@(results.count)).to(beGreaterThanOrEqualTo(@(nalUnits.count)));
+ });
+ });
+
+ describe(@"First two bytes of its output", ^{
+ it(@"indicates the length of a RTP packet", ^{
+ NSArray<NSData *> *nalUnits = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ UInt16 length = sdl_readShortInNetworkByteOrder(header);
+ expect(@((length))).to(equal(@(results[0].length - FrameLengthLen)));
+ });
+ });
+
+ describe(@"header of the RTP packet", ^{
+ __block const UInt8 *header;
+
+ beforeEach(^{
+ NSArray<NSData *> *nalUnits = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ header = results[0].bytes;
+ });
+
+ it(@"indicates version 2", ^{
+ expect(@((header[FrameLengthLen] >> 6) & 3)).to(equal(@2));
+ });
+ it(@"indicates no padding", ^{
+ expect(@((header[FrameLengthLen] >> 5) & 1)).to(equal(@0));
+ });
+ it(@"indicates no extension", ^{
+ expect(@((header[FrameLengthLen] >> 4) & 1)).to(equal(@0));
+ });
+ it(@"indicates no CSRC", ^{
+ expect(@(header[FrameLengthLen] & 0xF)).to(equal(@0));
+ });
+ });
+
+ describe(@"the marker bit in the header of the RTP packet", ^{
+ context(@"when there is only one NAL unit input", ^{
+ it(@"is always set", ^{
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ expect(@((header[FrameLengthLen+1] >> 7) & 1)).to(equal(@1));
+
+ NSArray<NSData *> *nalUnits2 = @[pframe];
+ results = [packetizer createPackets:nalUnits2 presentationTimestamp:1.0/30];
+ header = results[0].bytes;
+ expect(@((header[FrameLengthLen+1] >> 7) & 1)).to(equal(@1));
+ });
+ });
+
+ context(@"when multiple NAL units are input for an access unit", ^{
+ it(@"is set only for the last packet", ^{
+ // 3 NAL units for a frame
+ NSArray<NSData *> *nalUnits1 = @[sps, pps, iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+
+ [results enumerateObjectsUsingBlock:^(NSData *packet, NSUInteger index, BOOL *stop) {
+ const UInt8 *header = packet.bytes;
+ if (index == results.count - 1) {
+ expect(@((header[FrameLengthLen+1] >> 7) & 1)).to(equal(@1));
+ } else {
+ expect(@((header[FrameLengthLen+1] >> 7) & 1)).to(equal(@0));
+ }
+ }];
+
+ // Only 1 NAL unit for the next frame
+ NSArray<NSData *> *nalUnits2 = @[pframe];
+ results = [packetizer createPackets:nalUnits2 presentationTimestamp:1.0/30];
+ const UInt8 *header = results[0].bytes;
+ expect(@((header[FrameLengthLen+1] >> 7) & 1)).to(equal(@1));
+ });
+ });
+ });
+
+ describe(@"the payload type in the header of the RTP packet", ^{
+ context(@"when it is not configured", ^{
+ it(@"equals to 96", ^{
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ expect(@(header[FrameLengthLen+1] & 0x7F)).to(equal(@(DefaultPayloadType)));
+ });
+ });
+
+ context(@"when it is explicitly configured", ^{
+ it(@"is same as the given number if the number is between 0 and 127", ^{
+ UInt8 payloadType = 100;
+ packetizer.payloadType = payloadType;
+
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ expect(@(header[FrameLengthLen+1] & 0x7F)).to(equal(@(payloadType)));
+ });
+
+ it(@"equals to 96 if the given number is out of range", ^{
+ packetizer.payloadType = 200;
+
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ expect(@(header[FrameLengthLen+1] & 0x7F)).to(equal(@(DefaultPayloadType)));
+ });
+ });
+ });
+
+ describe(@"the sequence number in the header of the RTP packet", ^{
+ it(@"has an initial value of random number", ^{
+ // no way to test a random number
+ });
+
+ it(@"increments by one for the next packet", ^{
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ UInt16 sequenceNumber = sdl_readShortInNetworkByteOrder(&header[FrameLengthLen+2]);
+
+ NSArray<NSData *> *nalUnits2 = @[pframe];
+ results = [packetizer createPackets:nalUnits2 presentationTimestamp:1.0/30];
+ header = results[0].bytes;
+
+ sequenceNumber++;
+ expect(@(sequenceNumber)).to(equal(@(sdl_readShortInNetworkByteOrder(&header[FrameLengthLen+2]))));
+ });
+
+ it(@"wraps around after reaching 65535", ^{
+ NSArray<NSData *> *nalUnits = @[iframe];
+ UInt16 prevSequenceNumber = 0;
+
+ for (NSUInteger i = 0; i <= 65536; i++) {
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:i/30.0];
+ const UInt8 *header = results[0].bytes;
+ UInt16 sequenceNumber = sdl_readShortInNetworkByteOrder(&header[FrameLengthLen+2]);
+
+ if (prevSequenceNumber == 65535) {
+ expect(@(sequenceNumber)).to(equal(@(0)));
+ break; // end testing
+ } else {
+ prevSequenceNumber = sequenceNumber;
+ }
+ }
+ });
+ });
+
+ describe(@"the timestamp field in the header of the RTP packet", ^{
+ it(@"has an initial value of random number", ^{
+ // no way to test a random number
+ });
+
+ it(@"then increases in 90 kHz clock value", ^{
+ NSArray<NSData *> *nalUnits = @[iframe];
+ UInt32 initialPresentationTimestamp = 0;
+
+ for (NSUInteger i = 0; i <= 100; i++) {
+ // the timestamp increases by 1/30 seconds
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:i/30.0];
+ const UInt8 *header = results[0].bytes;
+ UInt32 presentationTimestamp = sdl_readLongInNetworkByteOrder(&header[FrameLengthLen+4]);
+
+ if (i == 0) {
+ initialPresentationTimestamp = presentationTimestamp;
+ } else {
+ UInt32 expectedPresentationTimestamp = initialPresentationTimestamp + i / 30.0 * ClockRate;
+ // accept calculation error (+-1)
+ expect(@(presentationTimestamp)).to(beGreaterThanOrEqualTo(@(expectedPresentationTimestamp - 1)));
+ expect(@(presentationTimestamp)).to(beLessThanOrEqualTo(@(expectedPresentationTimestamp + 1)));
+ }
+ }
+ });
+ });
+
+ describe(@"the SSRC field in the header of the RTP packet", ^{
+ context(@"when it is not configured", ^{
+ it(@"is a random number", ^{
+ // No way to test a random number. We only check that it is shared among packets.
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ UInt32 ssrc = sdl_readLongInNetworkByteOrder(&header[FrameLengthLen+8]);
+
+ NSArray<NSData *> *nalUnits2 = @[pframe];
+ results = [packetizer createPackets:nalUnits2 presentationTimestamp:1.0/30];
+ header = results[0].bytes;
+ UInt32 ssrc2 = sdl_readLongInNetworkByteOrder(&header[FrameLengthLen+8]);
+
+ expect(@(ssrc)).to(equal(@(ssrc2)));
+ });
+ });
+
+ context(@"when it is explicitly configured", ^{
+ it(@"is same as the given number", ^{
+ UInt32 expectedSSRC = 0xFEDCBA98;
+ packetizer.ssrc = expectedSSRC;
+
+ NSArray<NSData *> *nalUnits1 = @[iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits1 presentationTimestamp:0.0];
+ const UInt8 *header = results[0].bytes;
+ UInt32 ssrc = sdl_readLongInNetworkByteOrder(&header[FrameLengthLen+8]);
+ expect(@(ssrc)).to(equal(@(expectedSSRC)));
+
+ NSArray<NSData *> *nalUnits2 = @[pframe];
+ results = [packetizer createPackets:nalUnits2 presentationTimestamp:1.0/30];
+ header = results[0].bytes;
+ ssrc = sdl_readLongInNetworkByteOrder(&header[FrameLengthLen+8]);
+ expect(@(ssrc)).to(equal(@(expectedSSRC)));
+ });
+ });
+ });
+
+ describe(@"the payload of its output packet", ^{
+ NSData *(^createFakeNALUnit)(UInt8, NSUInteger) = ^NSData *(UInt8 firstByte, NSUInteger length) {
+ UInt8 *data = malloc(length);
+ data[0] = firstByte;
+ for (NSUInteger i = 1; i < length; i++) {
+ data[i] = i % 256;
+ }
+ return [NSData dataWithBytes:data length:length];
+ };
+
+ UInt8 firstByte;
+ [iframe getBytes:&firstByte length:1];
+
+ it(@"is not fragmented if input NAL unit size is less than 65524 bytes (65536-12)", ^{
+ NSData *fakeNALUnit = createFakeNALUnit(firstByte, MaxRTPPacketSize - RTPHeaderLen);
+ NSArray<NSData *> *nalUnits = @[fakeNALUnit];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+
+ // we should get only one packet
+ expect(@(results.count)).to(equal(@(1)));
+ });
+
+ it(@"is fragmented if input NAL unit size equals to or is greater than 65524 bytes", ^{
+ NSData *fakeNALUnit = createFakeNALUnit(firstByte, MaxRTPPacketSize - RTPHeaderLen + 1);
+ NSArray<NSData *> *nalUnits = @[fakeNALUnit];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+
+ // the NAL unit should be fragmented into two
+ expect(@(results.count)).to(equal(@(2)));
+ });
+
+ context(@"when payload is not fragmented", ^{
+ it(@"is duplicate of input NAL unit", ^{
+ NSArray<NSData *> *nalUnits = @[sps, pps, iframe];
+ NSArray<NSData *> *results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+
+ NSUInteger nalUnitIndex = 0;
+ for (NSData *packet in results) {
+ const UInt8 *p = packet.bytes;
+ int ret = memcmp(p + FrameLengthLen + RTPHeaderLen,
+ nalUnits[nalUnitIndex].bytes,
+ nalUnits[nalUnitIndex].length);
+ expect(@(ret)).to(equal(@0));
+ nalUnitIndex++;
+ }
+ });
+ });
+
+ context(@"when payload is fragmented", ^{
+ __block NSData *fakeNALUnit;
+ __block NSArray<NSData *> *results;
+
+ beforeEach(^{
+ fakeNALUnit = createFakeNALUnit(firstByte, MaxRTPPacketSize - RTPHeaderLen + 1);
+ NSArray<NSData *> *nalUnits = @[fakeNALUnit];
+ results = [packetizer createPackets:nalUnits presentationTimestamp:0.0];
+ });
+
+ describe(@"its first byte", ^{
+ it(@"has F bit and NRI field which are same as those of the input NAL unit", ^{
+ for (NSData *packet in results) {
+ const UInt8 *header = packet.bytes;
+ expect(@((header[FrameLengthLen+RTPHeaderLen] >> 5) & 3)).to(equal(@((firstByte >> 5) & 3)));
+ }
+ });
+
+ it(@"indicates a Fragmentation Unit Version A type (0x1C)", ^{
+ for (NSData *packet in results) {
+ const UInt8 *header = packet.bytes;
+ expect(@(header[FrameLengthLen+RTPHeaderLen] & 0x1F)).to(equal(@(FragmentationUnitVersionA)));
+ }
+ });
+ });
+
+ describe(@"its second byte", ^{
+ it(@"has a start bit which is set only at the beginning of fragment group", ^{
+ BOOL shouldBeFirstFragment = YES;
+
+ for (NSUInteger i = 0; i < results.count; i++) {
+ const UInt8 *header = results[i].bytes;
+ UInt8 startBit = (header[FrameLengthLen+RTPHeaderLen+1] >> 7) & 1;
+ expect(@(startBit)).to(equal(@(shouldBeFirstFragment ? 1 : 0)));
+ shouldBeFirstFragment = NO;
+ }
+ });
+
+ it(@"has a end bit which is set only at the end of fragment group", ^{
+ BOOL shouldBeLastFragment = NO;
+
+ for (NSUInteger i = 0; i < results.count; i++) {
+ if (i == results.count - 1) {
+ shouldBeLastFragment = YES;
+ } else {
+ shouldBeLastFragment = NO;
+ }
+
+ const UInt8 *header = results[i].bytes;
+ UInt8 endBit = (header[FrameLengthLen+RTPHeaderLen+1] >> 6) & 1;
+ expect(@(endBit)).to(equal(@(shouldBeLastFragment ? 1 : 0)));
+ }
+ });
+
+ it(@"has a reserved bit which is always zero", ^{
+ for (NSUInteger i = 0; i < results.count; i++) {
+ const UInt8 *header = results[i].bytes;
+ expect(@((header[FrameLengthLen+RTPHeaderLen+1] >> 5) & 1)).to(equal(@(0)));
+ }
+ });
+
+ it(@"has a type field which is same as the input NAL unit's type", ^{
+ for (NSUInteger i = 0; i < results.count; i++) {
+ const UInt8 *header = results[i].bytes;
+ expect(@(header[FrameLengthLen+RTPHeaderLen+1] & 0x1F)).to(equal(@(firstByte & 0x1F)));
+ }
+ });
+ });
+
+ describe(@"its third and onward bytes", ^{
+ it(@"equals to original NAL unit's second and onward bytes when concatenated", ^{
+ NSMutableData *concatData = [[NSMutableData alloc] init];
+
+ for (NSUInteger i = 0; i < results.count; i++) {
+ NSData *packet = results[i];
+ const UInt8 *p = packet.bytes;
+ [concatData appendBytes:p + FrameLengthLen + RTPHeaderLen + 2
+ length:packet.length - (FrameLengthLen + RTPHeaderLen + 2)];
+ }
+
+ expect(@([concatData isEqualToData:[fakeNALUnit subdataWithRange:NSMakeRange(1, fakeNALUnit.length - 1)]])).to(beTruthy());
+ });
+ });
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadNakSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadNakSpec.m
index ef0d8fae2..df7bd1305 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadNakSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadNakSpec.m
@@ -54,4 +54,18 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadNak *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadNak alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.rejectedParams).to(beNil());
+ });
+});
+
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadVideoStartServiceSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadVideoStartServiceSpec.m
index 1af113777..c93d72c9b 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadVideoStartServiceSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFramePayloadVideoStartServiceSpec.m
@@ -77,4 +77,17 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadVideoStartService *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadVideoStartService alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.data.length).to(equal(0));
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFrameVideoStartServiceAckSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFrameVideoStartServiceAckSpec.m
index cc7db881c..c817f44f4 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFrameVideoStartServiceAckSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/ControlFramePayloadSpecs/SDLControlFrameVideoStartServiceAckSpec.m
@@ -83,4 +83,17 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadVideoStartServiceAck *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadVideoStartServiceAck alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.data.length).to(equal(0));
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadAudioStartServiceAckSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadAudioStartServiceAckSpec.m
index a168fc39d..548110d0d 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadAudioStartServiceAckSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadAudioStartServiceAckSpec.m
@@ -57,4 +57,18 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadAudioStartServiceAck *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadAudioStartServiceAck alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.mtu).to(equal(-1));
+ expect(testPayload.data.length).to(equal(0));
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadEndServiceSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadEndServiceSpec.m
index 8f7a0c3d2..a59c95811 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadEndServiceSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadEndServiceSpec.m
@@ -55,4 +55,18 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadEndService *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadEndService alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.hashId).to(equal(-1));
+ expect(testPayload.data.length).to(equal(0));
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m
index ee6793249..7397f5713 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceAckSpec.m
@@ -68,4 +68,17 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadRPCStartServiceAck *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadRPCStartServiceAck alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.data.length).to(equal(0));
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceSpec.m
index e8e773c8a..f39204330 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLControlFramePayloadRPCStartServiceSpec.m
@@ -57,4 +57,18 @@ describe(@"Test decoding data", ^{
});
});
+describe(@"Test nil data", ^{
+ __block SDLControlFramePayloadRPCStartService *testPayload = nil;
+ __block NSData *testData = nil;
+
+ beforeEach(^{
+ testPayload = [[SDLControlFramePayloadRPCStartService alloc] initWithData:testData];
+ });
+
+ it(@"should output the correct params", ^{
+ expect(testPayload.protocolVersion).to(beNil());
+ expect(testPayload.data.length).to(equal(0));
+ });
+});
+
QuickSpecEnd
diff --git a/SmartDeviceLinkTests/ProtocolSpecs/SDLFunctionIDSpec.m b/SmartDeviceLinkTests/ProtocolSpecs/SDLFunctionIDSpec.m
index b1f9965fb..51145a6f6 100644
--- a/SmartDeviceLinkTests/ProtocolSpecs/SDLFunctionIDSpec.m
+++ b/SmartDeviceLinkTests/ProtocolSpecs/SDLFunctionIDSpec.m
@@ -60,6 +60,8 @@ describe(@"GetFunctionName Tests", ^ {
expect([functionID functionNameForId:45]).to(equal(SDLNameGetWayPoints));
expect([functionID functionNameForId:46]).to(equal(SDLNameSubscribeWayPoints));
expect([functionID functionNameForId:47]).to(equal(SDLNameUnsubscribeWayPoints));
+ expect([functionID functionNameForId:48]).to(equal(SDLNameGetSystemCapability));
+ expect([functionID functionNameForId:49]).to(equal(SDLNameSendHapticData));
expect([functionID functionNameForId:32768]).to(equal(SDLNameOnHMIStatus));
expect([functionID functionNameForId:32769]).to(equal(SDLNameOnAppInterfaceUnregistered));
expect([functionID functionNameForId:32770]).to(equal(SDLNameOnButtonEvent));
@@ -131,6 +133,8 @@ describe(@"GetFunctionID Tests", ^ {
expect([functionID functionIdForName:SDLNameGetWayPoints]).to(equal(@45));
expect([functionID functionIdForName:SDLNameSubscribeWayPoints]).to(equal(@46));
expect([functionID functionIdForName:SDLNameUnsubscribeWayPoints]).to(equal(@47));
+ expect([functionID functionIdForName:SDLNameGetSystemCapability]).to(equal(@48));
+ expect([functionID functionIdForName:SDLNameSendHapticData]).to(equal(@49));
expect([functionID functionIdForName:SDLNameOnHMIStatus]).to(equal(@32768));
expect([functionID functionIdForName:SDLNameOnAppInterfaceUnregistered]).to(equal(@32769));
expect([functionID functionIdForName:SDLNameOnButtonEvent]).to(equal(@32770));
diff --git a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMetadataTypeSpec.m b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMetadataTypeSpec.m
index 1ede591ee..0ef9bc45f 100644
--- a/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMetadataTypeSpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/EnumSpecs/SDLMetadataTypeSpec.m
@@ -29,7 +29,6 @@ describe(@"Individual Enum Value Tests", ^ {
expect(SDLMetadataTypeMinimumTemperature).to(equal(@"minimumTemperature"));
expect(SDLMetadataTypeWeatherTerm).to(equal(@"weatherTerm"));
expect(SDLMetadataTypeHumidity).to(equal(@"humidity"));
- expect(SDLMetadataTypeNone).to(equal(@"none"));
});
});
diff --git a/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSendHapticDataSpec.m b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSendHapticDataSpec.m
new file mode 100644
index 000000000..24bf7ddb2
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/RequestSpecs/SDLSendHapticDataSpec.m
@@ -0,0 +1,62 @@
+//
+// SDLSendHapticDataSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/4/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLNames.h"
+#import "SDLHapticRect.h"
+#import "SDLRectangle.h"
+#import "SDLSendHapticData.h"
+
+QuickSpecBegin(SDLSendHapticDataSpec)
+
+describe(@"Initialization Tests", ^ {
+ __block SDLHapticRect *testStruct = nil;
+
+ beforeEach(^{
+ testStruct = [[SDLHapticRect alloc] initWithId:123 rect:[[SDLRectangle alloc] initWithX:23.1 y:45.6 width:69.0 height:69]];
+ });
+
+ context(@"Getter/Setter Tests", ^ {
+ it(@"Should set and get correctly", ^ {
+ SDLSendHapticData *testRequest = [[SDLSendHapticData alloc] init];
+ testRequest.hapticRectData = [@[testStruct] mutableCopy];
+
+ expect(testRequest.hapticRectData).to(equal(@[testStruct]));
+ });
+ });
+
+ context(@"Init tests", ^{
+ it(@"Should get correctly when initialized with a dictionary", ^ {
+ NSMutableDictionary* dict = [@{SDLNameRequest:
+ @{SDLNameParameters:
+ @{SDLNameHapticRectData:@[testStruct]},
+ SDLNameOperationName:SDLNameSendHapticData}} mutableCopy];
+ SDLSendHapticData *testRequest = [[SDLSendHapticData alloc] initWithDictionary:dict];
+
+ expect(testRequest.hapticRectData).to(equal(@[testStruct]));
+ });
+
+ it(@"Should initialize correctly with initWithType:", ^{
+ SDLSendHapticData *testRequest = [[SDLSendHapticData alloc] initWithHapticRectData:@[testStruct]];
+
+ expect(testRequest.hapticRectData).to(equal(@[testStruct]));
+ });
+
+ it(@"Should return nil if not set", ^ {
+ SDLSendHapticData *testRequest = [[SDLSendHapticData alloc] init];
+
+ expect(testRequest.hapticRectData).to(beNil());
+ });
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLSendHapticDataResponseSpec.m b/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLSendHapticDataResponseSpec.m
new file mode 100644
index 000000000..29be138ad
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/ResponseSpecs/SDLSendHapticDataResponseSpec.m
@@ -0,0 +1,19 @@
+//
+// SDLSendHapticDataResponseSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/4/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLNames.h"
+#import "SDLSendHapticDataResponse.h"
+
+QuickSpecBegin(SDLSendHapticDataResponseSpec)
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLHapticRectSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLHapticRectSpec.m
new file mode 100644
index 000000000..6235ea62f
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLHapticRectSpec.m
@@ -0,0 +1,69 @@
+//
+// SDLHapticRectSpec.m
+// SmartDeviceLink-iOS
+//
+// Created by Nicole on 8/3/17.
+// Copyright © 2017 smartdevicelink. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLNames.h"
+#import "SDLHapticRect.h"
+#import "SDLRectangle.h"
+
+QuickSpecBegin(SDLHapticRectSpec)
+
+describe(@"Getter/Setter Tests", ^{
+ __block SDLRectangle *testRect = nil;
+ beforeEach(^{
+ testRect = [[SDLRectangle alloc] initWithX:1.2 y:42.3 width:78.9 height:69];
+ });
+
+ it(@"Should set and get correctly", ^{
+ SDLHapticRect *testStruct = [[SDLHapticRect alloc] init];
+
+ testStruct.id = @1;
+ testStruct.rect = testRect;
+
+ expect(testStruct.id).to(equal(@1));
+ expect(testStruct.rect).to(equal(testRect));
+ });
+
+ it(@"Should get correctly when initialized with parameters", ^{
+ SDLHapticRect *testStruct = [[SDLHapticRect alloc] initWithId:23 rect:testRect];
+
+ expect(testStruct.id).to(equal(@23));
+ expect(testStruct.rect).to(equal(testRect));
+ });
+
+ it(@"Should get correctly when initialized with a dict", ^{
+ NSMutableDictionary *dict = [@{SDLNameId:@2,
+ SDLNameRect: @{
+ SDLNameX:@20,
+ SDLNameY:@200,
+ SDLNameWidth:@2000,
+ SDLNameHeight:@3000
+ }
+ } mutableCopy];
+ SDLHapticRect *testStruct = [[SDLHapticRect alloc] initWithDictionary:dict];
+
+ expect(testStruct.id).to(equal(@2));
+ expect(testStruct.rect.x).to(equal(@20));
+ expect(testStruct.rect.y).to(equal(@200));
+ expect(testStruct.rect.width).to(equal(@2000));
+ expect(testStruct.rect.height).to(equal(@3000));
+ });
+
+ it(@"Should return nil if not set", ^{
+ SDLHapticRect *testStruct = [[SDLHapticRect alloc] init];
+
+ expect(testStruct.id).to(beNil());
+ expect(testStruct.rect).to(beNil());
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRectangleSpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRectangleSpec.m
new file mode 100644
index 000000000..59749135d
--- /dev/null
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLRectangleSpec.m
@@ -0,0 +1,58 @@
+#import <Foundation/Foundation.h>
+
+#import <Quick/Quick.h>
+#import <Nimble/Nimble.h>
+
+#import "SDLNames.h"
+#import "SDLRectangle.h"
+
+QuickSpecBegin(SDLRectangleSpec)
+
+describe(@"Getter/Setter Tests", ^{
+ it(@"Should set and get correctly", ^{
+ SDLRectangle *testStruct = [[SDLRectangle alloc] init];
+
+ testStruct.x = @10;
+ testStruct.y = @100;
+ testStruct.width = @1000;
+ testStruct.height = @2000;
+
+ expect(testStruct.x).to(equal(@10));
+ expect(testStruct.y).to(equal(@100));
+ expect(testStruct.width).to(equal(@1000));
+ expect(testStruct.height).to(equal(@2000));
+ });
+
+ it(@"Should get correctly when initialized with parameters", ^{
+ SDLRectangle *testStruct = [[SDLRectangle alloc] initWithX:50.5 y:60.2 width:500 height:600];
+
+ expect(testStruct.x).to(beCloseTo(@50.5));
+ expect(testStruct.y).to(beCloseTo(@60.2));
+ expect(testStruct.width).to(equal(@500.0));
+ expect(testStruct.height).to(equal(@600.0));
+ });
+
+ it(@"Should get correctly when initialized with a dict", ^{
+ NSDictionary *dict = @{SDLNameX:@20,
+ SDLNameY:@200,
+ SDLNameWidth:@2000,
+ SDLNameHeight:@3000};
+ SDLRectangle *testStruct = [[SDLRectangle alloc] initWithDictionary:dict];
+
+ expect(testStruct.x).to(equal(@20));
+ expect(testStruct.y).to(equal(@200));
+ expect(testStruct.width).to(equal(@2000));
+ expect(testStruct.height).to(equal(@3000));
+ });
+
+ it(@"Should return nil if not set", ^{
+ SDLRectangle *testStruct = [[SDLRectangle alloc] init];
+
+ expect(testStruct.x).to(beNil());
+ expect(testStruct.y).to(beNil());
+ expect(testStruct.width).to(beNil());
+ expect(testStruct.height).to(beNil());
+ });
+});
+
+QuickSpecEnd
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLSystemCapabilitySpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLSystemCapabilitySpec.m
index 27a7f713b..36f3c0e8e 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLSystemCapabilitySpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLSystemCapabilitySpec.m
@@ -82,12 +82,12 @@ describe(@"Initialization tests", ^{
});
it(@"should initialize correctly with initWithVideoStreamingCapability:", ^{
-
SDLImageResolution* resolution = [[SDLImageResolution alloc] init];
resolution.resolutionWidth = @600;
resolution.resolutionHeight = @500;
NSNumber *maxBitrate = @100;
+ NSNumber *hapticDataSupported = @YES;
SDLVideoStreamingFormat *format1 = [[SDLVideoStreamingFormat alloc] init];
format1.codec = SDLVideoStreamingCodecH264;
@@ -99,7 +99,7 @@ describe(@"Initialization tests", ^{
NSArray<SDLVideoStreamingFormat *> *formatArray = @[format1, format2];
- SDLVideoStreamingCapability *testVidStruct = [[SDLVideoStreamingCapability alloc] initWithVideoStreaming:resolution maxBitrate:maxBitrate supportedFormats:formatArray];
+ SDLVideoStreamingCapability *testVidStruct = [[SDLVideoStreamingCapability alloc] initWithVideoStreaming:resolution maxBitrate:maxBitrate supportedFormats:formatArray hapticDataSupported:hapticDataSupported];
SDLSystemCapability *testStruct = [[SDLSystemCapability alloc] initWithVideoStreamingCapability:testVidStruct];
expect(testStruct.systemCapabilityType).to(equal(SDLSystemCapabilityTypeVideoStreaming));
diff --git a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVideoStreamingCapabilitySpec.m b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVideoStreamingCapabilitySpec.m
index 1c1d4cee8..c977e0db7 100644
--- a/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVideoStreamingCapabilitySpec.m
+++ b/SmartDeviceLinkTests/RPCSpecs/StructSpecs/SDLVideoStreamingCapabilitySpec.m
@@ -22,12 +22,12 @@ QuickSpecBegin(SDLVideoStreamingCapabilitySpec)
describe(@"Initialization tests", ^{
it(@"Should get correctly when initialized with a dictionary", ^ {
-
SDLImageResolution* resolution = [[SDLImageResolution alloc] init];
resolution.resolutionWidth = @600;
resolution.resolutionHeight = @500;
NSNumber *maxBitrate = @100;
+ NSNumber *hapticDataSupported = @NO;
SDLVideoStreamingFormat *format1 = [[SDLVideoStreamingFormat alloc] init];
format1.codec = SDLVideoStreamingCodecH264;
@@ -41,13 +41,15 @@ describe(@"Initialization tests", ^{
NSMutableDictionary* dict = [@{SDLNamePreferredResolution: resolution,
SDLNameMaxBitrate: maxBitrate,
- SDLNameSupportedFormats: formatArray} mutableCopy];
+ SDLNameSupportedFormats: formatArray,
+ SDLNameHapticSpatialDataSupported: hapticDataSupported} mutableCopy];
SDLVideoStreamingCapability* testStruct = [[SDLVideoStreamingCapability alloc] initWithDictionary:dict];
expect(testStruct.preferredResolution).to(equal(resolution));
expect(testStruct.maxBitrate).to(equal(maxBitrate));
expect(testStruct.supportedFormats).to(equal(formatArray));
+ expect(testStruct.hapticSpatialDataSupported).to(equal(hapticDataSupported));
});
it(@"Should return nil if not set", ^ {
@@ -59,12 +61,12 @@ describe(@"Initialization tests", ^{
});
it(@"Should initialize correctly with initWithVideoStreaming:(SDLImageResolution *)preferredResolution (NSNumber *)maxBitrate (NSArray<SDLVideoStreamingFormat *> *)suportedFormats", ^ {
-
SDLImageResolution* resolution = [[SDLImageResolution alloc] init];
resolution.resolutionWidth = @600;
resolution.resolutionHeight = @500;
NSNumber *maxBitrate = @100;
+ NSNumber *hapticDataSupported = @YES;
SDLVideoStreamingFormat *format1 = [[SDLVideoStreamingFormat alloc] init];
format1.codec = SDLVideoStreamingCodecH264;
@@ -76,11 +78,12 @@ describe(@"Initialization tests", ^{
NSArray<SDLVideoStreamingFormat *> *formatArray = @[format1, format2];
- SDLVideoStreamingCapability *testStruct = [[SDLVideoStreamingCapability alloc] initWithVideoStreaming:resolution maxBitrate:maxBitrate supportedFormats:formatArray];
+ SDLVideoStreamingCapability *testStruct = [[SDLVideoStreamingCapability alloc] initWithVideoStreaming:resolution maxBitrate:maxBitrate supportedFormats:formatArray hapticDataSupported:hapticDataSupported];
expect(testStruct.preferredResolution).to(equal(resolution));
expect(testStruct.maxBitrate).to(equal(maxBitrate));
expect(testStruct.supportedFormats).to(equal(formatArray));
+ expect(testStruct.hapticSpatialDataSupported).to(equal(hapticDataSupported));
});
});
diff --git a/SmartDeviceLink_Example/Classes/ProxyManager.m b/SmartDeviceLink_Example/Classes/ProxyManager.m
index 0da979b4b..a992a043d 100644
--- a/SmartDeviceLink_Example/Classes/ProxyManager.m
+++ b/SmartDeviceLink_Example/Classes/ProxyManager.m
@@ -136,6 +136,13 @@ NS_ASSUME_NONNULL_BEGIN
show.graphic = [self.class sdlex_mainGraphicImage];
[self.sdlManager sendRequest:show];
+
+ SDLHapticRect *hapticRect = [[SDLHapticRect alloc] initWithId:1 rect:[[SDLRectangle alloc] initWithX:12.34 y:42.3 width:69 height:69]];
+ SDLSendHapticData *sendHaptic = [[SDLSendHapticData alloc] initWithHapticRectData:@[hapticRect]];
+
+ [self.sdlManager sendRequest:sendHaptic withResponseHandler:^(__kindof SDLRPCRequest * _Nullable request, __kindof SDLRPCResponse * _Nullable response, NSError * _Nullable error) {
+ NSLog(@"STOP");
+ }];
}
- (void)sdlex_setupPermissionsCallbacks {