diff options
author | Joel Fischer <joeljfischer@gmail.com> | 2017-12-19 13:48:09 -0500 |
---|---|---|
committer | Joel Fischer <joeljfischer@gmail.com> | 2017-12-19 13:48:09 -0500 |
commit | 37382e4b80ae9a8142729c5b1a492674e0dc5bb9 (patch) | |
tree | 8b083c5d47efe995ec299623689b68cf6dbfd1f4 | |
parent | 5a97adf2717df6f885acde31919c583e53c6b77b (diff) | |
parent | 11a29617004e7a114b9927374617b6ae60d7bd23 (diff) | |
download | sdl_ios-37382e4b80ae9a8142729c5b1a492674e0dc5bb9.tar.gz |
Merge branch 'develop' into feature/issue_794_CarWindow
# Conflicts:
# SmartDeviceLink-iOS.xcodeproj/project.pbxproj
# SmartDeviceLink/SDLStreamingMediaLifecycleManager.h
# SmartDeviceLink/SDLStreamingMediaLifecycleManager.m
# SmartDeviceLink/SDLStreamingMediaManager.m
# SmartDeviceLink/SmartDeviceLink.h
29 files changed, 907 insertions, 36 deletions
diff --git a/Cartfile.private b/Cartfile.private index 2b696abf7..7ef1104ea 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1,6 +1,4 @@ -# github "Quick/Quick" ~> 1.1 github "Quick/Quick" ~> 1.2 github "Quick/Nimble" ~> 7.0 -github "AliSoftware/OHHTTPStubs" ~> 6.1 github "erikdoe/ocmock" ~> 3.4 github "facebook/ios-snapshot-test-case" ~> 2.1 diff --git a/Cartfile.resolved b/Cartfile.resolved index 6832620d8..20086137a 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,4 +1,3 @@ -github "AliSoftware/OHHTTPStubs" "6.1.0" github "Quick/Nimble" "v7.0.3" github "Quick/Quick" "v1.2.0" github "erikdoe/ocmock" "v3.4.1" diff --git a/SmartDeviceLink-iOS.podspec b/SmartDeviceLink-iOS.podspec index c9cbdc708..b4fb6e61d 100644 --- a/SmartDeviceLink-iOS.podspec +++ b/SmartDeviceLink-iOS.podspec @@ -38,6 +38,9 @@ ss.public_header_files = [ 'SmartDeviceLink/SDLArtwork.h', 'SmartDeviceLink/SDLAudioPassThruCapabilities.h', 'SmartDeviceLink/SDLAudioStreamingState.h', +'SmartDeviceLink/SDLAudioStreamManager.h', +'SmartDeviceLink/SDLAudioStreamManagerDelegate.h', +'SmartDeviceLink/SDLStreamingAudioManagerType.h', 'SmartDeviceLink/SDLAudioType.h', 'SmartDeviceLink/SDLBeltStatus.h', 'SmartDeviceLink/SDLBitsPerSample.h', @@ -157,11 +160,11 @@ ss.public_header_files = [ 'SmartDeviceLink/SDLManager.h', 'SmartDeviceLink/SDLManagerDelegate.h', 'SmartDeviceLink/SDLMediaClockFormat.h', -'SmartDeviceLink/SDLModuleData.h', -'SmartDeviceLink/SDLModuleType.h', 'SmartDeviceLink/SDLMenuParams.h', 'SmartDeviceLink/SDLMetadataTags.h', 'SmartDeviceLink/SDLMetadataType.h', +'SmartDeviceLink/SDLModuleData.h', +'SmartDeviceLink/SDLModuleType.h', 'SmartDeviceLink/SDLMyKey.h', 'SmartDeviceLink/SDLNavigationCapability.h', 'SmartDeviceLink/SDLNotificationConstants.h', @@ -213,23 +216,24 @@ ss.public_header_files = [ 'SmartDeviceLink/SDLProxyListener.h', 'SmartDeviceLink/SDLPutFile.h', 'SmartDeviceLink/SDLPutFileResponse.h', +'SmartDeviceLink/SDLRadioBand.h', +'SmartDeviceLink/SDLRadioControlCapabilities.h', +'SmartDeviceLink/SDLRadioControlData.h', +'SmartDeviceLink/SDLRadioState.h', 'SmartDeviceLink/SDLReadDID.h', +'SmartDeviceLink/SDLRectangle.h', 'SmartDeviceLink/SDLReadDIDResponse.h', 'SmartDeviceLink/SDLRectangle.h', 'SmartDeviceLink/SDLRegisterAppInterface.h', 'SmartDeviceLink/SDLRegisterAppInterfaceResponse.h', +'SmartDeviceLink/SDLRemoteControlCapabilities.h', 'SmartDeviceLink/SDLRequestType.h', 'SmartDeviceLink/SDLResetGlobalProperties.h', 'SmartDeviceLink/SDLResetGlobalPropertiesResponse.h', 'SmartDeviceLink/SDLResult.h', +'SmartDeviceLink/SDLRDSData.h', 'SmartDeviceLink/SDLRPCMessage.h', 'SmartDeviceLink/SDLRPCMessageType.h', -'SmartDeviceLink/SDLRadioBand.h', -'SmartDeviceLink/SDLRadioControlCapabilities.h', -'SmartDeviceLink/SDLRadioControlData.h', -'SmartDeviceLink/SDLRadioState.h', -'SmartDeviceLink/SDLRDSData.h', -'SmartDeviceLink/SDLRemoteControlCapabilities.h', 'SmartDeviceLink/SDLRPCNotification.h', 'SmartDeviceLink/SDLRPCNotificationNotification.h', 'SmartDeviceLink/SDLRPCRequest.h', diff --git a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj index b6b728b84..c48de453e 100644 --- a/SmartDeviceLink-iOS.xcodeproj/project.pbxproj +++ b/SmartDeviceLink-iOS.xcodeproj/project.pbxproj @@ -904,6 +904,13 @@ 5D9F50811BE7E6E300FEF399 /* SDLPermissionsManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D9F50801BE7E6E300FEF399 /* SDLPermissionsManagerSpec.m */; }; 5D9F50831BEA5C6100FEF399 /* SDLFileManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D9F50821BEA5C6100FEF399 /* SDLFileManagerSpec.m */; }; 5D9F50871BED412E00FEF399 /* TestConnectionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D9F50861BED412E00FEF399 /* TestConnectionManager.m */; }; + 5D9FC29B1FD8812F00ACA5C2 /* SDLAudioStreamManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D9FC29A1FD8812E00ACA5C2 /* SDLAudioStreamManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D9FC29E1FD8813900ACA5C2 /* SDLAudioStreamManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D9FC29C1FD8813900ACA5C2 /* SDLAudioStreamManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D9FC29F1FD8813900ACA5C2 /* SDLAudioStreamManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D9FC29D1FD8813900ACA5C2 /* SDLAudioStreamManager.m */; }; + 5D9FC2A21FD8814A00ACA5C2 /* SDLAudioFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D9FC2A01FD8814A00ACA5C2 /* SDLAudioFile.m */; }; + 5D9FC2A31FD8814A00ACA5C2 /* SDLAudioFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D9FC2A11FD8814A00ACA5C2 /* SDLAudioFile.h */; }; + 5D9FC2A61FD8815800ACA5C2 /* SDLPCMAudioConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D9FC2A41FD8815800ACA5C2 /* SDLPCMAudioConverter.h */; }; + 5D9FC2A71FD8815800ACA5C2 /* SDLPCMAudioConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D9FC2A51FD8815800ACA5C2 /* SDLPCMAudioConverter.m */; }; 5D9FDA8F1F2A7D3400A495C8 /* bson_array.c in Sources */ = {isa = PBXBuildFile; fileRef = 5D9FDA891F2A7D3400A495C8 /* bson_array.c */; }; 5D9FDA901F2A7D3400A495C8 /* bson_array.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D9FDA8A1F2A7D3400A495C8 /* bson_array.h */; }; 5D9FDA911F2A7D3400A495C8 /* bson_object.c in Sources */ = {isa = PBXBuildFile; fileRef = 5D9FDA8B1F2A7D3400A495C8 /* bson_object.c */; }; @@ -1016,6 +1023,10 @@ 5DE372A41ACB336600849FAA /* SDLHMICapabilitiesSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE372A31ACB336600849FAA /* SDLHMICapabilitiesSpec.m */; }; 5DE5ABB71B0E38C90067BB02 /* SDLSystemRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D61FBD21A84238B00846EE7 /* SDLSystemRequest.h */; }; 5DE5ABB81B0E38C90067BB02 /* SDLSystemRequestResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D61FBD41A84238B00846EE7 /* SDLSystemRequestResponse.h */; }; + 5DEF695B1FD6F82D004B8C2F /* SDLStreamingAudioManagerType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DEF695A1FD6F82D004B8C2F /* SDLStreamingAudioManagerType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5DEF695D1FD6FA01004B8C2F /* testAudio.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 5DEF695C1FD6FA01004B8C2F /* testAudio.mp3 */; }; + 5DEF69611FD6FB75004B8C2F /* SDLAudioStreamManagerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DEF69601FD6FB75004B8C2F /* SDLAudioStreamManagerSpec.m */; }; + 5DEF69661FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DEF69651FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m */; }; 5DFFB9151BD7C89700DB3F04 /* SDLConnectionManagerType.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFFB9141BD7C89700DB3F04 /* SDLConnectionManagerType.h */; }; 8850DB601F4475D30053A48D /* TestMultipleFilesConnectionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8850DB5F1F4475D30053A48D /* TestMultipleFilesConnectionManager.m */; }; 8877F5EB1F34A3BE00DC128A /* SDLSendHapticDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 8877F5EA1F34A3BE00DC128A /* SDLSendHapticDataSpec.m */; }; @@ -2127,6 +2138,13 @@ 5D9F50821BEA5C6100FEF399 /* SDLFileManagerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLFileManagerSpec.m; path = DevAPISpecs/SDLFileManagerSpec.m; sourceTree = "<group>"; }; 5D9F50851BED412E00FEF399 /* TestConnectionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestConnectionManager.h; path = TestUtilities/TestConnectionManager.h; sourceTree = "<group>"; }; 5D9F50861BED412E00FEF399 /* TestConnectionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TestConnectionManager.m; path = TestUtilities/TestConnectionManager.m; sourceTree = "<group>"; }; + 5D9FC29A1FD8812E00ACA5C2 /* SDLAudioStreamManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLAudioStreamManagerDelegate.h; path = SmartDeviceLink/SDLAudioStreamManagerDelegate.h; sourceTree = SOURCE_ROOT; }; + 5D9FC29C1FD8813900ACA5C2 /* SDLAudioStreamManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLAudioStreamManager.h; path = SmartDeviceLink/SDLAudioStreamManager.h; sourceTree = SOURCE_ROOT; }; + 5D9FC29D1FD8813900ACA5C2 /* SDLAudioStreamManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLAudioStreamManager.m; path = SmartDeviceLink/SDLAudioStreamManager.m; sourceTree = SOURCE_ROOT; }; + 5D9FC2A01FD8814A00ACA5C2 /* SDLAudioFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLAudioFile.m; path = SmartDeviceLink/SDLAudioFile.m; sourceTree = SOURCE_ROOT; }; + 5D9FC2A11FD8814A00ACA5C2 /* SDLAudioFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLAudioFile.h; path = SmartDeviceLink/SDLAudioFile.h; sourceTree = SOURCE_ROOT; }; + 5D9FC2A41FD8815800ACA5C2 /* SDLPCMAudioConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDLPCMAudioConverter.h; path = SmartDeviceLink/SDLPCMAudioConverter.h; sourceTree = SOURCE_ROOT; }; + 5D9FC2A51FD8815800ACA5C2 /* SDLPCMAudioConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLPCMAudioConverter.m; path = SmartDeviceLink/SDLPCMAudioConverter.m; sourceTree = SOURCE_ROOT; }; 5D9FDA891F2A7D3400A495C8 /* bson_array.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bson_array.c; path = bson_c_lib/src/bson_array.c; sourceTree = SOURCE_ROOT; }; 5D9FDA8A1F2A7D3400A495C8 /* bson_array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bson_array.h; path = bson_c_lib/src/bson_array.h; sourceTree = SOURCE_ROOT; }; 5D9FDA8B1F2A7D3400A495C8 /* bson_object.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bson_object.c; path = bson_c_lib/src/bson_object.c; sourceTree = SOURCE_ROOT; }; @@ -2236,6 +2254,11 @@ 5DE372A01ACB2ED300849FAA /* SDLHMICapabilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHMICapabilities.m; sourceTree = "<group>"; }; 5DE372A31ACB336600849FAA /* SDLHMICapabilitiesSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLHMICapabilitiesSpec.m; sourceTree = "<group>"; }; 5DEE55BF1B8509CB004F0D0F /* SDLURLRequestTaskSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDLURLRequestTaskSpec.m; path = "UtilitiesSpecs/HTTP Connection/SDLURLRequestTaskSpec.m"; sourceTree = "<group>"; }; + 5DEF695A1FD6F82D004B8C2F /* SDLStreamingAudioManagerType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLStreamingAudioManagerType.h; sourceTree = "<group>"; }; + 5DEF695C1FD6FA01004B8C2F /* testAudio.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = testAudio.mp3; sourceTree = "<group>"; }; + 5DEF69601FD6FB75004B8C2F /* SDLAudioStreamManagerSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SDLAudioStreamManagerSpec.m; path = DevAPISpecs/SDLAudioStreamManagerSpec.m; sourceTree = "<group>"; }; + 5DEF69641FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLStreamingAudioManagerMock.h; sourceTree = "<group>"; }; + 5DEF69651FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLStreamingAudioManagerMock.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>"; }; 8850DB5E1F4475D30053A48D /* TestMultipleFilesConnectionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMultipleFilesConnectionManager.h; sourceTree = "<group>"; }; @@ -2829,6 +2852,28 @@ name = Lifecycle; sourceTree = "<group>"; }; + 5D23C9441FCF59F400002CA5 /* AudioManager */ = { + isa = PBXGroup; + children = ( + 5D9FC29C1FD8813900ACA5C2 /* SDLAudioStreamManager.h */, + 5D9FC29D1FD8813900ACA5C2 /* SDLAudioStreamManager.m */, + 5D9FC29A1FD8812E00ACA5C2 /* SDLAudioStreamManagerDelegate.h */, + 5D23C9471FCF59F400002CA5 /* Utilities */, + ); + path = AudioManager; + sourceTree = "<group>"; + }; + 5D23C9471FCF59F400002CA5 /* Utilities */ = { + isa = PBXGroup; + children = ( + 5D9FC2A41FD8815800ACA5C2 /* SDLPCMAudioConverter.h */, + 5D9FC2A51FD8815800ACA5C2 /* SDLPCMAudioConverter.m */, + 5D9FC2A11FD8814A00ACA5C2 /* SDLAudioFile.h */, + 5D9FC2A01FD8814A00ACA5C2 /* SDLAudioFile.m */, + ); + path = Utilities; + sourceTree = "<group>"; + }; 5D3E48771D6F3DA40000BFEF /* Superclass Operation */ = { isa = PBXGroup; children = ( @@ -4000,6 +4045,7 @@ 5D9F50711BE7DD4C00FEF399 /* Assets */ = { isa = PBXGroup; children = ( + 5DEF695C1FD6FA01004B8C2F /* testAudio.mp3 */, 5D850AAF1D4907C500E6E7EE /* TestLockScreenAppIcon.png */, 5D9F50721BE7DD4C00FEF399 /* testFileJSON.json */, 5D9F50731BE7DD4C00FEF399 /* testImageBMP.bmp */, @@ -4413,6 +4459,35 @@ name = "HTTP Connection"; sourceTree = "<group>"; }; + 5DEF69591FD5FE74004B8C2F /* Audio Manager */ = { + isa = PBXGroup; + children = ( + 5DEF69631FD6FEC2004B8C2F /* Mocks */, + 5DEF69601FD6FB75004B8C2F /* SDLAudioStreamManagerSpec.m */, + ); + name = "Audio Manager"; + sourceTree = "<group>"; + }; + 5DEF69621FD6FEB6004B8C2F /* Video */ = { + isa = PBXGroup; + children = ( + DA8966EE1E5693E300413EAB /* SDLStreamingMediaLifecycleManagerSpec.m */, + DABB62161E4A900C0034C567 /* SDLH264VideoEncoderSpec.m */, + EED5CA031F4D1D5E00F04000 /* SDLRAWH264PacketizerSpec.m */, + EED5CA091F4D206800F04000 /* SDLRTPH264PacketizerSpec.m */, + ); + name = Video; + sourceTree = "<group>"; + }; + 5DEF69631FD6FEC2004B8C2F /* Mocks */ = { + isa = PBXGroup; + children = ( + 5DEF69641FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.h */, + 5DEF69651FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m */, + ); + name = Mocks; + sourceTree = "<group>"; + }; 88B848C41F45E20900DED768 /* Helpers */ = { isa = PBXGroup; children = ( @@ -4439,6 +4514,7 @@ DA8966E71E56937100413EAB /* Streaming */ = { isa = PBXGroup; children = ( + 5D23C9441FCF59F400002CA5 /* AudioManager */, 5DCD7AD91FCCA5BF00A0FC7F /* CarWindow */, 5DA5918E1F96820F003264C3 /* Focus / Haptic */, DAC5724C1D0FE3B60004288B /* Touches */, @@ -4448,6 +4524,7 @@ 5D53C46B1B7A99B9003526EA /* SDLStreamingMediaManager.h */, 5D53C46C1B7A99B9003526EA /* SDLStreamingMediaManager.m */, 5D8A09801F54B4E5002502A2 /* SDLStreamingMediaManagerDataSource.h */, + 5DEF695A1FD6F82D004B8C2F /* SDLStreamingAudioManagerType.h */, ); name = Streaming; sourceTree = "<group>"; @@ -4464,11 +4541,9 @@ DA8966ED1E5693D100413EAB /* Streaming */ = { isa = PBXGroup; children = ( + 5DEF69621FD6FEB6004B8C2F /* Video */, + 5DEF69591FD5FE74004B8C2F /* Audio Manager */, DA1166D71D14601C00438CEA /* Touches */, - DA8966EE1E5693E300413EAB /* SDLStreamingMediaLifecycleManagerSpec.m */, - DABB62161E4A900C0034C567 /* SDLH264VideoEncoderSpec.m */, - EED5CA031F4D1D5E00F04000 /* SDLRAWH264PacketizerSpec.m */, - EED5CA091F4D206800F04000 /* SDLRTPH264PacketizerSpec.m */, ); name = Streaming; sourceTree = "<group>"; @@ -4545,6 +4620,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 5D9FC2A61FD8815800ACA5C2 /* SDLPCMAudioConverter.h in Headers */, 8BBEA6061F324165003EEA26 /* SDLMetadataType.h in Headers */, 5DA3F35A1BC448480026F2D0 /* SDLError.h in Headers */, 5DA3F35F1BC448590026F2D0 /* SDLNotificationConstants.h in Headers */, @@ -4589,6 +4665,7 @@ 5D61FD131A84238C00846EE7 /* SDLOnLanguageChange.h in Headers */, 5D61FDE71A84238C00846EE7 /* SDLUnsubscribeButton.h in Headers */, 5D61FCAB1A84238C00846EE7 /* SDLFuelCutoffStatus.h in Headers */, + 5D9FC2A31FD8814A00ACA5C2 /* SDLAudioFile.h in Headers */, 5DB9965C1F268F97002D8795 /* SDLControlFramePayloadVideoStartService.h in Headers */, 5D1665C81CF8CA3D00CC4CA1 /* SDLPermissionFilter.h in Headers */, E9C32B911AB20BA200F283AF /* SDLIAPSession.h in Headers */, @@ -4681,6 +4758,7 @@ 5D61FD7D1A84238C00846EE7 /* SDLScrollableMessageResponse.h in Headers */, 5D61FD431A84238C00846EE7 /* SDLProtocol.h in Headers */, 5D8B17531AC9E11B006A6E1C /* SDLDialNumberResponse.h in Headers */, + 5DEF695B1FD6F82D004B8C2F /* SDLStreamingAudioManagerType.h in Headers */, 5D61FC921A84238C00846EE7 /* SDLDisplayType.h in Headers */, 5D61FD0D1A84238C00846EE7 /* SDLOnHashChange.h in Headers */, 5D61FC6B1A84238C00846EE7 /* SDLCreateInteractionChoiceSet.h in Headers */, @@ -4711,6 +4789,7 @@ 1FF7DABA1F75B2A800B46C30 /* SDLFocusableItemLocator.h in Headers */, 5D61FC291A84238C00846EE7 /* SDLAbstractProtocol.h in Headers */, 5D61FDE11A84238C00846EE7 /* SDLTurn.h in Headers */, + 5D9FC29B1FD8812F00ACA5C2 /* SDLAudioStreamManagerDelegate.h in Headers */, 5D61FC801A84238C00846EE7 /* SDLDeleteSubMenuResponse.h in Headers */, 5D00AC731F151CFE004000D9 /* SDLGetSystemCapabilityResponse.h in Headers */, 5D61FDBD1A84238C00846EE7 /* SDLSystemContext.h in Headers */, @@ -4928,6 +5007,7 @@ 5D61FCFD1A84238C00846EE7 /* SDLObjectWithPriority.h in Headers */, DAC5726C1D11B4840004288B /* SDLTouchManagerDelegate.h in Headers */, 5D61FD3F1A84238C00846EE7 /* SDLPrioritizedObjectCollection.h in Headers */, + 5D9FC29E1FD8813900ACA5C2 /* SDLAudioStreamManager.h in Headers */, 5DD67CB01E65DDB7009CD394 /* SDLLogTargetAppleSystemLog.h in Headers */, 5D61FCBF1A84238C00846EE7 /* SDLHexUtility.h in Headers */, 5D00AC6B1F141339004000D9 /* SDLSystemCapability.h in Headers */, @@ -5051,7 +5131,7 @@ }; 5D61FA251A84237100846EE7 = { CreatedOnToolsVersion = 6.1.1; - LastSwiftMigration = 0820; + LastSwiftMigration = 0920; }; }; }; @@ -5119,6 +5199,7 @@ 5D9F507B1BE7DD4C00FEF399 /* testImageJPG.jpg in Resources */, 5D9F507C1BE7DD4C00FEF399 /* testImagePNG.png in Resources */, 5D616B461D552F7A00553F6B /* SDLLockScreen.storyboard in Resources */, + 5DEF695D1FD6FA01004B8C2F /* testAudio.mp3 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5163,6 +5244,7 @@ DA9F7E841DCC047200ACAE48 /* SDLWayPointType.m in Sources */, 5D61FC561A84238C00846EE7 /* SDLButtonName.m in Sources */, 5D61FCC21A84238C00846EE7 /* SDLHMILevel.m in Sources */, + 5D9FC2A71FD8815800ACA5C2 /* SDLPCMAudioConverter.m in Sources */, 5D61FDEC1A84238C00846EE7 /* SDLUnsubscribeVehicleData.m in Sources */, 5D61FDBE1A84238C00846EE7 /* SDLSystemContext.m in Sources */, 5D61FC441A84238C00846EE7 /* SDLAppInterfaceUnregisteredReason.m in Sources */, @@ -5174,6 +5256,7 @@ 5D61FC871A84238C00846EE7 /* SDLDeviceStatus.m in Sources */, 5D61FD561A84238C00846EE7 /* SDLPutFile.m in Sources */, 5D61FCE71A84238C00846EE7 /* SDLKeypressMode.m in Sources */, + 5D9FC29F1FD8813900ACA5C2 /* SDLAudioStreamManager.m in Sources */, 5D7F87F41CE3C29E002DD7C4 /* SDLFileWrapper.m in Sources */, 5D61FD941A84238C00846EE7 /* SDLShowConstantTBTResponse.m in Sources */, 5D61FE0A1A84238C00846EE7 /* SDLVehicleDataType.m in Sources */, @@ -5447,6 +5530,7 @@ 5D3E48761D6F3B330000BFEF /* SDLAsynchronousOperation.m in Sources */, 1E5AD06D1F208BAB0029B8AF /* SDLClimateControlData.m in Sources */, 5D61FE081A84238C00846EE7 /* SDLVehicleDataStatus.m in Sources */, + 5D9FC2A21FD8814A00ACA5C2 /* SDLAudioFile.m in Sources */, E9C32B9F1AB20C5900F283AF /* EAAccessoryManager+SDLProtocols.m in Sources */, 5D61FDA81A84238C00846EE7 /* SDLSpeakResponse.m in Sources */, 5DB92D331AC9C8BA00C15BB0 /* SDLRPCStruct.m in Sources */, @@ -5595,6 +5679,7 @@ 162E83121A9BDE8B00906325 /* SDLOnButtonPressSpec.m in Sources */, 162E838D1A9BDE8B00906325 /* SDLStartTimeSpec.m in Sources */, 162E836E1A9BDE8B00906325 /* SDLUnsubscribeButtonResponseSpec.m in Sources */, + 5DEF69611FD6FB75004B8C2F /* SDLAudioStreamManagerSpec.m in Sources */, 162E835B1A9BDE8B00906325 /* SDLPerformInteractionResponseSpec.m in Sources */, 162E832D1A9BDE8B00906325 /* SDLEncodedSyncPDataSpec.m in Sources */, 1EE8C44C1F385C7100FDC2CF /* SDLRDSDataSpec.m in Sources */, @@ -5649,6 +5734,7 @@ 1680B1161A9CD7AD00DBD79E /* SDLProtocolMessageSpec.m in Sources */, DA9F7EB21DCC084300ACAE48 /* SDLDeliveryModeSpec.m in Sources */, 162E83771A9BDE8B00906325 /* SDLClusterModeStatusSpec.m in Sources */, + 5DEF69661FD6FEF7004B8C2F /* SDLStreamingAudioManagerMock.m in Sources */, 162E83981A9BDE8B00906325 /* SDLVrHelpItemSpec.m in Sources */, 162E83831A9BDE8B00906325 /* SDLKeyboardPropertiesSpec.m in Sources */, DA9F7EA01DCC05D200ACAE48 /* SDLOnWaypointChangeSpec.m in Sources */, @@ -6250,7 +6336,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.smartdevicelink.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -6281,6 +6367,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "com.smartdevicelink.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Release; diff --git a/SmartDeviceLink.podspec b/SmartDeviceLink.podspec index f9232220b..0974d2055 100644 --- a/SmartDeviceLink.podspec +++ b/SmartDeviceLink.podspec @@ -38,6 +38,9 @@ ss.public_header_files = [ 'SmartDeviceLink/SDLArtwork.h', 'SmartDeviceLink/SDLAudioPassThruCapabilities.h', 'SmartDeviceLink/SDLAudioStreamingState.h', +'SmartDeviceLink/SDLAudioStreamManager.h', +'SmartDeviceLink/SDLAudioStreamManagerDelegate.h', +'SmartDeviceLink/SDLStreamingAudioManagerType.h', 'SmartDeviceLink/SDLAudioType.h', 'SmartDeviceLink/SDLBeltStatus.h', 'SmartDeviceLink/SDLBitsPerSample.h', diff --git a/SmartDeviceLink/SDLAudioFile.h b/SmartDeviceLink/SDLAudioFile.h new file mode 100755 index 000000000..932444945 --- /dev/null +++ b/SmartDeviceLink/SDLAudioFile.h @@ -0,0 +1,32 @@ +// +// SDLAudioFile.h +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import <SmartDeviceLink/SmartDeviceLink.h> + +NS_ASSUME_NONNULL_BEGIN + +@interface SDLAudioFile : NSObject + +@property (copy, nonatomic, readonly) NSURL *inputFileURL; + +@property (copy, nonatomic, readonly) NSURL *outputFileURL; + +/** + In seconds. UINT32_MAX if unknown. + */ +@property (assign, nonatomic) UInt32 estimatedDuration; + +@property (copy, nonatomic, readonly) NSData *data; + +@property (assign, nonatomic, readonly) unsigned long long fileSize; + +- (instancetype)initWithInputFileURL:(NSURL *)inputURL outputFileURL:(NSURL *)outputURL estimatedDuration:(UInt32)duration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLAudioFile.m b/SmartDeviceLink/SDLAudioFile.m new file mode 100755 index 000000000..1d0e2ef98 --- /dev/null +++ b/SmartDeviceLink/SDLAudioFile.m @@ -0,0 +1,62 @@ +// +// SDLAudioFile.m +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import "SDLAudioFile.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SDLAudioFile () + +@property (copy, nonatomic, readwrite) NSURL *inputFileURL; +@property (copy, nonatomic, readwrite) NSURL *outputFileURL; +@property (copy, nonatomic, readwrite) NSData *data; +@property (copy, nonatomic, readwrite) NSString *name; + +@end + +@implementation SDLAudioFile + +- (instancetype)initWithInputFileURL:(NSURL *)inputURL outputFileURL:(NSURL *)outputURL estimatedDuration:(UInt32)duration { + self = [super init]; + if (!self) { return nil; } + + _inputFileURL = inputURL; + _outputFileURL = outputURL; + _estimatedDuration = duration; + + return self; +} + +- (NSData *)data { + if (_data.length == 0) { + return [NSData dataWithContentsOfURL:_outputFileURL]; + } + + return _data; +} + +/** + Gets the size of the data. The data may be stored on disk or it may already be in the application's memory. + + @return The size of the data. + */ +- (unsigned long long)fileSize { + if (_outputFileURL != nil) { + // Data in file + NSString *path = [_outputFileURL path]; + return [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize; + } else if (_data) { + // Data in memory + return _data.length; + } + return 0; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLAudioStreamManager.h b/SmartDeviceLink/SDLAudioStreamManager.h new file mode 100755 index 000000000..1e4eb3969 --- /dev/null +++ b/SmartDeviceLink/SDLAudioStreamManager.h @@ -0,0 +1,60 @@ +// +// SDLBinaryAudioManager.h +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@class SDLAudioFile; +@class SDLManager; +@class SDLStreamingMediaLifecycleManager; +@protocol SDLStreamingAudioManagerType; +@protocol SDLAudioStreamManagerDelegate; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const SDLErrorDomainAudioStreamManager; + +typedef NS_ENUM(NSInteger, SDLAudioStreamManagerError) { + SDLAudioStreamManagerErrorNotConnected = -1, + SDLAudioStreamManagerErrorNoQueuedAudio = -2 +}; + +@interface SDLAudioStreamManager : NSObject + +@property (weak, nonatomic) id<SDLAudioStreamManagerDelegate> delegate; + +@property (assign, nonatomic, readonly, getter=isPlaying) BOOL playing; +@property (copy, nonatomic, readonly) NSArray<SDLAudioFile *> *queue; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithManager:(id<SDLStreamingAudioManagerType>)streamManager NS_DESIGNATED_INITIALIZER; + +/** + Push a new file URL onto the queue after converting it into the correct PCM format for streaming binary data. Call `playNextWhenReady` to start playing the next completed pushed file. + + @note This happens on a serial background thread and will provide an error callback using the delegate if the conversion fails. + + @param fileURL File URL to convert + */ +- (void)pushWithFileURL:(NSURL *)fileURL; + +/** + Play the next item in the queue. If an item is currently playing, it will continue playing and this item will begin playing after it is completed. + + When complete, this will callback on the delegate. + */ +- (void)playNextWhenReady; + +/** + Stop playing the queue after the current item completes and clear the queue. If nothing is playing, the queue will be cleared. + */ +- (void)stop; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLAudioStreamManager.m b/SmartDeviceLink/SDLAudioStreamManager.m new file mode 100755 index 000000000..654f2451b --- /dev/null +++ b/SmartDeviceLink/SDLAudioStreamManager.m @@ -0,0 +1,136 @@ +// +// SDLBinaryAudioManager.m +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import "SDLAudioStreamManager.h" + +#import "SDLAudioFile.h" +#import "SDLLogMacros.h" +#import "SDLManager.h" +#import "SDLPCMAudioConverter.h" +#import "SDLAudioStreamManagerDelegate.h" +#import "SDLStreamingAudioManagerType.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const SDLErrorDomainAudioStreamManager = @"com.sdl.extension.pcmAudioStreamManager"; + +@interface SDLAudioStreamManager () + +@property (weak, nonatomic) id<SDLStreamingAudioManagerType> streamManager; +@property (strong, nonatomic) NSMutableArray<SDLAudioFile *> *mutableQueue; +@property (strong, nonatomic) dispatch_queue_t audioQueue; +@property (assign, nonatomic, readwrite, getter=isPlaying) BOOL playing; + +@property (assign, nonatomic) BOOL shouldPlayWhenReady; + +@end + +@implementation SDLAudioStreamManager + +- (instancetype)initWithManager:(id<SDLStreamingAudioManagerType>)streamManager { + self = [super init]; + if (!self) { return nil; } + + _mutableQueue = [NSMutableArray array]; + _audioQueue = dispatch_queue_create("com.sdl.audiomanager.transcode", DISPATCH_QUEUE_SERIAL); + _shouldPlayWhenReady = NO; + + _streamManager = streamManager; + + return self; +} + +- (NSArray<SDLFile *> *)queue { + return [_mutableQueue copy]; +} + +- (void)pushWithFileURL:(NSURL *)fileURL { + dispatch_async(_audioQueue, ^{ + [self sdl_pushWithContentsOfURL:fileURL]; + }); +} + +- (void)sdl_pushWithContentsOfURL:(NSURL *)fileURL { + // Convert and store in the queue + NSError *error = nil; + SDLPCMAudioConverter *converter = [[SDLPCMAudioConverter alloc] initWithFileURL:fileURL]; + NSURL *_Nullable outputFileURL = [converter convertFileWithError:&error]; + UInt32 estimatedDuration = converter.estimatedDuration; + + if (outputFileURL == nil) { + SDLLogE(@"Error converting file to CAF / PCM: %@", error); + if (self.delegate != nil) { + [self.delegate audioStreamManager:self errorDidOccurForFile:fileURL error:error]; + } + return; + } + + SDLAudioFile *audioFile = [[SDLAudioFile alloc] initWithInputFileURL:fileURL outputFileURL:outputFileURL estimatedDuration:estimatedDuration]; + [self.mutableQueue addObject:audioFile]; + + if (self.shouldPlayWhenReady) { + [self sdl_playNextWhenReady]; + } +} + +- (void)playNextWhenReady { + dispatch_async(_audioQueue, ^{ + [self sdl_playNextWhenReady]; + }); +} + +- (void)sdl_playNextWhenReady { + if (self.mutableQueue.count == 0) { + self.shouldPlayWhenReady = YES; + return; + } + + if (!self.streamManager.isAudioConnected) { + if (self.delegate != nil) { + NSError *error = [NSError errorWithDomain:SDLErrorDomainAudioStreamManager code:SDLAudioStreamManagerErrorNotConnected userInfo:nil]; + [self.delegate audioStreamManager:self errorDidOccurForFile:self.mutableQueue.firstObject.inputFileURL error:error]; + } + return; + } + + self.shouldPlayWhenReady = NO; + __block SDLAudioFile *file = self.mutableQueue.firstObject; + [self.mutableQueue removeObjectAtIndex:0]; + + // Strip the first bunch of bytes (because of how Apple outputs the data) and send to the audio stream, if we don't do this, it will make a weird click sound + SDLLogD(@"Playing audio file: %@", file); + NSData *audioData = [file.data subdataWithRange:NSMakeRange(5760, (file.data.length - 5760))]; + __block BOOL success = [self.streamManager sendAudioData:audioData]; + self.playing = YES; + + float audioLengthSecs = (float)audioData.length / (float)32000.0; + __weak typeof(self) weakself = self; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(audioLengthSecs * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + weakself.playing = NO; + NSError *error = nil; + if (weakself.delegate != nil) { + [weakself.delegate audioStreamManager:weakself fileDidFinishPlaying:file.inputFileURL successfully:success]; + } + SDLLogD(@"Ending Audio file: %@", file); + [[NSFileManager defaultManager] removeItemAtURL:file.outputFileURL error:&error]; + if (weakself.delegate != nil && error != nil) { + [weakself.delegate audioStreamManager:weakself errorDidOccurForFile:file.inputFileURL error:error]; + } + }); +} + +- (void)stop { + dispatch_async(_audioQueue, ^{ + self.shouldPlayWhenReady = NO; + [self.mutableQueue removeAllObjects]; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLAudioStreamManagerDelegate.h b/SmartDeviceLink/SDLAudioStreamManagerDelegate.h new file mode 100755 index 000000000..f1fdb781a --- /dev/null +++ b/SmartDeviceLink/SDLAudioStreamManagerDelegate.h @@ -0,0 +1,24 @@ +// +// SDLBinaryAudioQueueDelegate.h +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@class SDLAudioFile; +@class SDLAudioStreamManager; + +NS_ASSUME_NONNULL_BEGIN + +@protocol SDLAudioStreamManagerDelegate <NSObject> + +@required +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager fileDidFinishPlaying:(NSURL *)fileURL successfully:(BOOL)successfully; +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForFile:(NSURL *)fileURL error:(NSError *)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLManager.m b/SmartDeviceLink/SDLManager.m index 9e36f7951..fa982a51b 100644 --- a/SmartDeviceLink/SDLManager.m +++ b/SmartDeviceLink/SDLManager.m @@ -2,15 +2,17 @@ #import <Foundation/Foundation.h> -#import "SmartDeviceLink.h" - #import "SDLManager.h" #import "NSMapTable+Subscripting.h" +#import "SDLConfiguration.h" #import "SDLConnectionManagerType.h" +#import "SDLLifecycleConfiguration.h" #import "SDLLifecycleManager.h" +#import "SDLLockScreenConfiguration.h" #import "SDLLockScreenManager.h" #import "SDLLockScreenPresenter.h" +#import "SDLLogConfiguration.h" #import "SDLManagerDelegate.h" #import "SDLNotificationDispatcher.h" #import "SDLResponseDispatcher.h" diff --git a/SmartDeviceLink/SDLPCMAudioConverter.h b/SmartDeviceLink/SDLPCMAudioConverter.h new file mode 100755 index 000000000..abd1a880a --- /dev/null +++ b/SmartDeviceLink/SDLPCMAudioConverter.h @@ -0,0 +1,31 @@ +// +// SDLPCMAudioConverter.h +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const SDLErrorDomainPCMAudioStreamConverter; + +@interface SDLPCMAudioConverter : NSObject + +@property (assign, nonatomic, readonly) UInt32 estimatedDuration; + +- (nullable instancetype)initWithFileURL:(NSURL *)fileURL; + +/** + Synchronously convert the file that it was init'd with, returning an error if it fails and the NSURL of the new file if it succeeds + + @param error An error object containing the OSStatus if it failed to convert + @return The NSURL of the newly converted file + */ +- (nullable NSURL *)convertFileWithError:(NSError *__autoreleasing *)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLPCMAudioConverter.m b/SmartDeviceLink/SDLPCMAudioConverter.m new file mode 100755 index 000000000..454ecdebb --- /dev/null +++ b/SmartDeviceLink/SDLPCMAudioConverter.m @@ -0,0 +1,205 @@ +// +// SDLPCMAudioConverter.m +// SmartDeviceLink-Example +// +// Created by Joel Fischer on 10/24/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#include <AudioToolbox/AudioToolbox.h> + +#import "SDLLogMacros.h" +#import "SDLPCMAudioConverter.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString *const SDLErrorDomainPCMAudioStreamConverter = @"com.sdl.extension.pcmAudioStreamManager.converter"; + +@interface SDLPCMAudioConverter() + +@property (copy, nonatomic) NSURL *inputFileURL; +@property (assign, nonatomic) UInt32 estimatedDuration; + +@end + +@implementation SDLPCMAudioConverter + +- (nullable instancetype)initWithFileURL:(NSURL *)inputFileURL { + self = [self init]; + if (!self) return nil; + + if (!inputFileURL.isFileURL) { + return nil; + } + + _inputFileURL = inputFileURL; + _estimatedDuration = UINT32_MAX; + + return self; +} + +- (nullable NSURL *)convertFileWithError:(NSError *__autoreleasing *)error { + if (NSTemporaryDirectory() == nil) { + // We can't write to disk for some reason + return nil; + } + + CFURLRef inputFileURL = (__bridge CFURLRef)_inputFileURL; + NSURL *outputURL = [[[NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES] URLByAppendingPathComponent:[NSUUID UUID].UUIDString] URLByAppendingPathExtension:@"caf"]; + CFURLRef outputFileURL = (__bridge CFURLRef)outputURL; + ExtAudioFileRef infile, outfile = 0; + + // Open the input file + OSStatus err = ExtAudioFileOpenURL(inputFileURL, &infile); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:@{@"type": @"ExtAudioFileOpenURL"}]; + } + return nil; + } + + AudioStreamBasicDescription inputFormat = {}; + UInt32 size = sizeof(inputFormat); + err = ExtAudioFileGetProperty(infile, kExtAudioFileProperty_FileDataFormat, &size, &inputFormat); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:@{@"type": @"kExtAudioFileProperty_FileDataFormat"}]; + } + return nil; + } + + SDLLogD(@"PCM Converter input format"); + [self.class printAudioStreamBasicDescription:inputFormat]; + + // create the output file (this will erase an existing file) + AudioStreamBasicDescription outputFormat = [self.class outputFormat]; + SDLLogD(@"PCM Converter output format"); + [self.class printAudioStreamBasicDescription:outputFormat]; + err = ExtAudioFileCreateWithURL(outputFileURL, kAudioFileCAFType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &outfile); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:@{@"type": @"ExtAudioFileCreateWithURL"}]; + } + return nil; + } + + // get and set the client format - it should be lpcm + AudioStreamBasicDescription clientFormat = (inputFormat.mFormatID == kAudioFormatLinearPCM ? inputFormat : outputFormat); + size = sizeof(clientFormat); + err = ExtAudioFileSetProperty(infile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:@{@"type": @"kExtAudioFileProperty_ClientDataFormat"}]; + } + return nil; + } + + size = sizeof(clientFormat); + err = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:@{@"type": @"kExtAudioFileProperty_ClientDataFormat"}]; + } + return nil; + } + + AudioConverterRef outConverter; + size = sizeof(outConverter); + err = ExtAudioFileGetProperty(outfile, kExtAudioFileProperty_AudioConverter, &size, &outConverter); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:@{@"type": @"kExtAudioFileProperty_AudioConverter"}]; + } + return nil; + } + + // set up buffers + const UInt32 kSrcBufSize = 32768; + char srcBuffer[kSrcBufSize]; + + // do the read and write - the conversion is done on and by the write call + while (1) { + AudioBufferList fillBufList; + fillBufList.mNumberBuffers = 1; + fillBufList.mBuffers[0].mNumberChannels = inputFormat.mChannelsPerFrame; + fillBufList.mBuffers[0].mDataByteSize = kSrcBufSize; + fillBufList.mBuffers[0].mData = srcBuffer; + + // client format is always linear PCM - so here we determine how many frames of lpcm + // we can read/write given our buffer size + UInt32 numFrames = (kSrcBufSize / clientFormat.mBytesPerFrame); + + err = ExtAudioFileRead(infile, &numFrames, &fillBufList); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:nil]; + } + return nil; + } + + // this is our termination condition + if (!numFrames) { break; } + + err = ExtAudioFileWrite(outfile, numFrames, &fillBufList); + if (err != noErr) { + if (*error != nil) { + *error = [NSError errorWithDomain:SDLErrorDomainPCMAudioStreamConverter code:err userInfo:nil]; + } + return nil; + } + } + + _estimatedDuration = [self estimatedDurationForFileRef:outfile]; + + // close + ExtAudioFileDispose(outfile); + ExtAudioFileDispose(infile); + + // TODO: If error + return outputURL; +} + +- (UInt32)estimatedDurationForFileRef:(ExtAudioFileRef)fileRef { + UInt32 estimatedDuration = 0; + UInt32 size = sizeof(estimatedDuration); + OSStatus err = ExtAudioFileGetProperty(fileRef, kAudioFilePropertyEstimatedDuration, &size, &estimatedDuration); + if (err != noErr) { + SDLLogW(@"Could not get estimated duration for file ref"); + return UINT32_MAX; + } + + return estimatedDuration; +} + ++ (AudioStreamBasicDescription)outputFormat { + AudioStreamBasicDescription outputFormat; + outputFormat.mSampleRate = 16000; + outputFormat.mFormatID = kAudioFormatLinearPCM; + outputFormat.mChannelsPerFrame = 1; + outputFormat.mBitsPerChannel = 16; + outputFormat.mBytesPerPacket = (outputFormat.mBitsPerChannel / 8); + outputFormat.mFramesPerPacket = 1; + outputFormat.mBytesPerFrame = outputFormat.mBytesPerPacket; + outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + + return outputFormat; +} + ++ (void)printAudioStreamBasicDescription:(AudioStreamBasicDescription)asbd { + char formatID[5]; + UInt32 mFormatID = CFSwapInt32HostToBig(asbd.mFormatID); + bcopy (&mFormatID, formatID, 4); + formatID[4] = '\0'; + SDLLogD(@"Sample Rate: %10.0f\n" + "Format ID: %10s\n" + "Format Flags: %10X\n" + "Bytes per Packet: %10d\n" + "Frames per Packet: %10d\n" + "Bytes per Frame: %10d\n" + "Channels per Frame: %10d\n" + "Bits per Channel: %10d\n", asbd.mSampleRate, formatID, (unsigned int)asbd.mFormatFlags, (unsigned int)asbd.mBytesPerPacket, (unsigned int)asbd.mFramesPerPacket, (unsigned int)asbd.mBytesPerFrame, (unsigned int)asbd.mChannelsPerFrame, (unsigned int)asbd.mBitsPerChannel); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLStreamingAudioManagerType.h b/SmartDeviceLink/SDLStreamingAudioManagerType.h new file mode 100644 index 000000000..5d3771881 --- /dev/null +++ b/SmartDeviceLink/SDLStreamingAudioManagerType.h @@ -0,0 +1,17 @@ +// +// SDLStreamingAudioManagerType.h +// SmartDeviceLink +// +// Created by Joel Fischer on 12/5/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@protocol SDLStreamingAudioManagerType <NSObject> + +@property (assign, nonatomic, readonly, getter=isAudioConnected) BOOL audioConnected; + +- (BOOL)sendAudioData:(NSData *)audioData; + +@end diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h index ab49e368a..008cb2a01 100644 --- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h +++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.h @@ -12,9 +12,11 @@ #import "SDLConnectionManagerType.h" #import "SDLHMILevel.h" #import "SDLProtocolListener.h" +#import "SDLStreamingAudioManagerType.h" #import "SDLStreamingMediaManagerConstants.h" @class SDLAbstractProtocol; +@class SDLAudioStreamManager; @class SDLCarWindow; @class SDLImageResolution; @class SDLStateMachine; @@ -46,7 +48,7 @@ extern SDLAudioStreamState *const SDLAudioStreamStateShuttingDown; #pragma mark - Interface -@interface SDLStreamingMediaLifecycleManager : NSObject <SDLProtocolListener> +@interface SDLStreamingMediaLifecycleManager : NSObject <SDLProtocolListener, SDLStreamingAudioManagerType> @property (strong, nonatomic, readonly) SDLStateMachine *appStateMachine; @property (strong, nonatomic, readonly) SDLStateMachine *videoStreamStateMachine; @@ -65,8 +67,8 @@ extern SDLAudioStreamState *const SDLAudioStreamStateShuttingDown; */ @property (nonatomic, strong, readonly) SDLTouchManager *touchManager; +@property (nonatomic, strong, readonly) SDLAudioStreamManager *audioManager; @property (nonatomic, strong) UIViewController *rootViewController; - @property (strong, nonatomic, readonly, nullable) SDLCarWindow *carWindow; /** diff --git a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m index ffae34e4d..00c8b4bfc 100644 --- a/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m +++ b/SmartDeviceLink/SDLStreamingMediaLifecycleManager.m @@ -9,6 +9,7 @@ #import "SDLStreamingMediaLifecycleManager.h" #import "SDLAbstractProtocol.h" +#import "SDLAudioStreamManager.h" #import "SDLCarWindow.h" #import "SDLControlFramePayloadAudioStartServiceAck.h" #import "SDLControlFramePayloadConstants.h" @@ -126,6 +127,7 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N } _touchManager = [[SDLTouchManager alloc] initWithHitTester:(id)_focusableItemManager]; + _audioManager = [[SDLAudioStreamManager alloc] initWithManager:self]; _requestedEncryptionType = configuration.maximumDesiredEncryption; _dataSource = configuration.dataSource; @@ -838,7 +840,7 @@ typedef void(^SDLVideoCapabilityResponseHandler)(SDLVideoStreamingCapability *_N } - (BOOL)isHmiStateAudioStreamCapable { - return YES; + return ![self.hmiLevel isEqualToEnum:SDLHMILevelNone]; } - (BOOL)isHmiStateVideoStreamCapable { diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h index a22d67793..76f4ab8a2 100644 --- a/SmartDeviceLink/SDLStreamingMediaManager.h +++ b/SmartDeviceLink/SDLStreamingMediaManager.h @@ -9,9 +9,11 @@ #import <Foundation/Foundation.h> #import <VideoToolbox/VideoToolbox.h> +#import "SDLStreamingAudioManagerType.h" #import "SDLStreamingMediaManagerConstants.h" @class SDLAbstractProtocol; +@class SDLAudioStreamManager; @class SDLStreamingMediaConfiguration; @class SDLTouchManager; @class SDLVideoStreamingFormat; @@ -23,13 +25,15 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Interface -@interface SDLStreamingMediaManager : NSObject +@interface SDLStreamingMediaManager : NSObject <SDLStreamingAudioManagerType> /** * Touch Manager responsible for providing touch event notifications. */ @property (nonatomic, strong, readonly) SDLTouchManager *touchManager; +@property (nonatomic, strong, readonly) SDLAudioStreamManager *audioManager; + /** This property is used for SDLCarWindow, the ability to stream any view controller. To start, you must set an initial view controller on `SDLStreamingMediaConfiguration` `rootViewController`. After streaming begins, you can replace that view controller with a new root by placing the new view controller into this property. */ diff --git a/SmartDeviceLink/SDLStreamingMediaManager.m b/SmartDeviceLink/SDLStreamingMediaManager.m index f439ebd0f..4a0b08b28 100644 --- a/SmartDeviceLink/SDLStreamingMediaManager.m +++ b/SmartDeviceLink/SDLStreamingMediaManager.m @@ -8,6 +8,7 @@ #import "SDLStreamingMediaManager.h" +#import "SDLAudioStreamManager.h" #import "SDLConnectionManagerType.h" #import "SDLStreamingMediaConfiguration.h" #import "SDLStreamingMediaManagerDataSource.h" @@ -67,6 +68,10 @@ NS_ASSUME_NONNULL_BEGIN return self.lifecycleManager.touchManager; } +- (SDLAudioStreamManager *)audioManager { + return self.lifecycleManager.audioManager; +} + - (UIViewController *)rootViewController { return self.lifecycleManager.rootViewController; } diff --git a/SmartDeviceLink/SmartDeviceLink.h b/SmartDeviceLink/SmartDeviceLink.h index 1e02a0a19..f992275c1 100644 --- a/SmartDeviceLink/SmartDeviceLink.h +++ b/SmartDeviceLink/SmartDeviceLink.h @@ -318,6 +318,16 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[]; #import "SDLLockScreenConfiguration.h" #import "SDLStreamingMediaConfiguration.h" +// Streaming +#import "SDLAudioStreamManager.h" +#import "SDLAudioStreamManagerDelegate.h" +#import "SDLCarWindowViewController.h" +#import "SDLStreamingAudioManagerType.h" +#import "SDLStreamingMediaManager.h" +#import "SDLTouchManager.h" +#import "SDLTouchManagerDelegate.h" +#import "SDLSecurityType.h" + // Files #import "SDLArtwork.h" #import "SDLFile.h" @@ -335,13 +345,6 @@ FOUNDATION_EXPORT const unsigned char SmartDeviceLinkVersionString[]; #import "SDLPermissionConstants.h" #import "SDLPermissionManager.h" -// Streaming -#import "SDLCarWindowViewController.h" -#import "SDLSecurityType.h" -#import "SDLStreamingMediaManager.h" -#import "SDLTouchManager.h" -#import "SDLTouchManagerDelegate.h" - // Touches #import "SDLPinchGesture.h" #import "SDLTouch.h" diff --git a/SmartDeviceLinkTests/Assets/testAudio.mp3 b/SmartDeviceLinkTests/Assets/testAudio.mp3 Binary files differnew file mode 100644 index 000000000..4be1bc45c --- /dev/null +++ b/SmartDeviceLinkTests/Assets/testAudio.mp3 diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m new file mode 100644 index 000000000..a087ecb5a --- /dev/null +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m @@ -0,0 +1,89 @@ +#import <Quick/Quick.h> +#import <Nimble/Nimble.h> + +#import "SDLAudioStreamManager.h" +#import "SDLStreamingAudioManagerMock.h" + +QuickSpecBegin(SDLAudioStreamManagerSpec) + +describe(@"the audio stream manager", ^{ + __block SDLAudioStreamManager *testManager = nil; + __block SDLStreamingAudioManagerMock *mockAudioManager = nil; + __block NSURL *testAudioFileURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"testAudio" withExtension:@"mp3"]; + + beforeEach(^{ + mockAudioManager = [[SDLStreamingAudioManagerMock alloc] init]; + testManager = [[SDLAudioStreamManager alloc] initWithManager:mockAudioManager]; + testManager.delegate = mockAudioManager; + }); + + it(@"should have proper initial vars", ^{ + expect(testManager.delegate).toNot(beNil()); + expect(testManager.playing).to(beFalse()); + expect(testManager.queue).to(beEmpty()); + + // Also just double check that we actually have a URL + expect(testAudioFileURL).toNot(beNil()); + }); + + describe(@"when audio streaming is not connected", ^{ + beforeEach(^{ + mockAudioManager.audioConnected = NO; + [testManager pushWithFileURL:testAudioFileURL]; + + [NSThread sleepForTimeInterval:0.5]; + }); + + describe(@"after attempting to play the file", ^{ + beforeEach(^{ + [mockAudioManager clearData]; + [testManager playNextWhenReady]; + }); + + it(@"should fail to send data", ^{ + expect(mockAudioManager.dataSinceClear.length).to(equal(0)); + expect(mockAudioManager.fileError.code).to(equal(SDLAudioStreamManagerErrorNotConnected)); + }); + }); + }); + + describe(@"after adding an audio file to the queue", ^{ + beforeEach(^{ + mockAudioManager.audioConnected = YES; + [testManager pushWithFileURL:testAudioFileURL]; + + [NSThread sleepForTimeInterval:0.5]; + }); + + it(@"should have a file in the queue", ^{ + expect(testManager.queue).toNot(beEmpty()); + }); + + describe(@"after attempting to play the file", ^{ + beforeEach(^{ + [mockAudioManager clearData]; + [testManager playNextWhenReady]; + }); + + it(@"should be sending data", ^{ + expect(testManager.isPlaying).toEventually(beTrue()); + expect(mockAudioManager.dataSinceClear.length).toEventually(equal(34380)); + + // Fails when it shouldn't, `weakself` goes to nil in `sdl_playNextWhenReady` +// expect(mockAudioManager.fileFinishedPlaying).toEventually(beTrue()); + }); + }); + + describe(@"after stopping the manager", ^{ + beforeEach(^{ + [testManager stop]; + }); + + it(@"should have an empty queue", ^{ + expect(testManager.queue).to(beEmpty()); + }); + }); + }); +}); + +QuickSpecEnd diff --git a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testAppAndVehicleIcons@2x.png b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testAppAndVehicleIcons@2x.png Binary files differindex fb6f87fba..bef5354d6 100644 --- a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testAppAndVehicleIcons@2x.png +++ b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testAppAndVehicleIcons@2x.png diff --git a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testLightBackgroundNoAppNoVehicleIcons@2x.png b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testLightBackgroundNoAppNoVehicleIcons@2x.png Binary files differindex 0830ec96c..7c3972fd4 100644 --- a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testLightBackgroundNoAppNoVehicleIcons@2x.png +++ b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testLightBackgroundNoAppNoVehicleIcons@2x.png diff --git a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testNoAppNoVehicleIcons@2x.png b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testNoAppNoVehicleIcons@2x.png Binary files differindex ea74dd949..b6bca2f99 100644 --- a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testNoAppNoVehicleIcons@2x.png +++ b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testNoAppNoVehicleIcons@2x.png diff --git a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyAppIcon@2x.png b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyAppIcon@2x.png Binary files differindex 6b242fb84..2081fcdcc 100644 --- a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyAppIcon@2x.png +++ b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyAppIcon@2x.png diff --git a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyVehicleIcon@2x.png b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyVehicleIcon@2x.png Binary files differindex 1e4539141..d83c4e6dc 100644 --- a/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyVehicleIcon@2x.png +++ b/SmartDeviceLinkTests/ReferenceImages_64/SDLLockScreenViewControllerSnapshotTests/testOnlyVehicleIcon@2x.png diff --git a/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h new file mode 100644 index 000000000..2717798a5 --- /dev/null +++ b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h @@ -0,0 +1,33 @@ +// +// SDLStreamingAudioManagerMock.h +// SmartDeviceLinkTests +// +// Created by Joel Fischer on 12/5/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import <Foundation/Foundation.h> + +#import "SDLAudioStreamManagerDelegate.h" +#import "SDLStreamingAudioManagerType.h" + +@interface SDLStreamingAudioManagerMock : NSObject <SDLStreamingAudioManagerType, SDLAudioStreamManagerDelegate> + +@property (copy, nonatomic, readonly) NSData *dataSinceClear; +@property (strong, nonatomic) NSData *lastSentData; + +- (void)clearData; + +#pragma mark SDLStreamingAudioManagerType +@property (assign, nonatomic, readonly, getter=isAudioConnected) BOOL audioConnected; +- (BOOL)sendAudioData:(NSData *)audioData; + +- (void)setAudioConnected:(BOOL)audioConnected; + +#pragma mark SDLAudioStreamManagerDelegate +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager fileDidFinishPlaying:(SDLAudioFile *)file successfully:(BOOL)successfully; +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForFile:(SDLAudioFile *)file error:(NSError *)error; +@property (assign, nonatomic, readonly) BOOL fileFinishedPlaying; +@property (strong, nonatomic, readonly) NSError *fileError; + +@end diff --git a/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m new file mode 100644 index 000000000..21d1d8732 --- /dev/null +++ b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m @@ -0,0 +1,72 @@ +// +// SDLStreamingAudioManagerMock.m +// SmartDeviceLinkTests +// +// Created by Joel Fischer on 12/5/17. +// Copyright © 2017 smartdevicelink. All rights reserved. +// + +#import "SDLStreamingAudioManagerMock.h" + +@interface SDLStreamingAudioManagerMock() + +@property (assign, nonatomic, readwrite, getter=isAudioConnected) BOOL audioConnected; + +@property (strong, nonatomic) NSMutableData *mutableDataSinceClear; + +@property (assign, nonatomic, readwrite) BOOL fileFinishedPlaying; +@property (strong, nonatomic, readwrite) NSError *fileError; + +@end + +@implementation SDLStreamingAudioManagerMock + +- (instancetype)init { + self = [super init]; + if (!self) { return nil; } + + _lastSentData = nil; + _mutableDataSinceClear = nil; + + return self; +} + +- (void)clearData { + _lastSentData = nil; + _mutableDataSinceClear = nil; + + _fileFinishedPlaying = NO; + _fileError = nil; +} + +#pragma mark SDLStreamingAudioManagerType +- (NSData *)dataSinceClear { + return [_mutableDataSinceClear copy]; +} + +- (BOOL)sendAudioData:(NSData *)audioData { + _lastSentData = audioData; + + if (_mutableDataSinceClear == nil) { + _mutableDataSinceClear = [audioData mutableCopy]; + } else { + [_mutableDataSinceClear appendData:audioData]; + } + + return YES; +} + +- (void)setAudioConnected:(BOOL)audioConnected { + _audioConnected = audioConnected; +} + +#pragma mark SDLAudioStreamManagerDelegate +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager fileDidFinishPlaying:(SDLAudioFile *)file successfully:(BOOL)successfully { + _fileFinishedPlaying = successfully; +} + +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForFile:(SDLAudioFile *)file error:(NSError *)error { + _fileError = error; +} + +@end diff --git a/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m b/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m index 616454d97..e1487076a 100644 --- a/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m +++ b/SmartDeviceLinkTests/SDLStreamingMediaLifecycleManagerSpec.m @@ -75,6 +75,7 @@ describe(@"the streaming media manager", ^{ it(@"should initialize properties", ^{ expect(streamingLifecycleManager.touchManager).toNot(beNil()); expect(streamingLifecycleManager.focusableItemManager).toNot(beNil()); + expect(streamingLifecycleManager.audioManager).toNot(beNil()); expect(@(streamingLifecycleManager.isStreamingSupported)).to(equal(@NO)); expect(@(streamingLifecycleManager.isVideoConnected)).to(equal(@NO)); expect(@(streamingLifecycleManager.isAudioConnected)).to(equal(@NO)); @@ -208,8 +209,8 @@ describe(@"the streaming media manager", ^{ sendNotificationForHMILevel(SDLHMILevelNone); }); - it(@"should close only the video stream", ^{ - expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady)); + it(@"should close both streams", ^{ + expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateShuttingDown)); expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown)); }); }); @@ -273,8 +274,8 @@ describe(@"the streaming media manager", ^{ sendNotificationForHMILevel(SDLHMILevelNone); }); - it(@"should close only the video stream", ^{ - expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateReady)); + it(@"should close both streams", ^{ + expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateShuttingDown)); expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateShuttingDown)); }); }); @@ -330,8 +331,8 @@ describe(@"the streaming media manager", ^{ sendNotificationForHMILevel(SDLHMILevelNone); }); - it(@"should only start the audio stream", ^{ - expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStarting)); + it(@"should not start either stream", ^{ + expect(streamingLifecycleManager.currentAudioStreamState).to(equal(SDLAudioStreamStateStopped)); expect(streamingLifecycleManager.currentVideoStreamState).to(equal(SDLVideoStreamStateStopped)); }); }); |