diff --git a/AUTHORS b/AUTHORS index 10cfacd141..135b64cca9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -997,6 +997,9 @@ Developers: jagd Added setSubsteps() and getSubsteps() in PhysicsWorld + + denpen + Fixed a bug that scroll view hidden picks up the touch events. Retired Core Developers: WenSheng Yang diff --git a/CHANGELOG b/CHANGELOG index d64df950a5..84aed66e37 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ cocos2d-x-3.3?? ?? [NEW] ActionManager: added removeAllActionsByTag() + [NEW] Audio: added new audio system for iOS and Android [NEW] GLViewProtocol: added getAllTouches() [NEW] Node: added stopAllActionsByTag() [NEW] PhysicsWorld: add setSubsteps() and getSubsteps() @@ -13,6 +14,7 @@ cocos2d-x-3.3?? ?? [FIX] Node: create unneeded temple `Vec2` object in `setPosition(int, int)`, `setPositionX()` and `setPositionY()` [FIX] Node: skew effect is wrong [FIX] Node: setNormalizedPosition can not take effect if parent position is not changed + [FIX] External: ScrollView: scroll view hidden picks up the touch events [FIX] TextureAtlas: may crash if only drawing part of it cocos2d-x-3.3alpha0 Aug.28 2014 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fcc2753a1..2550a3d7b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ # ****************************************************************************/ cmake_minimum_required(VERSION 2.8) -project (Cocos2dx) +project (Cocos2d-X) # The version number set(COCOS2D_X_VERSION 3.3.0) diff --git a/build/cocos2d_libs.xcodeproj/project.pbxproj b/build/cocos2d_libs.xcodeproj/project.pbxproj index 5feb80ef5c..eb33637bf1 100644 --- a/build/cocos2d_libs.xcodeproj/project.pbxproj +++ b/build/cocos2d_libs.xcodeproj/project.pbxproj @@ -1267,6 +1267,14 @@ 299CF1FC19A434BC00C378C1 /* ccRandom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 299CF1F919A434BC00C378C1 /* ccRandom.cpp */; }; 299CF1FD19A434BC00C378C1 /* ccRandom.h in Headers */ = {isa = PBXBuildFile; fileRef = 299CF1FA19A434BC00C378C1 /* ccRandom.h */; }; 299CF1FE19A434BC00C378C1 /* ccRandom.h in Headers */ = {isa = PBXBuildFile; fileRef = 299CF1FA19A434BC00C378C1 /* ccRandom.h */; }; + 3E2BDADE19C030ED0055CDCD /* AudioEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E2BDADD19C030ED0055CDCD /* AudioEngine.h */; }; + 3E2BDAE519C0329B0055CDCD /* AudioCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E2BDADF19C0329B0055CDCD /* AudioCache.h */; }; + 3E2BDAE619C0329B0055CDCD /* AudioCache.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E2BDAE019C0329B0055CDCD /* AudioCache.mm */; }; + 3E2BDAE719C0329B0055CDCD /* AudioEngine-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E2BDAE119C0329B0055CDCD /* AudioEngine-inl.h */; }; + 3E2BDAE819C0329B0055CDCD /* AudioEngine-inl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E2BDAE219C0329B0055CDCD /* AudioEngine-inl.mm */; }; + 3E2BDAE919C0329B0055CDCD /* AudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E2BDAE319C0329B0055CDCD /* AudioPlayer.h */; }; + 3E2BDAEA19C0329B0055CDCD /* AudioPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E2BDAE419C0329B0055CDCD /* AudioPlayer.mm */; }; + 3E2BDAEC19C0436F0055CDCD /* AudioEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3E2BDAEB19C0436F0055CDCD /* AudioEngine.cpp */; }; 3E6176681960F89B00DE83F5 /* CCController-iOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3E6176551960F89B00DE83F5 /* CCController-iOS.mm */; }; 3E6176691960F89B00DE83F5 /* CCController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E6176561960F89B00DE83F5 /* CCController.h */; }; 3E6176741960F89B00DE83F5 /* CCEventController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3E6176611960F89B00DE83F5 /* CCEventController.cpp */; }; @@ -2282,6 +2290,14 @@ 37936A3C1869B76800E974DD /* reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reader.h; sourceTree = ""; }; 37936A3D1869B76800E974DD /* stringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stringbuffer.h; sourceTree = ""; }; 37936A3E1869B76800E974DD /* writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = writer.h; sourceTree = ""; }; + 3E2BDADD19C030ED0055CDCD /* AudioEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioEngine.h; sourceTree = ""; }; + 3E2BDADF19C0329B0055CDCD /* AudioCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioCache.h; sourceTree = ""; }; + 3E2BDAE019C0329B0055CDCD /* AudioCache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioCache.mm; sourceTree = ""; }; + 3E2BDAE119C0329B0055CDCD /* AudioEngine-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AudioEngine-inl.h"; sourceTree = ""; }; + 3E2BDAE219C0329B0055CDCD /* AudioEngine-inl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "AudioEngine-inl.mm"; sourceTree = ""; }; + 3E2BDAE319C0329B0055CDCD /* AudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioPlayer.h; sourceTree = ""; }; + 3E2BDAE419C0329B0055CDCD /* AudioPlayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioPlayer.mm; sourceTree = ""; }; + 3E2BDAEB19C0436F0055CDCD /* AudioEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioEngine.cpp; sourceTree = ""; }; 3E6176551960F89B00DE83F5 /* CCController-iOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "CCController-iOS.mm"; path = "../base/CCController-iOS.mm"; sourceTree = ""; }; 3E6176561960F89B00DE83F5 /* CCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CCController.h; path = ../base/CCController.h; sourceTree = ""; }; 3E6176611960F89B00DE83F5 /* CCEventController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CCEventController.cpp; path = ../base/CCEventController.cpp; sourceTree = ""; }; @@ -3996,6 +4012,7 @@ 46A15FD01807A56F005B8026 /* audio */ = { isa = PBXGroup; children = ( + 3E2BDAEB19C0436F0055CDCD /* AudioEngine.cpp */, 46A15FE01807A56F005B8026 /* include */, 46A15FE31807A56F005B8026 /* ios */, 46A15FF31807A56F005B8026 /* mac */, @@ -4007,6 +4024,7 @@ 46A15FE01807A56F005B8026 /* include */ = { isa = PBXGroup; children = ( + 3E2BDADD19C030ED0055CDCD /* AudioEngine.h */, 46A15FE11807A56F005B8026 /* Export.h */, 46A15FE21807A56F005B8026 /* SimpleAudioEngine.h */, ); @@ -4016,6 +4034,12 @@ 46A15FE31807A56F005B8026 /* ios */ = { isa = PBXGroup; children = ( + 3E2BDADF19C0329B0055CDCD /* AudioCache.h */, + 3E2BDAE019C0329B0055CDCD /* AudioCache.mm */, + 3E2BDAE119C0329B0055CDCD /* AudioEngine-inl.h */, + 3E2BDAE219C0329B0055CDCD /* AudioEngine-inl.mm */, + 3E2BDAE319C0329B0055CDCD /* AudioPlayer.h */, + 3E2BDAE419C0329B0055CDCD /* AudioPlayer.mm */, 46A15FE41807A56F005B8026 /* CDAudioManager.h */, 46A15FE51807A56F005B8026 /* CDAudioManager.m */, 46A15FE61807A56F005B8026 /* CDConfig.h */, @@ -5377,6 +5401,7 @@ 1A5701A0180BCB590088DEC7 /* CCFont.h in Headers */, 292DB14819B4574100A80320 /* UIEditBoxImpl-ios.h in Headers */, 15AE1A0819AAD3A700C27E9E /* BoneData.h in Headers */, + 3E2BDADE19C030ED0055CDCD /* AudioEngine.h in Headers */, 50ABBD9A1925AB4100A911A9 /* CCGLProgramStateCache.h in Headers */, 15AE181D19AAD2F700C27E9E /* CCBundle3D.h in Headers */, 15AE192519AAD35100C27E9E /* CocoLoader.h in Headers */, @@ -5430,6 +5455,7 @@ 5034CA22191D591100CE6051 /* ccShader_PositionTextureColorAlphaTest.frag in Headers */, 15AE1B8E19AADA9A00C27E9E /* UIDeprecated.h in Headers */, 15AE1A3919AAD3D500C27E9E /* Box2D.h in Headers */, + 3E2BDAE519C0329B0055CDCD /* AudioCache.h in Headers */, 50ABBECE1925AB6F00A911A9 /* s3tc.h in Headers */, 50643BE519BFCF1800EF68ED /* CCPlatformMacros.h in Headers */, 15AE1BFA19AAE01E00C27E9E /* CCControlSwitch.h in Headers */, @@ -5523,6 +5549,7 @@ 15AE1BAE19AADFDF00C27E9E /* UILayoutParameter.h in Headers */, 15AE18C819AAD33D00C27E9E /* CCMenuItemImageLoader.h in Headers */, 15AE18D119AAD33D00C27E9E /* CCNodeLoaderLibrary.h in Headers */, + 3E2BDAE719C0329B0055CDCD /* AudioEngine-inl.h in Headers */, 15AE1AC319AAD40300C27E9E /* b2DistanceJoint.h in Headers */, 50ABBE741925AB6F00A911A9 /* CCEventListenerMouse.h in Headers */, 1A5702CB180BCE370088DEC7 /* CCTextFieldTTF.h in Headers */, @@ -5556,6 +5583,7 @@ B375107F1823ACA100B3BA6A /* CCPhysicsContactInfo_chipmunk.h in Headers */, 15AE180719AAD2F700C27E9E /* 3dExport.h in Headers */, 15AE1A2019AAD3A700C27E9E /* spine-cocos2dx.h in Headers */, + 3E2BDAE919C0329B0055CDCD /* AudioPlayer.h in Headers */, 15AE185D19AAD31200C27E9E /* CocosDenshion.h in Headers */, 15AE194319AAD35100C27E9E /* CCColliderDetector.h in Headers */, 15AE1BC419AADFFB00C27E9E /* ExtensionMacros.h in Headers */, @@ -5759,7 +5787,7 @@ 1551A336158F2AB200E66CFE /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0600; ORGANIZATIONNAME = ""; }; buildConfigurationList = 1551A339158F2AB200E66CFE /* Build configuration list for PBXProject "cocos2d_libs" */; @@ -6213,6 +6241,7 @@ 50ABBDA01925AB4100A911A9 /* CCGroupCommand.cpp in Sources */, 46A171031807CECB005B8026 /* CCPhysicsShape.cpp in Sources */, 50ABC0161926664800A911A9 /* CCImage.cpp in Sources */, + 3E2BDAE819C0329B0055CDCD /* AudioEngine-inl.mm in Sources */, 1A01C6A518F58F7500EFE3A6 /* CCNotificationCenter.cpp in Sources */, 292DB14E19B4574100A80320 /* UIEditBoxImpl-mac.mm in Sources */, 15AE1BFB19AAE01E00C27E9E /* CCControlUtils.cpp in Sources */, @@ -6241,6 +6270,7 @@ B257B44F1989D5E800D9A687 /* CCPrimitive.cpp in Sources */, 50ABBE281925AB6F00A911A9 /* CCAutoreleasePool.cpp in Sources */, 15AE18D519AAD33D00C27E9E /* CCScale9SpriteLoader.cpp in Sources */, + 3E2BDAEA19C0329B0055CDCD /* AudioPlayer.mm in Sources */, 15AE192919AAD35100C27E9E /* TriggerMng.cpp in Sources */, 15AE185E19AAD31200C27E9E /* CocosDenshion.m in Sources */, 46A170FE1807CECB005B8026 /* CCPhysicsContact.cpp in Sources */, @@ -6558,6 +6588,7 @@ 3E6176761960F89B00DE83F5 /* CCEventListenerController.cpp in Sources */, 15AE1AC219AAD40300C27E9E /* b2DistanceJoint.cpp in Sources */, 503DD8E71926736A00CD74DD /* CCEAGLView-ios.mm in Sources */, + 3E2BDAEC19C0436F0055CDCD /* AudioEngine.cpp in Sources */, 50ABBDA41925AB4100A911A9 /* CCQuadCommand.cpp in Sources */, 15AE18C319AAD33D00C27E9E /* CCLayerGradientLoader.cpp in Sources */, 15AE197919AAD35700C27E9E /* CCActionTimelineCache.cpp in Sources */, @@ -6584,6 +6615,7 @@ 15AE18CC19AAD33D00C27E9E /* CCNode+CCBRelativePositioning.cpp in Sources */, 50ABBD5D1925AB0000A911A9 /* Vec3.cpp in Sources */, 50ABC0121926664800A911A9 /* CCGLView.cpp in Sources */, + 3E2BDAE619C0329B0055CDCD /* AudioCache.mm in Sources */, 50ABC0021926664800A911A9 /* CCLock-apple.cpp in Sources */, 50ABBEBC1925AB6F00A911A9 /* ccUtils.cpp in Sources */, 15AE1A4719AAD3D500C27E9E /* b2ChainShape.cpp in Sources */, @@ -6622,7 +6654,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_BOOL_CONVERSION = YES; @@ -6660,7 +6691,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_BOOL_CONVERSION = YES; @@ -6695,7 +6725,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD)"; + COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_EXTENSION = a; EXECUTABLE_PREFIX = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -6729,7 +6759,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD)"; + COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_EXTENSION = a; EXECUTABLE_PREFIX = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; @@ -6764,7 +6794,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD)"; EXECUTABLE_PREFIX = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "../cocos/cocos2d-prefix.pch"; @@ -6796,7 +6825,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD)"; EXECUTABLE_PREFIX = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/build/cocos2d_tests.xcodeproj/project.pbxproj b/build/cocos2d_tests.xcodeproj/project.pbxproj index f50d3bf013..20341db71a 100644 --- a/build/cocos2d_tests.xcodeproj/project.pbxproj +++ b/build/cocos2d_tests.xcodeproj/project.pbxproj @@ -871,6 +871,8 @@ 38FA2E74194AEBE100FF2BE4 /* ActionTimelineTestScene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 38FA2E71194AEBE100FF2BE4 /* ActionTimelineTestScene.cpp */; }; 38FA2E76194AECF800FF2BE4 /* ActionTimeline in Resources */ = {isa = PBXBuildFile; fileRef = 38FA2E75194AECF800FF2BE4 /* ActionTimeline */; }; 38FA2E77194AECF800FF2BE4 /* ActionTimeline in Resources */ = {isa = PBXBuildFile; fileRef = 38FA2E75194AECF800FF2BE4 /* ActionTimeline */; }; + 3E2BDAD019BEA3410055CDCD /* NewAudioEngineTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3E2BDACE19BEA3410055CDCD /* NewAudioEngineTest.cpp */; }; + 3E2BDAD219BEA3E20055CDCD /* audio in Resources */ = {isa = PBXBuildFile; fileRef = 3E2BDAD119BEA3E20055CDCD /* audio */; }; 3E6177221960FAED00DE83F5 /* libcocos2d iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 46A15FBE1807A4F9005B8026 /* libcocos2d iOS.a */; }; 3E6177241960FAED00DE83F5 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D60AE43317F7FFE100757E4B /* CoreMotion.framework */; }; 3E6177251960FAED00DE83F5 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 15C6482E165F399D007D4F18 /* libz.dylib */; }; @@ -931,8 +933,8 @@ A07A52C31783B02C0073F6A7 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A07A52C11783B01F0073F6A7 /* AVFoundation.framework */; }; B2507B6B192589AF00FA4972 /* Shaders3D in Resources */ = {isa = PBXBuildFile; fileRef = B2507B6A192589AF00FA4972 /* Shaders3D */; }; B2507B6C192589AF00FA4972 /* Shaders3D in Resources */ = {isa = PBXBuildFile; fileRef = B2507B6A192589AF00FA4972 /* Shaders3D */; }; - B60EF5F919B842B000EAF38D /* BillBoardTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60EF5F719B842B000EAF38D /* BillBoardTest.cpp */; }; - B60EF5FA19B842B000EAF38D /* BillBoardTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60EF5F719B842B000EAF38D /* BillBoardTest.cpp */; }; + B609E67319C18DAD003D0074 /* BillBoardTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B609E67119C18DAD003D0074 /* BillBoardTest.cpp */; }; + B609E67419C18DAD003D0074 /* BillBoardTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B609E67119C18DAD003D0074 /* BillBoardTest.cpp */; }; C04F935A1941B05400E9FEAB /* TileMapTest2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C04F93581941B05400E9FEAB /* TileMapTest2.cpp */; }; C04F935B1941B05400E9FEAB /* TileMapTest2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C04F93581941B05400E9FEAB /* TileMapTest2.cpp */; }; C08689C118D370C90093E810 /* background.caf in Resources */ = {isa = PBXBuildFile; fileRef = C08689C018D370C90093E810 /* background.caf */; }; @@ -2894,6 +2896,9 @@ 38FA2E71194AEBE100FF2BE4 /* ActionTimelineTestScene.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActionTimelineTestScene.cpp; sourceTree = ""; }; 38FA2E72194AEBE100FF2BE4 /* ActionTimelineTestScene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActionTimelineTestScene.h; sourceTree = ""; }; 38FA2E75194AECF800FF2BE4 /* ActionTimeline */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ActionTimeline; path = "../tests/cpp-tests/Resources/ActionTimeline"; sourceTree = ""; }; + 3E2BDACE19BEA3410055CDCD /* NewAudioEngineTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewAudioEngineTest.cpp; sourceTree = ""; }; + 3E2BDACF19BEA3410055CDCD /* NewAudioEngineTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewAudioEngineTest.h; sourceTree = ""; }; + 3E2BDAD119BEA3E20055CDCD /* audio */ = {isa = PBXFileReference; lastKnownFileType = folder; name = audio; path = "../tests/cpp-tests/Resources/audio"; sourceTree = ""; }; 3E6176B71960FA6300DE83F5 /* AppDelegate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AppDelegate.cpp; sourceTree = ""; }; 3E6176B81960FA6300DE83F5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 3E6176B91960FA6300DE83F5 /* AppMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppMacros.h; sourceTree = ""; }; @@ -2950,8 +2955,8 @@ A07A52BB1783AEB80073F6A7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; A07A52C11783B01F0073F6A7 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; B2507B6A192589AF00FA4972 /* Shaders3D */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Shaders3D; path = "../tests/cpp-tests/Resources/Shaders3D"; sourceTree = ""; }; - B60EF5F719B842B000EAF38D /* BillBoardTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BillBoardTest.cpp; path = BillBoardTest/BillBoardTest.cpp; sourceTree = ""; }; - B60EF5F819B842B000EAF38D /* BillBoardTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BillBoardTest.h; path = BillBoardTest/BillBoardTest.h; sourceTree = ""; }; + B609E67119C18DAD003D0074 /* BillBoardTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BillBoardTest.cpp; path = BillBoardTest/BillBoardTest.cpp; sourceTree = ""; }; + B609E67219C18DAD003D0074 /* BillBoardTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BillBoardTest.h; path = BillBoardTest/BillBoardTest.h; sourceTree = ""; }; C04F93581941B05400E9FEAB /* TileMapTest2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileMapTest2.cpp; sourceTree = ""; }; C04F93591941B05400E9FEAB /* TileMapTest2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileMapTest2.h; sourceTree = ""; }; C08689C018D370C90093E810 /* background.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = background.caf; path = "../tests/cpp-tests/Resources/background.caf"; sourceTree = ""; }; @@ -5426,7 +5431,8 @@ 1AC3592418CECF0A00F37B72 /* Classes */ = { isa = PBXGroup; children = ( - B60EF5F619B8428700EAF38D /* BillBoardTest */, + B609E67019C18D90003D0074 /* BillBoardTest */, + 3E2BDACD19BEA3410055CDCD /* NewAudioEngineTest */, 3E9E75CB199324A8005B7047 /* Camera3DTest */, 1AC3592818CECF0A00F37B72 /* ActionManagerTest */, 1AC3592B18CECF0A00F37B72 /* ActionsEaseTest */, @@ -6450,6 +6456,7 @@ 1AC35CA818CED83500F37B72 /* Resources */ = { isa = PBXGroup; children = ( + 3E2BDAD119BEA3E20055CDCD /* audio */, 38FA2E75194AECF800FF2BE4 /* ActionTimeline */, B2507B6A192589AF00FA4972 /* Shaders3D */, 3E92EA841921A7720094CD21 /* Sprite3DTest */, @@ -7031,6 +7038,15 @@ path = CocoStudioActionTimelineTest; sourceTree = ""; }; + 3E2BDACD19BEA3410055CDCD /* NewAudioEngineTest */ = { + isa = PBXGroup; + children = ( + 3E2BDACE19BEA3410055CDCD /* NewAudioEngineTest.cpp */, + 3E2BDACF19BEA3410055CDCD /* NewAudioEngineTest.h */, + ); + path = NewAudioEngineTest; + sourceTree = ""; + }; 3E6176B51960FA6300DE83F5 /* game-controller-test */ = { isa = PBXGroup; children = ( @@ -7130,11 +7146,11 @@ name = Products; sourceTree = ""; }; - B60EF5F619B8428700EAF38D /* BillBoardTest */ = { + B609E67019C18D90003D0074 /* BillBoardTest */ = { isa = PBXGroup; children = ( - B60EF5F719B842B000EAF38D /* BillBoardTest.cpp */, - B60EF5F819B842B000EAF38D /* BillBoardTest.h */, + B609E67119C18DAD003D0074 /* BillBoardTest.cpp */, + B609E67219C18DAD003D0074 /* BillBoardTest.h */, ); name = BillBoardTest; sourceTree = ""; @@ -7333,7 +7349,7 @@ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0600; }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "cocos2d_tests" */; compatibilityVersion = "Xcode 3.2"; @@ -7828,6 +7844,7 @@ 1AC35CD518CED84500F37B72 /* ccb in Resources */, 1AC35CE118CED84500F37B72 /* configs in Resources */, 1AC35CE918CED84500F37B72 /* extensions in Resources */, + 3E2BDAD219BEA3E20055CDCD /* audio in Resources */, C08689C318D370C90093E810 /* background.caf in Resources */, 1AC35C9518CECF1400F37B72 /* Icon-72.png in Resources */, 1AC35D0B18CED84500F37B72 /* zwoptex in Resources */, @@ -8030,7 +8047,7 @@ 1AC35B7D18CECF0C00F37B72 /* PlayerController.cpp in Sources */, 29080D9F191B595E0066F8DF /* CustomReader.cpp in Sources */, 1AC35BE718CECF0C00F37B72 /* CCControlScene.cpp in Sources */, - B60EF5F919B842B000EAF38D /* BillBoardTest.cpp in Sources */, + B609E67319C18DAD003D0074 /* BillBoardTest.cpp in Sources */, 292CF01419A1965E00E8E6A0 /* UIEditBoxTest.cpp in Sources */, 29080DBF191B595E0066F8DF /* UIPageViewTest_Editor.cpp in Sources */, 1AC35B5F18CECF0C00F37B72 /* DataVisitorTest.cpp in Sources */, @@ -8215,10 +8232,12 @@ 292CF01519A1965E00E8E6A0 /* UIEditBoxTest.cpp in Sources */, 1AC35B2818CECF0C00F37B72 /* ActionsTest.cpp in Sources */, 1AC35C4A18CECF0C00F37B72 /* ShaderTest.cpp in Sources */, + B609E67419C18DAD003D0074 /* BillBoardTest.cpp in Sources */, C04F935B1941B05400E9FEAB /* TileMapTest2.cpp in Sources */, 1AC35B4418CECF0C00F37B72 /* Bug-624.cpp in Sources */, 1AC35BF818CECF0C00F37B72 /* SocketIOTest.cpp in Sources */, 1AC35C5018CECF0C00F37B72 /* SpriteTest.cpp in Sources */, + 3E2BDAD019BEA3410055CDCD /* NewAudioEngineTest.cpp in Sources */, 1AC35C0418CECF0C00F37B72 /* FileUtilsTest.cpp in Sources */, 1AC35B5C18CECF0C00F37B72 /* CurlTest.cpp in Sources */, 1AC35C0018CECF0C00F37B72 /* CustomTableViewCell.cpp in Sources */, @@ -8255,7 +8274,6 @@ 1AC35BEE18CECF0C00F37B72 /* CCControlStepperTest.cpp in Sources */, 1AC35C3418CECF0C00F37B72 /* PerformanceScenarioTest.cpp in Sources */, 29080DA4191B595E0066F8DF /* UIButtonTest.cpp in Sources */, - B60EF5FA19B842B000EAF38D /* BillBoardTest.cpp in Sources */, 1AC35C5A18CECF0C00F37B72 /* TextureAtlasEncryptionTest.cpp in Sources */, 1AC35B5618CECF0C00F37B72 /* ConfigurationTest.cpp in Sources */, 1AC35BE618CECF0C00F37B72 /* CCControlPotentiometerTest.cpp in Sources */, @@ -8573,7 +8591,6 @@ 1A0EE2B018CDF6DA004CD58F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", @@ -8588,7 +8605,6 @@ 1A0EE2B118CDF6DA004CD58F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", @@ -8604,7 +8620,6 @@ 1A0EE31218CDF733004CD58F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", CC_TARGET_OS_MAC, @@ -8624,7 +8639,6 @@ 1A0EE31318CDF733004CD58F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", CC_TARGET_OS_MAC, @@ -8719,7 +8733,6 @@ 1ABCA2B318CD91520087CE3A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", CC_TARGET_OS_MAC, @@ -8739,7 +8752,6 @@ 1ABCA2B418CD91520087CE3A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", CC_TARGET_OS_MAC, @@ -8801,7 +8813,6 @@ 1D6058940D05DD3E006BFB54 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", CC_TARGET_OS_MAC, @@ -8815,7 +8826,6 @@ 1D6058950D05DD3E006BFB54 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD)"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", CC_TARGET_OS_MAC, diff --git a/cocos/2d/CCNodeGrid.cpp b/cocos/2d/CCNodeGrid.cpp index eb42030199..2153b9dca2 100644 --- a/cocos/2d/CCNodeGrid.cpp +++ b/cocos/2d/CCNodeGrid.cpp @@ -150,8 +150,9 @@ void NodeGrid::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t p this->draw(renderer, _modelViewTransform, dirty); } - // reset for next frame - _orderOfArrival = 0; + // FIX ME: Why need to set _orderOfArrival to 0?? + // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 + // setOrderOfArrival(0); if(_nodeGrid && _nodeGrid->isActive()) { diff --git a/cocos/2d/CCProtectedNode.cpp b/cocos/2d/CCProtectedNode.cpp index d65ca6a7b5..3a8259b48d 100644 --- a/cocos/2d/CCProtectedNode.cpp +++ b/cocos/2d/CCProtectedNode.cpp @@ -330,8 +330,9 @@ void ProtectedNode::visit(Renderer* renderer, const Mat4 &parentTransform, uint3 for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) (*it)->visit(renderer, _modelViewTransform, flags); - // reset for next frame - _orderOfArrival = 0; + // FIX ME: Why need to set _orderOfArrival to 0?? + // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 + // setOrderOfArrival(0); director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); } diff --git a/cocos/2d/CCRenderTexture.cpp b/cocos/2d/CCRenderTexture.cpp index 13fed5a85e..201cf0cfc1 100644 --- a/cocos/2d/CCRenderTexture.cpp +++ b/cocos/2d/CCRenderTexture.cpp @@ -403,7 +403,9 @@ void RenderTexture::visit(Renderer *renderer, const Mat4 &parentTransform, uint3 director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); - _orderOfArrival = 0; + // FIX ME: Why need to set _orderOfArrival to 0?? + // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 + // setOrderOfArrival(0); } bool RenderTexture::saveToFile(const std::string& filename, bool isRGBA, std::function callback) diff --git a/cocos/2d/cocos2d_headers.props b/cocos/2d/cocos2d_headers.props index aaaefd1c7d..06da521592 100644 --- a/cocos/2d/cocos2d_headers.props +++ b/cocos/2d/cocos2d_headers.props @@ -7,7 +7,7 @@ - $(EngineRoot)cocos;$(EngineRoot)cocos\platform\win32;$(EngineRoot)cocos\platform\desktop;$(EngineRoot)external\glfw3\include\win32;$(EngineRoot)external\win32-specific\gles\include\OGLES + $(EngineRoot)cocos;$(EngineRoot)cocos\platform;$(EngineRoot)cocos\platform\desktop;$(EngineRoot)external\glfw3\include\win32;$(EngineRoot)external\win32-specific\gles\include\OGLES _VARIADIC_MAX=10;%(PreprocessorDefinitions) diff --git a/cocos/Android.mk b/cocos/Android.mk index 08873fb606..4b9ded3248 100644 --- a/cocos/Android.mk +++ b/cocos/Android.mk @@ -187,7 +187,7 @@ physics/chipmunk/CCPhysicsWorldInfo_chipmunk.cpp \ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \ $(LOCAL_PATH)/. \ - $(LOCAL_PATH)/platform/android \ + $(LOCAL_PATH)/platform \ $(LOCAL_PATH)/base \ $(LOCAL_PATH)/../external/tinyxml2 \ $(LOCAL_PATH)/../external/unzip \ @@ -197,7 +197,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \ LOCAL_C_INCLUDES := $(LOCAL_PATH) \ $(LOCAL_PATH)/. \ - $(LOCAL_PATH)/platform/android \ + $(LOCAL_PATH)/platform \ $(LOCAL_PATH)/../external \ $(LOCAL_PATH)/../external/tinyxml2 \ $(LOCAL_PATH)/../external/unzip \ @@ -238,6 +238,7 @@ LOCAL_MODULE := cocos2dx_static LOCAL_MODULE_FILENAME := libcocos2d LOCAL_STATIC_LIBRARIES := cocostudio_static +LOCAL_STATIC_LIBRARIES += audioengine_static LOCAL_STATIC_LIBRARIES += cocos3d_static LOCAL_STATIC_LIBRARIES += cocosbuilder_static LOCAL_STATIC_LIBRARIES += spine_static diff --git a/cocos/CMakeLists.txt b/cocos/CMakeLists.txt index e1d889b96c..d4ced21da2 100644 --- a/cocos/CMakeLists.txt +++ b/cocos/CMakeLists.txt @@ -296,7 +296,7 @@ if(MACOSX) ${COCOS2D_BASE_SRC} ui/UIEditBox/UIEditBoxImpl-ios.mm ui/UIEditBox/UIEditBoxImpl-mac.mm - base/CCUserDefault.mm + base/CCUserDefault-apple.mm ) endif() diff --git a/cocos/audio/AudioEngine.cpp b/cocos/audio/AudioEngine.cpp new file mode 100644 index 0000000000..03579936bf --- /dev/null +++ b/cocos/audio/AudioEngine.cpp @@ -0,0 +1,395 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS + +#include "audio/include/AudioEngine.h" +#include "platform/CCFileUtils.h" +#include "base/ccUtils.h" + +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +#include "android/AudioEngine-inl.h" +#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS +#include "ios/AudioEngine-inl.h" +#endif + +#define TIME_DELAY_PRECISION 0.0001 + +using namespace cocos2d; + +const int AudioEngine::INVAILD_AUDIO_ID = -1; +const float AudioEngine::TIME_UNKNOWN = -1.0f; + +//audio file path,audio IDs +std::unordered_map> AudioEngine::_audioPathIDMap; +//profileName,ProfileHelper +std::unordered_map AudioEngine::_audioPathProfileHelperMap; +int AudioEngine::_maxInstances = MAX_AUDIOINSTANCES; +AudioEngine::ProfileHelper* AudioEngine::_defaultProfileHelper; +std::unordered_map AudioEngine::_audioIDInfoMap; +AudioEngineImpl* AudioEngine::_audioEngineImpl = nullptr; + +void AudioEngine::end() +{ + delete _audioEngineImpl; + _audioEngineImpl = nullptr; + + delete _defaultProfileHelper; + _defaultProfileHelper = nullptr; +} + +bool AudioEngine::lazyInit() +{ + if (_audioEngineImpl == nullptr) + { + _audioEngineImpl = new (std::nothrow) AudioEngineImpl(); + if(!_audioEngineImpl || !_audioEngineImpl->init() ){ + return false; + } + } + + return true; +} + +int AudioEngine::play2d(const std::string& filePath, bool loop, float volume, const AudioProfile *profile) +{ + int ret = AudioEngine::INVAILD_AUDIO_ID; + + do { + if ( !lazyInit() ){ + break; + } + + if ( !FileUtils::getInstance()->isFileExist(filePath)){ + break; + } + + ProfileHelper* manage = _defaultProfileHelper; + if (profile && profile != &manage->profile){ + CC_ASSERT(!profile->name.empty()); + manage = &_audioPathProfileHelperMap[profile->name]; + manage->profile = *profile; + } + + if (_audioIDInfoMap.size() >= _maxInstances) { + log("Fail to play %s cause by limited max instance of AudioEngine",filePath.c_str()); + break; + } + if (manage) + { + if(manage->profile.maxInstances != 0 && manage->audioIDs.size() >= manage->profile.maxInstances){ + log("Fail to play %s cause by limited max instance of AudioProfile",filePath.c_str()); + break; + } + if (manage->profile.minDelay > TIME_DELAY_PRECISION) { + auto currTime = utils::gettime(); + if (manage->lastPlayTime > TIME_DELAY_PRECISION && currTime - manage->lastPlayTime <= manage->profile.minDelay) { + log("Fail to play %s cause by limited minimum delay",filePath.c_str()); + break; + } + } + } + + if (volume < 0.0f) { + volume = 0.0f; + } + else if (volume > 1.0f){ + volume = 1.0f; + } + + ret = _audioEngineImpl->play2d(filePath, loop, volume); + if (ret != INVAILD_AUDIO_ID) + { + _audioPathIDMap[filePath].push_back(ret); + auto it = _audioPathIDMap.find(filePath); + + auto& audioRef = _audioIDInfoMap[ret]; + audioRef.volume = volume; + audioRef.loop = loop; + audioRef.is3dAudio = false; + audioRef.filePath = &it->first; + + if (manage) { + manage->lastPlayTime = utils::gettime(); + manage->audioIDs.push_back(ret); + } + audioRef.profileHelper = manage; + } + } while (0); + + return ret; +} + +void AudioEngine::setLoop(int audioID, bool loop) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end() && it->second.loop != loop){ + _audioEngineImpl->setLoop(audioID, loop); + it->second.loop = loop; + } +} + +void AudioEngine::setVolume(int audioID, float volume) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end()){ + if (volume < 0.0f) { + volume = 0.0f; + } + else if (volume > 1.0f){ + volume = 1.0f; + } + + if (it->second.volume != volume){ + _audioEngineImpl->setVolume(audioID, volume); + it->second.volume = volume; + } + } +} + +void AudioEngine::pause(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end() && it->second.state == AudioState::PLAYING){ + _audioEngineImpl->pause(audioID); + it->second.state = AudioState::PAUSED; + } +} + +void AudioEngine::pauseAll() +{ + auto itEnd = _audioIDInfoMap.end(); + for (auto it = _audioIDInfoMap.begin(); it != itEnd; ++it) + { + if (it->second.state == AudioState::PLAYING) + { + _audioEngineImpl->pause(it->first); + it->second.state = AudioState::PAUSED; + } + } +} + +void AudioEngine::resume(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end() && it->second.state == AudioState::PAUSED){ + _audioEngineImpl->resume(audioID); + it->second.state = AudioState::PLAYING; + } +} + +void AudioEngine::resumeAll() +{ + auto itEnd = _audioIDInfoMap.end(); + for (auto it = _audioIDInfoMap.begin(); it != itEnd; ++it) + { + if (it->second.state == AudioState::PAUSED) + { + _audioEngineImpl->resume(it->first); + it->second.state = AudioState::PLAYING; + } + } +} + +void AudioEngine::stop(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end()){ + _audioEngineImpl->stop(audioID); + + remove(audioID); + } +} + +void AudioEngine::remove(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end()){ + if (it->second.profileHelper) { + it->second.profileHelper->audioIDs.remove(audioID); + } + _audioPathIDMap[*it->second.filePath].remove(audioID); + _audioIDInfoMap.erase(audioID); + } +} + +void AudioEngine::stopAll() +{ + _audioEngineImpl->stopAll(); + auto itEnd = _audioIDInfoMap.end(); + for (auto it = _audioIDInfoMap.begin(); it != itEnd; ++it) + { + if (it->second.profileHelper){ + it->second.profileHelper->audioIDs.remove(it->first); + } + } + _audioPathIDMap.clear(); + _audioIDInfoMap.clear(); +} + +void AudioEngine::uncache(const std::string &filePath) +{ + if(_audioPathIDMap.find(filePath) != _audioPathIDMap.end()){ + auto itEnd = _audioPathIDMap[filePath].end(); + for (auto it = _audioPathIDMap[filePath].begin() ; it != itEnd; ++it) { + auto audioID = *it; + _audioEngineImpl->stop(audioID); + + auto itInfo = _audioIDInfoMap.find(audioID); + if (itInfo != _audioIDInfoMap.end()){ + if (itInfo->second.profileHelper) { + itInfo->second.profileHelper->audioIDs.remove(audioID); + } + _audioIDInfoMap.erase(audioID); + } + } + _audioEngineImpl->uncache(filePath); + _audioPathIDMap.erase(filePath); + } +} + +void AudioEngine::uncacheAll() +{ + stopAll(); + _audioEngineImpl->uncacheAll(); +} + +float AudioEngine::getDuration(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end() && it->second.state != AudioState::INITIALZING) + { + if (it->second.duration == TIME_UNKNOWN) + { + it->second.duration = _audioEngineImpl->getDuration(audioID); + } + return it->second.duration; + } + + return TIME_UNKNOWN; +} + +bool AudioEngine::setCurrentTime(int audioID, float time) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end() && it->second.state != AudioState::INITIALZING){ + return _audioEngineImpl->setCurrentTime(audioID, time); + } + + return false; +} + +float AudioEngine::getCurrentTime(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end() && it->second.state != AudioState::INITIALZING){ + return _audioEngineImpl->getCurrentTime(audioID); + } + return 0.0f; +} + +void AudioEngine::setFinishCallback(int audioID, const std::function &callback) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end()){ + _audioEngineImpl->setFinishCallback(audioID, callback); + } +} + +bool AudioEngine::setMaxAudioInstance(int maxInstances) +{ + if (maxInstances > 0 && maxInstances <= MAX_AUDIOINSTANCES) { + _maxInstances = maxInstances; + return true; + } + + return false; +} + +bool AudioEngine::isLoop(int audioID) +{ + auto tmpIterator = _audioIDInfoMap.find(audioID); + if (tmpIterator != _audioIDInfoMap.end()) + { + return tmpIterator->second.loop; + } + + log("AudioEngine::isLoop-->The audio instance %d is non-existent", audioID); + return false; +} + +float AudioEngine::getVolume(int audioID) +{ + auto tmpIterator = _audioIDInfoMap.find(audioID); + if (tmpIterator != _audioIDInfoMap.end()) + { + return tmpIterator->second.volume; + } + + log("AudioEngine::getVolume-->The audio instance %d is non-existent", audioID); + return 0.0f; +} + +AudioEngine::AudioState AudioEngine::getState(int audioID) +{ + auto tmpIterator = _audioIDInfoMap.find(audioID); + if (tmpIterator != _audioIDInfoMap.end()) + { + return tmpIterator->second.state; + } + + return AudioState::ERROR; +} + +AudioProfile* AudioEngine::getProfile(int audioID) +{ + auto it = _audioIDInfoMap.find(audioID); + if (it != _audioIDInfoMap.end()) + { + return &it->second.profileHelper->profile; + } + + return nullptr; +} + +AudioProfile* AudioEngine::getDefaultProfile() +{ + if (_defaultProfileHelper == nullptr) + { + _defaultProfileHelper = new (std::nothrow) ProfileHelper(); + } + + return &_defaultProfileHelper->profile; +} + +AudioProfile* AudioEngine::getProfile(const std::string &name) +{ + auto it = _audioPathProfileHelperMap.find(name); + if (it != _audioPathProfileHelperMap.end()) { + return &it->second.profile; + } else { + return nullptr; + } +} + +#endif diff --git a/cocos/audio/android/Android.mk b/cocos/audio/android/Android.mk index 3854fa79d7..bbd7725d9d 100644 --- a/cocos/audio/android/Android.mk +++ b/cocos/audio/android/Android.mk @@ -16,3 +16,23 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include \ $(LOCAL_PATH)/../../platform/android include $(BUILD_STATIC_LIBRARY) + +#new audio engine +include $(CLEAR_VARS) + +LOCAL_MODULE := audioengine_static + +LOCAL_MODULE_FILENAME := libaudioengine + +LOCAL_SRC_FILES := AudioEngine-inl.cpp \ + ../AudioEngine.cpp + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../include + +LOCAL_EXPORT_LDLIBS := -lOpenSLES + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../.. \ + $(LOCAL_PATH)/../../platform/android + +include $(BUILD_STATIC_LIBRARY) diff --git a/cocos/audio/android/AudioEngine-inl.cpp b/cocos/audio/android/AudioEngine-inl.cpp new file mode 100644 index 0000000000..69389ab05e --- /dev/null +++ b/cocos/audio/android/AudioEngine-inl.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID +#include "AudioEngine-inl.h" + +#include +// for native asset manager +#include +#include +#include + +#include "audio/include/AudioEngine.h" +#include "base/CCDirector.h" +#include "platform/android/CCFileUtils-android.h" + +#include "platform/android/jni/JniHelper.h" +#include +#include + +using namespace cocos2d; + +void PlayOverEvent(SLPlayItf caller, void* context, SLuint32 playEvent) +{ + if (context && playEvent == SL_PLAYEVENT_HEADATEND) + { + AudioEngineImpl* engineImpl = (AudioEngineImpl*)context; + engineImpl->playerFinishCallback(caller,playEvent); + } +} + +AudioPlayer::AudioPlayer() + : _fdPlayerObject(nullptr) + , _finishCallback(nullptr) + , _duration(0.0f) +{ + +} + +AudioPlayer::~AudioPlayer() +{ + if (_fdPlayerObject) + { + (*_fdPlayerObject)->Destroy(_fdPlayerObject); + _fdPlayerObject = nullptr; + } +} + +bool AudioPlayer::init(SLEngineItf engineEngine, SLObjectItf outputMixObject,const std::string& fileFullPath, float volume, bool loop) +{ + bool ret = false; + + do + { + SLDataSource audioSrc; + + SLDataLocator_AndroidFD loc_fd; + SLDataLocator_URI loc_uri; + + SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; + audioSrc.pFormat = &format_mime; + + if (fileFullPath[0] != '/'){ + std::string relativePath = ""; + + size_t position = fileFullPath.find("assets/"); + if (0 == position) { + // "assets/" is at the beginning of the path and we don't want it + relativePath += fileFullPath.substr(strlen("assets/")); + } else { + relativePath += fileFullPath; + } + + auto asset = AAssetManager_open(cocos2d::FileUtilsAndroid::getAssetManager(), relativePath.c_str(), AASSET_MODE_UNKNOWN); + + // open asset as file descriptor + off_t start, length; + int fd = AAsset_openFileDescriptor(asset, &start, &length); + if (fd <= 0){ + AAsset_close(asset); + break; + } + AAsset_close(asset); + + // configure audio source + loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length}; + + audioSrc.pLocator = &loc_fd; + } + else{ + loc_uri = {SL_DATALOCATOR_URI , (SLchar*)fileFullPath.c_str()}; + audioSrc.pLocator = &loc_uri; + } + + // configure audio sink + SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; + SLDataSink audioSnk = {&loc_outmix, NULL}; + + // create audio player + const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_PREFETCHSTATUS, SL_IID_VOLUME}; + const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + auto result = (*engineEngine)->CreateAudioPlayer(engineEngine, &_fdPlayerObject, &audioSrc, &audioSnk, 3, ids, req); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("create audio player fail"); break; } + + // realize the player + result = (*_fdPlayerObject)->Realize(_fdPlayerObject, SL_BOOLEAN_FALSE); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("realize the player fail"); break; } + + // get the play interface + result = (*_fdPlayerObject)->GetInterface(_fdPlayerObject, SL_IID_PLAY, &_fdPlayerPlay); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("get the play interface fail"); break; } + + // get the seek interface + result = (*_fdPlayerObject)->GetInterface(_fdPlayerObject, SL_IID_SEEK, &_fdPlayerSeek); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("get the seek interface fail"); break; } + + // get the volume interface + result = (*_fdPlayerObject)->GetInterface(_fdPlayerObject, SL_IID_VOLUME, &_fdPlayerVolume); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("get the volume interface fail"); break; } + + if (loop){ + (*_fdPlayerSeek)->SetLoop(_fdPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN); + } + + int dbVolume = 2000 * log10(volume); + if(dbVolume < SL_MILLIBEL_MIN){ + dbVolume = SL_MILLIBEL_MIN; + } + (*_fdPlayerVolume)->SetVolumeLevel(_fdPlayerVolume, dbVolume); + + result = (*_fdPlayerPlay)->SetPlayState(_fdPlayerPlay, SL_PLAYSTATE_PLAYING); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("SetPlayState fail"); break; } + + ret = true; + } while (0); + + return ret; +} + +//==================================================== +AudioEngineImpl::AudioEngineImpl() + : currentAudioID(0) + , _engineObject(nullptr) + , _engineEngine(nullptr) + , _outputMixObject(nullptr) +{ + +} + +AudioEngineImpl::~AudioEngineImpl() +{ + if (_outputMixObject) + { + (*_outputMixObject)->Destroy(_outputMixObject); + } + if (_engineObject) + { + (*_engineObject)->Destroy(_engineObject); + } +} + +bool AudioEngineImpl::init() +{ + bool ret = false; + do{ + // create engine + auto result = slCreateEngine(&_engineObject, 0, nullptr, 0, nullptr, nullptr); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("create opensl engine fail"); break; } + + // realize the engine + result = (*_engineObject)->Realize(_engineObject, SL_BOOLEAN_FALSE); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("realize the engine fail"); break; } + + // get the engine interface, which is needed in order to create other objects + result = (*_engineObject)->GetInterface(_engineObject, SL_IID_ENGINE, &_engineEngine); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("get the engine interface fail"); break; } + + // create output mix + const SLInterfaceID outputMixIIDs[] = {}; + const SLboolean outputMixReqs[] = {}; + result = (*_engineEngine)->CreateOutputMix(_engineEngine, &_outputMixObject, 0, outputMixIIDs, outputMixReqs); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("create output mix fail"); break; } + + // realize the output mix + result = (*_outputMixObject)->Realize(_outputMixObject, SL_BOOLEAN_FALSE); + if(SL_RESULT_SUCCESS != result){ ERRORLOG("realize the output mix fail"); break; } + + ret = true; + }while (false); + + return ret; +} + +int AudioEngineImpl::play2d(const std::string &fileFullPath ,bool loop ,float volume) +{ + auto audioId = AudioEngine::INVAILD_AUDIO_ID; + + do + { + if (_engineEngine == nullptr) + break; + + auto& player = _audioPlayers[currentAudioID]; + auto initPlayer = player.init( _engineEngine, _outputMixObject, fileFullPath, volume, loop); + if (!initPlayer){ + _audioPlayers.erase(currentAudioID); + log("%s,%d message:create player for %s fail", __func__, __LINE__, fileFullPath.c_str()); + break; + } + + audioId = currentAudioID++; + player._audioID = audioId; + + (*(player._fdPlayerPlay))->RegisterCallback(player._fdPlayerPlay, PlayOverEvent, (void*)this); + (*(player._fdPlayerPlay))->SetCallbackEventsMask(player._fdPlayerPlay, SL_PLAYEVENT_HEADATEND); + + AudioEngine::_audioIDInfoMap[audioId].state = AudioEngine::AudioState::PLAYING; + } while (0); + + return audioId; +} + +void AudioEngineImpl::playerFinishCallback(SLPlayItf caller, SLuint32 playEvent) +{ + auto itend = _audioPlayers.end(); + for (auto iter = _audioPlayers.begin(); iter != itend; ++iter) + { + if (iter->second._fdPlayerPlay == caller) + { + if (iter->second._finishCallback) + { + iter->second._finishCallback(iter->second._audioID, *AudioEngine::_audioIDInfoMap[iter->second._audioID].filePath); + } + AudioEngine::stop(iter->second._audioID); + break; + } + } +} + +void AudioEngineImpl::setVolume(int audioID,float volume) +{ + auto& player = _audioPlayers[audioID]; + int dbVolume = 2000 * log10(volume); + if(dbVolume < SL_MILLIBEL_MIN){ + dbVolume = SL_MILLIBEL_MIN; + } + auto result = (*player._fdPlayerVolume)->SetVolumeLevel(player._fdPlayerVolume, dbVolume); + if(SL_RESULT_SUCCESS != result){ + log("%s error:%lu",__func__, result); + } +} + +void AudioEngineImpl::setLoop(int audioID, bool loop) +{ + auto& player = _audioPlayers[audioID]; + SLboolean loopEnabled = SL_BOOLEAN_TRUE; + if (!loop){ + loopEnabled = SL_BOOLEAN_FALSE; + } + (*player._fdPlayerSeek)->SetLoop(player._fdPlayerSeek, loopEnabled, 0, SL_TIME_UNKNOWN); +} + +void AudioEngineImpl::pause(int audioID) +{ + auto& player = _audioPlayers[audioID]; + auto result = (*player._fdPlayerPlay)->SetPlayState(player._fdPlayerPlay, SL_PLAYSTATE_PAUSED); + if(SL_RESULT_SUCCESS != result){ + log("%s error:%lu",__func__, result); + } +} + +void AudioEngineImpl::resume(int audioID) +{ + auto& player = _audioPlayers[audioID]; + auto result = (*player._fdPlayerPlay)->SetPlayState(player._fdPlayerPlay, SL_PLAYSTATE_PLAYING); + if(SL_RESULT_SUCCESS != result){ + log("%s error:%lu",__func__, result); + } +} + +void AudioEngineImpl::stop(int audioID) +{ + auto& player = _audioPlayers[audioID]; + auto result = (*player._fdPlayerPlay)->SetPlayState(player._fdPlayerPlay, SL_PLAYSTATE_STOPPED); + if(SL_RESULT_SUCCESS != result){ + log("%s error:%lu",__func__, result); + } + + _audioPlayers.erase(audioID); +} + +void AudioEngineImpl::stopAll() +{ + auto itEnd = _audioPlayers.end(); + for (auto it = _audioPlayers.begin(); it != itEnd; ++it) + { + auto result = (*it->second._fdPlayerPlay)->SetPlayState(it->second._fdPlayerPlay, SL_PLAYSTATE_STOPPED); + } + _audioPlayers.clear(); +} + +float AudioEngineImpl::getDuration(int audioID) +{ + SLmillisecond duration; + auto& player = _audioPlayers[audioID]; + auto result = (*player._fdPlayerPlay)->GetDuration(player._fdPlayerPlay, &duration); + if (duration == SL_TIME_UNKNOWN){ + return AudioEngine::TIME_UNKNOWN; + } + else{ + player._duration = duration / 1000.0; + + if (player._duration <= 0) + { + return AudioEngine::TIME_UNKNOWN; + } + + return player._duration; + } +} + +float AudioEngineImpl::getCurrentTime(int audioID) +{ + SLmillisecond currPos; + auto& player = _audioPlayers[audioID]; + (*player._fdPlayerPlay)->GetPosition(player._fdPlayerPlay, &currPos); + return currPos / 1000.0f; +} + +bool AudioEngineImpl::setCurrentTime(int audioID, float time) +{ + auto& player = _audioPlayers[audioID]; + SLmillisecond pos = 1000 * time; + auto result = (*player._fdPlayerSeek)->SetPosition(player._fdPlayerSeek, pos, SL_SEEKMODE_ACCURATE); + if(SL_RESULT_SUCCESS != result){ + return false; + } + return true; +} + +void AudioEngineImpl::setFinishCallback(int audioID, const std::function &callback) +{ + _audioPlayers[audioID]._finishCallback = callback; +} + +#endif diff --git a/cocos/audio/android/AudioEngine-inl.h b/cocos/audio/android/AudioEngine-inl.h new file mode 100644 index 0000000000..bf9f7a7773 --- /dev/null +++ b/cocos/audio/android/AudioEngine-inl.h @@ -0,0 +1,108 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID + +#ifndef __AUDIO_ENGINE_INL_H_ +#define __AUDIO_ENGINE_INL_H_ + +#include +#include +#include +#include +#include "base/ccUtils.h" + +#define MAX_AUDIOINSTANCES 24 + +#define ERRORLOG(msg) log("fun:%s,line:%d,msg:%s",__func__,__LINE__,#msg) + +NS_CC_BEGIN + +class AudioEngineImpl; + +class AudioPlayer +{ +public: + AudioPlayer(); + ~AudioPlayer(); + + bool init(SLEngineItf engineEngine, SLObjectItf outputMixObject,const std::string& fileFullPath, float volume, bool loop); + +private: + + SLObjectItf _fdPlayerObject; + SLPlayItf _fdPlayerPlay; + SLSeekItf _fdPlayerSeek; + SLVolumeItf _fdPlayerVolume; + + float _duration; + int _audioID; + + std::function _finishCallback; + + friend class AudioEngineImpl; +}; + +class AudioEngineImpl +{ +public: + AudioEngineImpl(); + ~AudioEngineImpl(); + + bool init(); + int play2d(const std::string &fileFullPath ,bool loop ,float volume); + void setVolume(int audioID,float volume); + void setLoop(int audioID, bool loop); + void pause(int audioID); + void resume(int audioID); + void stop(int audioID); + void stopAll(); + float getDuration(int audioID); + float getCurrentTime(int audioID); + bool setCurrentTime(int audioID, float time); + void setFinishCallback(int audioID, const std::function &callback); + + void playerFinishCallback(SLPlayItf caller, SLuint32 playEvent); + + void uncache(const std::string& filePath){} + void uncacheAll(){} +private: + + // engine interfaces + SLObjectItf _engineObject; + SLEngineItf _engineEngine; + + // output mix interfaces + SLObjectItf _outputMixObject; + + //audioID,AudioInfo + std::unordered_map _audioPlayers; + + int currentAudioID; +}; + +#endif // __AUDIO_ENGINE_INL_H_ + +NS_CC_END + +#endif diff --git a/cocos/audio/include/AudioEngine.h b/cocos/audio/include/AudioEngine.h new file mode 100644 index 0000000000..a3663b0868 --- /dev/null +++ b/cocos/audio/include/AudioEngine.h @@ -0,0 +1,271 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS +#ifndef __AUDIO_ENGINE_H_ +#define __AUDIO_ENGINE_H_ + +#include +#include + +#include "2d/CCNode.h" +#include "Export.h" + +#ifdef ERROR +#undef ERROR +#endif // ERROR + +NS_CC_BEGIN + +class EXPORT_DLL AudioProfile +{ +public: + //name can't be empty + std::string name; + + unsigned int maxInstances; + + /* minimum delay in between sounds */ + double minDelay; + + AudioProfile() + : minDelay(0.0) + , maxInstances(0) + { + + } +}; + +class AudioEngineImpl; + +/** + @class AudioEngine + @brief + @note + */ + +class EXPORT_DLL AudioEngine +{ +public: + enum class AudioState + { + ERROR = -1, + INITIALZING, + PLAYING, + PAUSED + }; + + static const int INVAILD_AUDIO_ID; + + static const float TIME_UNKNOWN; + + static bool lazyInit(); + /** + * Release related objects + @warning It must be called before the application exit + */ + static void end(); + + /** Gets the default profile of audio instances + * @return the default profile of audio instances + */ + static AudioProfile* getDefaultProfile(); + + /** Play 2d sound + * @param filePath The path of an audio file + * @param loop Whether audio instance loop or not + * @param volume volume value (range from 0.0 to 1.0) + * @param profile a profile for audio instance + * @return an audio ID. It allows you to dynamically change the behavior of an audio instance on the fly. + */ + static int play2d(const std::string& filePath, bool loop = false, float volume = 1.0f, const AudioProfile *profile = nullptr); + + /** Sets whether an audio instance loop or not. + @param audioID an audioID returned by the play2d function + @param loop Whether audio instance loop or not + */ + static void setLoop(int audioID, bool loop); + + /** Checks whether an audio instance is loop. + * @param audioID an audioID returned by the play2d function + * @return Whether or not an audio instance is loop. + */ + static bool isLoop(int audioID); + + /** Sets volume for an audio instance. + * @param audioID an audioID returned by the play2d function + * @param volume volume value (range from 0.0 to 1.0) + */ + static void setVolume(int audioID, float volume); + + /** Gets the volume value of an audio instance. + * @param audioID an audioID returned by the play2d function + * @return volume value (range from 0.0 to 1.0) + */ + static float getVolume(int audioID); + + /** Pause an audio instance. + * @param audioID an audioID returned by the play2d function + */ + static void pause(int audioID); + + /** Pause all playing audio instances */ + static void pauseAll(); + + /** Resume an audio instance. + * @param audioID an audioID returned by the play2d function + */ + static void resume(int audioID); + + /** Resume all suspended audio instances */ + static void resumeAll(); + + /** Stop an audio instance. + * @param audioID an audioID returned by the play2d function + */ + static void stop(int audioID); + + /** Stop all audio instances */ + static void stopAll(); + + /** Sets the current playback position of an audio instance. + * @param audioID an audioID returned by the play2d function + * @return + */ + static bool setCurrentTime(int audioID, float time); + + /** Gets the current playback position of an audio instance. + * @param audioID an audioID returned by the play2d function + * @return the current playback position of an audio instance + */ + static float getCurrentTime(int audioID); + + /** Gets the duration of an audio instance. + * @param audioID an audioID returned by the play2d function + * @return the duration of an audio instance + */ + static float getDuration(int audioID); + + /** Returns the state of an audio instance. + * @param audioID an audioID returned by the play2d function + * @return the status of an audio instance + */ + static AudioState getState(int audioID); + + /** Register a callback to be invoked when an audio instance has completed playing. + * @param audioID an audioID returned by the play2d function + * @param callback + */ + static void setFinishCallback(int audioID, const std::function& callback); + + static int getMaxAudioInstance() {return _maxInstances;} + + static bool setMaxAudioInstance(int maxInstances); + + /** Uncache the audio data from internal buffer. + * AudioEngine cache audio data on ios platform + * @warning This can lead to stop related audio first. + * @param filePath The path of an audio file + */ + static void uncache(const std::string& filePath); + + /** Uncache all audio data from internal buffer. + * @warning All audio will be stopped first. + * @param + */ + static void uncacheAll(); + + /** Gets the audio profile by id of audio instance. + * @param audioID an audioID returned by the play2d function + * @return the audio profile + */ + static AudioProfile* getProfile(int audioID); + + /** Gets the audio profile by name. + * @param name name of audio profile + * @return the audio profile + */ + static AudioProfile* getProfile(const std::string &name); + +protected: + + static void remove(int audioID); + + struct ProfileHelper + { + AudioProfile profile; + + std::list audioIDs; + + double lastPlayTime; + + ProfileHelper() + : lastPlayTime(0.0) + { + + } + }; + + struct AudioInfo + { + const std::string* filePath; + ProfileHelper* profileHelper; + + float volume; + bool loop; + float duration; + AudioState state; + + bool is3dAudio; + + AudioInfo() + : profileHelper(nullptr) + , duration(TIME_UNKNOWN) + , state(AudioState::INITIALZING) + { + + } + }; + + //audioID,audioAttribute + static std::unordered_map _audioIDInfoMap; + + //audio file path,audio IDs + static std::unordered_map> _audioPathIDMap; + + //profileName,ProfileHelper + static std::unordered_map _audioPathProfileHelperMap; + + static int _maxInstances; + + static ProfileHelper* _defaultProfileHelper; + + static AudioEngineImpl* _audioEngineImpl; + + friend class AudioEngineImpl; +}; + +NS_CC_END + +#endif // __AUDIO_ENGINE_H_ +#endif diff --git a/cocos/audio/ios/AudioCache.h b/cocos/audio/ios/AudioCache.h new file mode 100644 index 0000000000..603350e507 --- /dev/null +++ b/cocos/audio/ios/AudioCache.h @@ -0,0 +1,98 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS + +#ifndef __AUDIO_CACHE_H_ +#define __AUDIO_CACHE_H_ + +#import +#import + +#include +#include +#include + +#include "CCPlatformMacros.h" + +#define QUEUEBUFFER_NUM 3 +#define QUEUEBUFFER_TIME_STEP 0.1 + +NS_CC_BEGIN + +class AudioEngineImpl; +class AudioPlayer; + +class AudioCache{ +public: + AudioCache(); + ~AudioCache(); + + void addCallbacks(const std::function &callback); + +private: + + void readDataTask(); + + void invokingCallbacks(); + + //pcm data related stuff + ALsizei _dataSize; + ALenum _format; + ALsizei _sampleRate; + float _duration; + int _bytesPerFrame; + AudioStreamBasicDescription outputFormat; + + /*Cache related stuff; + * Cache pcm data when sizeInBytes less than PCMDATA_CACHEMAXSIZE + */ + ALuint _alBufferId; + char* _pcmData; + SInt64 _bytesOfRead; + + /*Queue buffer related stuff + * Streaming in openal when sizeInBytes greater then PCMDATA_CACHEMAXSIZE + */ + char* _queBuffers[QUEUEBUFFER_NUM]; + UInt32 _queBufferFrames; + UInt32 _queBufferBytes; + + bool _alBufferReady; + std::mutex _callbackMutex; + + std::vector< std::function > _callbacks; + std::mutex _readDataTaskMutex; + + bool _exitReadDataTask; + std::string _fileFullPath; + + friend class AudioEngineImpl; + friend class AudioPlayer; +} ; + +NS_CC_END + +#endif // __AUDIO_CACHE_H_ +#endif + diff --git a/cocos/audio/ios/AudioCache.mm b/cocos/audio/ios/AudioCache.mm new file mode 100644 index 0000000000..33fae2fb40 --- /dev/null +++ b/cocos/audio/ios/AudioCache.mm @@ -0,0 +1,239 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#include "AudioCache.h" +#include +#import +#import + +#define PCMDATA_CACHEMAXSIZE 1048576 + +typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq); +static ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) +{ + static alBufferDataStaticProcPtr proc = NULL; + + if (proc == NULL){ + proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); + } + + if (proc){ + proc(bid, format, data, size, freq); + } + + return; +} +using namespace cocos2d; + +AudioCache::AudioCache() +: _pcmData(nullptr) +, _dataSize(0) +, _bytesOfRead(0) +, _exitReadDataTask(false) +, _queBufferFrames(0) +, _queBufferBytes(0) +, _alBufferReady(false) +{ + +} + +AudioCache::~AudioCache() +{ + _exitReadDataTask = true; + if(_pcmData){ + if (_alBufferReady){ + alDeleteBuffers(1, &_alBufferId); + } + //wait for the 'readDataTask' task to exit + _readDataTaskMutex.lock(); + _readDataTaskMutex.unlock(); + + free(_pcmData); + } + + if (_queBufferFrames > 0) { + for (int index = 0; index < QUEUEBUFFER_NUM; ++index) { + free(_queBuffers[index]); + } + } +} + +void AudioCache::readDataTask() +{ + _readDataTaskMutex.lock(); + + AudioStreamBasicDescription theFileFormat; + UInt32 thePropertySize = sizeof(theFileFormat); + + SInt64 theFileLengthInFrames; + SInt64 readInFrames; + SInt64 dataSize; + SInt64 frames; + AudioBufferList theDataBuffer; + ExtAudioFileRef extRef = nullptr; + + auto fileURL = (CFURLRef)[[NSURL fileURLWithPath:[NSString stringWithCString:_fileFullPath.c_str() encoding:[NSString defaultCStringEncoding]]] retain]; + + auto error = ExtAudioFileOpenURL(fileURL, &extRef); + if(error) { + printf("%s: ExtAudioFileOpenURL FAILED, Error = %d\n", __PRETTY_FUNCTION__, error); + goto ExitThread; + } + + // Get the audio data format + error = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat); + if(error) { + printf("%s: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %d\n", __PRETTY_FUNCTION__, error); + goto ExitThread; + } + if (theFileFormat.mChannelsPerFrame > 2) { + printf("%s: Unsupported Format, channel count is greater than stereo\n",__PRETTY_FUNCTION__); + goto ExitThread; + } + + // Set the client format to 16 bit signed integer (native-endian) data + // Maintain the channel count and sample rate of the original source format + outputFormat.mSampleRate = theFileFormat.mSampleRate; + outputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame; + + _bytesPerFrame = 2 * outputFormat.mChannelsPerFrame; + outputFormat.mFormatID = kAudioFormatLinearPCM; + outputFormat.mBytesPerPacket = _bytesPerFrame; + outputFormat.mFramesPerPacket = 1; + outputFormat.mBytesPerFrame = _bytesPerFrame; + outputFormat.mBitsPerChannel = 16; + outputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; + + error = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(outputFormat), &outputFormat); + if(error) { + printf("%s: ExtAudioFileSetProperty FAILED, Error = %d\n", __PRETTY_FUNCTION__, error); + goto ExitThread; + } + + // Get the total frame count + thePropertySize = sizeof(theFileLengthInFrames); + error = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames); + if(error) { + printf("%s: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %d\n", __PRETTY_FUNCTION__, error); + goto ExitThread; + } + + _dataSize = (ALsizei)(theFileLengthInFrames * outputFormat.mBytesPerFrame); + _format = (outputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; + _sampleRate = (ALsizei)outputFormat.mSampleRate; + _duration = 1.0f * theFileLengthInFrames / outputFormat.mSampleRate; + + if (_dataSize <= PCMDATA_CACHEMAXSIZE) { + _pcmData = (char*)malloc(_dataSize); + alGenBuffers(1, &_alBufferId); + auto alError = alGetError(); + if (alError != AL_NO_ERROR) { + printf("%s: attaching audio to buffer fail: %x\n", __PRETTY_FUNCTION__, alError); + goto ExitThread; + } + alBufferDataStaticProc(_alBufferId, _format, _pcmData, _dataSize, _sampleRate); + + readInFrames = theFileFormat.mSampleRate * QUEUEBUFFER_TIME_STEP * QUEUEBUFFER_NUM; + dataSize = outputFormat.mBytesPerFrame * readInFrames; + if (dataSize > _dataSize) { + dataSize = _dataSize; + readInFrames = theFileLengthInFrames; + } + theDataBuffer.mNumberBuffers = 1; + theDataBuffer.mBuffers[0].mDataByteSize = (UInt32)dataSize; + theDataBuffer.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame; + + theDataBuffer.mBuffers[0].mData = _pcmData; + frames = readInFrames; + ExtAudioFileRead(extRef, (UInt32*)&frames, &theDataBuffer); + _alBufferReady = true; + _bytesOfRead += dataSize; + invokingCallbacks(); + + while (!_exitReadDataTask && _bytesOfRead + dataSize < _dataSize) { + theDataBuffer.mBuffers[0].mData = _pcmData + _bytesOfRead; + frames = readInFrames; + ExtAudioFileRead(extRef, (UInt32*)&frames, &theDataBuffer); + _bytesOfRead += dataSize; + } + + dataSize = _dataSize - _bytesOfRead; + if (!_exitReadDataTask && dataSize > 0) { + theDataBuffer.mBuffers[0].mDataByteSize = (UInt32)dataSize; + theDataBuffer.mBuffers[0].mData = _pcmData + _bytesOfRead; + frames = readInFrames; + ExtAudioFileRead(extRef, (UInt32*)&frames, &theDataBuffer); + } + + _bytesOfRead = _dataSize; + } + else{ + _queBufferFrames = theFileFormat.mSampleRate * QUEUEBUFFER_TIME_STEP; + _queBufferBytes = _queBufferFrames * outputFormat.mBytesPerFrame; + + theDataBuffer.mNumberBuffers = QUEUEBUFFER_NUM; + for (int index = 0; index < QUEUEBUFFER_NUM; ++index) { + _queBuffers[index] = (char*)malloc(_queBufferBytes); + + theDataBuffer.mBuffers[index].mDataByteSize = _queBufferBytes; + theDataBuffer.mBuffers[index].mNumberChannels = outputFormat.mChannelsPerFrame; + theDataBuffer.mBuffers[index].mData = _queBuffers[index]; + } + + frames = _queBufferFrames * QUEUEBUFFER_NUM; + ExtAudioFileRead(extRef, (UInt32*)&frames, &theDataBuffer); + } + +ExitThread: + CFRelease(fileURL); + if (extRef) + ExtAudioFileDispose(extRef); + + _readDataTaskMutex.unlock(); + if (_queBufferFrames > 0) + _alBufferReady = true; + + invokingCallbacks(); +} + +void AudioCache::invokingCallbacks() +{ + _callbackMutex.lock(); + auto count = _callbacks.size(); + for (size_t index = 0; index < count; ++index) { + _callbacks[index](); + } + _callbacks.clear(); + _callbackMutex.unlock(); +} + +void AudioCache::addCallbacks(const std::function &callback) +{ + _callbackMutex.lock(); + if (_alBufferReady) { + callback(); + } else { + _callbacks.push_back(callback); + } + _callbackMutex.unlock(); +} diff --git a/cocos/audio/ios/AudioEngine-inl.h b/cocos/audio/ios/AudioEngine-inl.h new file mode 100644 index 0000000000..1f67978435 --- /dev/null +++ b/cocos/audio/ios/AudioEngine-inl.h @@ -0,0 +1,94 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS + +#ifndef __AUDIO_ENGINE_INL_H_ +#define __AUDIO_ENGINE_INL_H_ + +#include + +#include "base/CCRef.h" +#include "AudioCache.h" +#include "AudioPlayer.h" + +NS_CC_BEGIN + +#define MAX_AUDIOINSTANCES 32 + +class AudioEngineThreadPool; + +class AudioEngineImpl : public cocos2d::Ref +{ +public: + AudioEngineImpl(); + ~AudioEngineImpl(); + + bool init(); + int play2d(const std::string &fileFullPath ,bool loop ,float volume); + void setVolume(int audioID,float volume); + void setLoop(int audioID, bool loop); + bool pause(int audioID); + bool resume(int audioID); + bool stop(int audioID); + void stopAll(); + float getDuration(int audioID); + float getCurrentTime(int audioID); + bool setCurrentTime(int audioID, float time); + void setFinishCallback(int audioID, const std::function &callback); + + void uncache(const std::string& filePath); + void uncacheAll(); + + void update(float dt); + +private: + void _play2d(AudioCache *cache, int audioID); + + AudioEngineThreadPool* _threadPool; + + ALuint _alSources[MAX_AUDIOINSTANCES]; + + //source,used + std::unordered_map _alSourceUsed; + + //filePath,bufferInfo + std::unordered_map _audioCaches; + + //audioID,AudioInfo + std::unordered_map _audioPlayers; + + std::mutex _threadMutex; + + std::vector _toRemoveCaches; + std::vector _toRemoveAudioIDs; + + bool _lazyInitLoop; + + int _currentAudioID; + +}; +NS_CC_END +#endif // __AUDIO_ENGINE_INL_H_ +#endif + diff --git a/cocos/audio/ios/AudioEngine-inl.mm b/cocos/audio/ios/AudioEngine-inl.mm new file mode 100644 index 0000000000..e81ade8588 --- /dev/null +++ b/cocos/audio/ios/AudioEngine-inl.mm @@ -0,0 +1,505 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#include "AudioEngine-inl.h" +#include "audio/include/AudioEngine.h" + +#import +#include "platform/CCFileUtils.h" +#include "base/CCDirector.h" +#include "base/CCScheduler.h" +#include "base/ccUtils.h" + +using namespace cocos2d; + +static ALCdevice *s_ALDevice = nullptr; +static ALCcontext *s_ALContext = nullptr; + +static void AudioInterrupionListenerCallback(void* user_data, UInt32 interruption_state) +{ + if(kAudioSessionBeginInterruption == interruption_state){ + alcMakeContextCurrent(nullptr); + } + else if (kAudioSessionEndInterruption == interruption_state){ + AudioSessionSetActive(true); + alcMakeContextCurrent(s_ALContext); + } +} + +namespace cocos2d { + class AudioEngineThreadPool + { + public: + AudioEngineThreadPool() + : _running(true) + , _numThread(6) + { + _threads.reserve(_numThread); + _tasks.reserve(_numThread); + + for (int index = 0; index < _numThread; ++index) { + _tasks.push_back(nullptr); + _threads.push_back( std::thread( std::bind(&AudioEngineThreadPool::threadFunc,this,index) ) ); + } + } + + void addTask(const std::function &task){ + _taskMutex.lock(); + int targetIndex = -1; + for (int index = 0; index < _numThread; ++index) { + if (_tasks[index] == nullptr) { + targetIndex = index; + _tasks[index] = task; + break; + } + } + if (targetIndex == -1) { + _tasks.push_back(task); + _threads.push_back( std::thread( std::bind(&AudioEngineThreadPool::threadFunc,this,_numThread) ) ); + + _numThread++; + } + _taskMutex.unlock(); + + _sleepCondition.notify_all(); + } + + void destroy() + { + _running = false; + _sleepCondition.notify_all(); + + for (int index = 0; index < _numThread; ++index) { + _threads[index].join(); + } + } + + private: + bool _running; + std::vector _threads; + std::vector< std::function > _tasks; + + void threadFunc(int index) + { + while (_running) { + std::function task = nullptr; + _taskMutex.lock(); + task = _tasks[index]; + _taskMutex.unlock(); + + if (nullptr == task) + { + std::unique_lock lk(_sleepMutex); + _sleepCondition.wait(lk); + continue; + } + + task(); + + _taskMutex.lock(); + _tasks[index] = nullptr; + _taskMutex.unlock(); + } + } + + int _numThread; + + std::mutex _taskMutex; + std::mutex _sleepMutex; + std::condition_variable _sleepCondition; + + }; +} + +AudioEngineImpl::AudioEngineImpl() +: _lazyInitLoop(true) +, _currentAudioID(0) +, _threadPool(nullptr) +{ + +} + +AudioEngineImpl::~AudioEngineImpl() +{ + if (s_ALContext) { + alDeleteSources(MAX_AUDIOINSTANCES, _alSources); + + _audioCaches.clear(); + + alcDestroyContext(s_ALContext); + } + if (s_ALDevice) { + alcCloseDevice(s_ALDevice); + } + if (_threadPool) { + _threadPool->destroy(); + delete _threadPool; + } +} + +bool AudioEngineImpl::init() +{ + //set up the audio session + AudioSessionInitialize(nullptr, nullptr, AudioInterrupionListenerCallback, nullptr); + + bool ret = false; + do{ + s_ALDevice = alcOpenDevice(nullptr); + + if (s_ALDevice) { + auto alError = alGetError(); + s_ALContext = alcCreateContext(s_ALDevice, nullptr); + alcMakeContextCurrent(s_ALContext); + + alGenSources(MAX_AUDIOINSTANCES, _alSources); + alError = alGetError(); + if(alError != AL_NO_ERROR) + { + printf("%s:generating sources fail! error = %x\n", __PRETTY_FUNCTION__, alError); + break; + } + + for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) { + _alSourceUsed[_alSources[i]] = false; + } + + _threadPool = new (std::nothrow) AudioEngineThreadPool(); + ret = true; + } + }while (false); + + return ret; +} + +int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume) +{ + if (s_ALDevice == nullptr) { + return AudioEngine::INVAILD_AUDIO_ID; + } + + bool sourceFlag = false; + ALuint alSource = 0; + for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) { + alSource = _alSources[i]; + + if ( !_alSourceUsed[alSource]) { + sourceFlag = true; + break; + } + } + if(!sourceFlag){ + return AudioEngine::INVAILD_AUDIO_ID; + } + + AudioCache* audioCache = nullptr; + auto it = _audioCaches.find(filePath); + if (it == _audioCaches.end()) { + audioCache = &_audioCaches[filePath]; + audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath); + + _threadPool->addTask(std::bind(&AudioCache::readDataTask, audioCache)); + } + else { + audioCache = &it->second; + } + + auto player = &_audioPlayers[_currentAudioID]; + player->_alSource = alSource; + player->_loop = loop; + player->_volume = volume; + audioCache->addCallbacks(std::bind(&AudioEngineImpl::_play2d,this,audioCache,_currentAudioID)); + + _alSourceUsed[alSource] = true; + + if (_lazyInitLoop) { + _lazyInitLoop = false; + + auto scheduler = cocos2d::Director::getInstance()->getScheduler(); + scheduler->schedule(schedule_selector(AudioEngineImpl::update), this, 0.05f, false); + } + + return _currentAudioID++; +} + +void AudioEngineImpl::_play2d(AudioCache *cache, int audioID) +{ + if(cache->_alBufferReady){ + auto playerIt = _audioPlayers.find(audioID); + if (playerIt != _audioPlayers.end()) { + if (playerIt->second.play2d(cache)) { + AudioEngine::_audioIDInfoMap[audioID].state = AudioEngine::AudioState::PLAYING; + } + else{ + _threadMutex.lock(); + _toRemoveAudioIDs.push_back(audioID); + _threadMutex.unlock(); + } + } + } + else { + _threadMutex.lock(); + _toRemoveCaches.push_back(cache); + _toRemoveAudioIDs.push_back(audioID); + _threadMutex.unlock(); + } +} + +void AudioEngineImpl::setVolume(int audioID,float volume) +{ + auto& player = _audioPlayers[audioID]; + player._volume = volume; + + if (player._ready) { + alSourcef(_audioPlayers[audioID]._alSource, AL_GAIN, volume); + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + printf("%s: audio id = %d, error = %x\n", __PRETTY_FUNCTION__,audioID,error); + } + } +} + +void AudioEngineImpl::setLoop(int audioID, bool loop) +{ + auto& player = _audioPlayers[audioID]; + + if (player._ready) { + if (player._streamingSource) { + player.setLoop(loop); + } else { + if (loop) { + alSourcei(player._alSource, AL_LOOPING, AL_TRUE); + } else { + alSourcei(player._alSource, AL_LOOPING, AL_FALSE); + } + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + printf("%s: audio id = %d, error = %x\n", __PRETTY_FUNCTION__,audioID,error); + } + } + } + else { + player._loop = loop; + } +} + +bool AudioEngineImpl::pause(int audioID) +{ + bool ret = true; + alSourcePause(_audioPlayers[audioID]._alSource); + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + ret = false; + printf("%s: audio id = %d, error = %x\n", __PRETTY_FUNCTION__,audioID,error); + } + + return ret; +} + +bool AudioEngineImpl::resume(int audioID) +{ + bool ret = true; + alSourcePlay(_audioPlayers[audioID]._alSource); + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + ret = false; + printf("%s: audio id = %d, error = %x\n", __PRETTY_FUNCTION__,audioID,error); + } + + return ret; +} + +bool AudioEngineImpl::stop(int audioID) +{ + bool ret = true; + auto& player = _audioPlayers[audioID]; + if (player._ready) { + alSourceStop(player._alSource); + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + ret = false; + printf("%s: audio id = %d, error = %x\n", __PRETTY_FUNCTION__,audioID,error); + } + } + + alSourcei(player._alSource, AL_BUFFER, NULL); + + _alSourceUsed[player._alSource] = false; + _audioPlayers.erase(audioID); + + return ret; +} + +void AudioEngineImpl::stopAll() +{ + for(int index = 0; index < MAX_AUDIOINSTANCES; ++index) + { + alSourceStop(_alSources[index]); + alSourcei(_alSources[index], AL_BUFFER, NULL); + _alSourceUsed[_alSources[index]] = false; + } + + _audioPlayers.clear(); +} + +float AudioEngineImpl::getDuration(int audioID) +{ + auto& player = _audioPlayers[audioID]; + if(player._ready){ + return player._audioCache->_duration; + } else { + return AudioEngine::TIME_UNKNOWN; + } +} + +float AudioEngineImpl::getCurrentTime(int audioID) +{ + float ret = 0.0f; + auto& player = _audioPlayers[audioID]; + if(player._ready){ + if (player._streamingSource) { + ret = player.getTime(); + } else { + alGetSourcef(player._alSource, AL_SEC_OFFSET, &ret); + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + printf("%s, audio id:%d,error code:%x", __PRETTY_FUNCTION__,audioID,error); + } + } + } + + return ret; +} + +bool AudioEngineImpl::setCurrentTime(int audioID, float time) +{ + bool ret = false; + auto& player = _audioPlayers[audioID]; + + do { + if (!player._ready) { + break; + } + + if (player._streamingSource) { + ret = player.setTime(time); + break; + } + else { + if (player._audioCache->_bytesOfRead != player._audioCache->_dataSize && + (time * player._audioCache->_sampleRate * player._audioCache->_bytesPerFrame) > player._audioCache->_bytesOfRead) { + printf("%s: audio id = %d\n", __PRETTY_FUNCTION__,audioID); + break; + } + + alSourcef(player._alSource, AL_SEC_OFFSET, time); + + auto error = alGetError(); + if (error != AL_NO_ERROR) { + printf("%s: audio id = %d, error = %x\n", __PRETTY_FUNCTION__,audioID,error); + } + ret = true; + } + } while (0); + + return ret; +} + +void AudioEngineImpl::setFinishCallback(int audioID, const std::function &callback) +{ + _audioPlayers[audioID]._finishCallbak = callback; +} + +void AudioEngineImpl::update(float dt) +{ + ALint sourceState; + int audioID; + + if (_threadMutex.try_lock()) { + size_t removeAudioCount = _toRemoveAudioIDs.size(); + for (size_t index = 0; index < removeAudioCount; ++index) { + audioID = _toRemoveAudioIDs[index]; + auto playerIt = _audioPlayers.find(audioID); + if (playerIt != _audioPlayers.end()) { + _alSourceUsed[playerIt->second._alSource] = false; + _audioPlayers.erase(audioID); + AudioEngine::remove(audioID); + } + } + size_t removeCacheCount = _toRemoveCaches.size(); + for (size_t index = 0; index < removeCacheCount; ++index) { + auto itEnd = _audioCaches.end(); + for (auto it = _audioCaches.begin(); it != itEnd; ++it) { + if (&it->second == _toRemoveCaches[index]) { + _audioCaches.erase(it); + break; + } + } + } + _threadMutex.unlock(); + } + + for (auto it = _audioPlayers.begin(); it != _audioPlayers.end(); ) { + audioID = it->first; + auto& player = it->second; + alGetSourcei(player._alSource, AL_SOURCE_STATE, &sourceState); + + if (player._ready && sourceState == AL_STOPPED) { + _alSourceUsed[player._alSource] = false; + auto& audioInfo = AudioEngine::_audioIDInfoMap[audioID]; + if (player._finishCallbak) { + player._finishCallbak(audioID, *audioInfo.filePath); + } + + AudioEngine::remove(audioID); + + it = _audioPlayers.erase(it); + } + else{ + ++it; + } + } + + if(_audioPlayers.empty()){ + _lazyInitLoop = true; + + auto scheduler = cocos2d::Director::getInstance()->getScheduler(); + scheduler->unschedule(schedule_selector(AudioEngineImpl::update), this); + } +} + +void AudioEngineImpl::uncache(const std::string &filePath) +{ + auto fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath); + _audioCaches.erase(fileFullPath); +} + +void AudioEngineImpl::uncacheAll() +{ + _audioCaches.clear(); +} diff --git a/cocos/audio/ios/AudioPlayer.h b/cocos/audio/ios/AudioPlayer.h new file mode 100644 index 0000000000..76d9e3ad31 --- /dev/null +++ b/cocos/audio/ios/AudioPlayer.h @@ -0,0 +1,76 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS + +#ifndef __AUDIO_PLAYER_H_ +#define __AUDIO_PLAYER_H_ + +#import +#include +#include +#include "CCPlatformMacros.h" + +NS_CC_BEGIN +class AudioCache; +class AudioEngineImpl; + +class AudioPlayer +{ +public: + AudioPlayer(); + ~AudioPlayer(); + + //queue buffer related stuff + bool setTime(float time); + float getTime() { return _currTime;} + bool setLoop(bool loop); + +private: + void rotateBufferThread(int offsetFrame); + bool play2d(AudioCache* cache); + + AudioCache* _audioCache; + + float _volume; + bool _loop; + std::function _finishCallbak; + + bool _ready; + ALuint _alSource; + + //play by circular buffer + float _currTime; + bool _streamingSource; + ALuint _bufferIds[3]; + std::thread _rotateBufferThread; + std::timed_mutex _timeMtx; + bool _exitThread; + bool _timeDirty; + + friend class AudioEngineImpl; +}; +NS_CC_END +#endif // __AUDIO_PLAYER_H_ +#endif + diff --git a/cocos/audio/ios/AudioPlayer.mm b/cocos/audio/ios/AudioPlayer.mm new file mode 100644 index 0000000000..c7d93216d4 --- /dev/null +++ b/cocos/audio/ios/AudioPlayer.mm @@ -0,0 +1,214 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#include "AudioPlayer.h" +#include "AudioCache.h" +#include "platform/CCFileUtils.h" +#import + +using namespace cocos2d; + +AudioPlayer::AudioPlayer() +: _exitThread(false) +, _timeDirty(false) +, _streamingSource(false) +, _currTime(0.0f) +, _finishCallbak(nullptr) +, _ready(false) +, _audioCache(nullptr) +{ + +} + +AudioPlayer::~AudioPlayer() +{ + _exitThread = true; + if (_audioCache && _audioCache->_queBufferFrames > 0) { + _timeMtx.unlock(); + if (_rotateBufferThread.joinable()) { + _rotateBufferThread.join(); + } + alDeleteBuffers(3, _bufferIds); + } +} + +bool AudioPlayer::play2d(AudioCache* cache) +{ + if (!cache->_alBufferReady) { + return false; + } + _audioCache = cache; + + alSourcei(_alSource, AL_BUFFER, NULL); + alSourcef(_alSource, AL_PITCH, 1.0f); + alSourcef(_alSource, AL_GAIN, _volume); + + if (_audioCache->_queBufferFrames == 0) { + if (_loop) { + alSourcei(_alSource, AL_LOOPING, AL_TRUE); + } + else { + alSourcei(_alSource, AL_LOOPING, AL_FALSE); + } + alSourcei(_alSource, AL_BUFFER, _audioCache->_alBufferId); + + } else { + _streamingSource = true; + + auto alError = alGetError(); + alGenBuffers(3, _bufferIds); + alError = alGetError(); + if (alError == AL_NO_ERROR) { + for (int index = 0; index < QUEUEBUFFER_NUM; ++index) { + alBufferData(_bufferIds[index], _audioCache->_format, _audioCache->_queBuffers[index], _audioCache->_queBufferBytes, _audioCache->_sampleRate); + } + alSourcei(_alSource, AL_BUFFER, NULL); + alSourceQueueBuffers(_alSource, QUEUEBUFFER_NUM, _bufferIds); + + _timeMtx.lock(); + _rotateBufferThread = std::thread(&AudioPlayer::rotateBufferThread,this, _audioCache->_queBufferFrames * QUEUEBUFFER_NUM + 1); + } + else { + printf("%s:alGenBuffers error code:%x", __PRETTY_FUNCTION__,alError); + return false; + } + } + + alSourcePlay(_alSource); + _ready = true; + auto alError = alGetError(); + + if (alError != AL_NO_ERROR) { + printf("%s:alSourcePlay error code:%x\n", __PRETTY_FUNCTION__,alError); + return false; + } + + return true; +} + +void AudioPlayer::rotateBufferThread(int offsetFrame) +{ + printf("%s start\n",__PRETTY_FUNCTION__); + + ALint sourceState; + ALint bufferProcessed = 0; + ExtAudioFileRef extRef = nullptr; + + auto fileURL = (CFURLRef)[[NSURL fileURLWithPath:[NSString stringWithCString:_audioCache->_fileFullPath.c_str() encoding:[NSString defaultCStringEncoding]]] retain]; + char* tmpBuffer = (char*)malloc(_audioCache->_queBufferBytes); + auto frames = _audioCache->_queBufferFrames; + + auto error = ExtAudioFileOpenURL(fileURL, &extRef); + if(error) { + printf("%s: ExtAudioFileOpenURL FAILED, Error = %d\n", __PRETTY_FUNCTION__, error); + goto ExitBufferThread; + } + + error = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(_audioCache->outputFormat), &_audioCache->outputFormat); + AudioBufferList theDataBuffer; + theDataBuffer.mNumberBuffers = 1; + theDataBuffer.mBuffers[0].mData = tmpBuffer; + theDataBuffer.mBuffers[0].mDataByteSize = _audioCache->_queBufferBytes; + theDataBuffer.mBuffers[0].mNumberChannels = _audioCache->outputFormat.mChannelsPerFrame; + + if (offsetFrame != 0) { + ExtAudioFileSeek(extRef, offsetFrame); + } + + while (!_exitThread) { + alGetSourcei(_alSource, AL_SOURCE_STATE, &sourceState); + if (sourceState == AL_PLAYING) { + alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &bufferProcessed); + while (bufferProcessed > 0) { + bufferProcessed--; + if (_timeDirty) { + _timeDirty = false; + offsetFrame = _currTime * _audioCache->outputFormat.mSampleRate; + ExtAudioFileSeek(extRef, offsetFrame); + } + else { + _currTime += QUEUEBUFFER_TIME_STEP; + if (_currTime > _audioCache->_duration) { + if (_loop) { + _currTime = 0.0f; + } else { + _currTime = _audioCache->_duration; + } + } + } + + frames = _audioCache->_queBufferFrames; + ExtAudioFileRead(extRef, (UInt32*)&frames, &theDataBuffer); + if (frames <= 0) { + if (_loop) { + ExtAudioFileSeek(extRef, 0); + frames = _audioCache->_queBufferFrames; + theDataBuffer.mBuffers[0].mDataByteSize = _audioCache->_queBufferBytes; + ExtAudioFileRead(extRef, (UInt32*)&frames, &theDataBuffer); + } else { + _exitThread = true; + break; + } + } + + ALuint bid; + alSourceUnqueueBuffers(_alSource, 1, &bid); + alBufferData(bid, _audioCache->_format, tmpBuffer, frames * _audioCache->outputFormat.mBytesPerFrame, _audioCache->_sampleRate); + alSourceQueueBuffers(_alSource, 1, &bid); + } + } + + _timeMtx.try_lock_for(std::chrono::milliseconds(50)); + } + +ExitBufferThread: + CFRelease(fileURL); + // Dispose the ExtAudioFileRef, it is no longer needed + if (extRef){ + ExtAudioFileDispose(extRef); + } + free(tmpBuffer); + printf("%s: end\n",__PRETTY_FUNCTION__); +} + +bool AudioPlayer::setLoop(bool loop) +{ + if (!_exitThread ) { + _loop = loop; + return true; + } + + return false; +} + +bool AudioPlayer::setTime(float time) +{ + if (!_exitThread && time >= 0.0f && time < _audioCache->_duration) { + + _currTime = time; + _timeDirty = true; + + return true; + } + return false; +} diff --git a/cocos/editor-support/cocostudio/CCArmature.cpp b/cocos/editor-support/cocostudio/CCArmature.cpp index a005e23127..62517e1604 100644 --- a/cocos/editor-support/cocostudio/CCArmature.cpp +++ b/cocos/editor-support/cocostudio/CCArmature.cpp @@ -486,8 +486,9 @@ void Armature::visit(cocos2d::Renderer *renderer, const Mat4 &parentTransform, u sortAllChildren(); draw(renderer, _modelViewTransform, flags); - // reset for next frame - _orderOfArrival = 0; + // FIX ME: Why need to set _orderOfArrival to 0?? + // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 + // setOrderOfArrival(0); director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); } diff --git a/cocos/editor-support/cocostudio/CCBatchNode.cpp b/cocos/editor-support/cocostudio/CCBatchNode.cpp index c8128748f3..19d339d6c7 100644 --- a/cocos/editor-support/cocostudio/CCBatchNode.cpp +++ b/cocos/editor-support/cocostudio/CCBatchNode.cpp @@ -124,8 +124,9 @@ void BatchNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t sortAllChildren(); draw(renderer, _modelViewTransform, flags); - // reset for next frame - _orderOfArrival = 0; + // FIX ME: Why need to set _orderOfArrival to 0?? + // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 + // setOrderOfArrival(0); director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); } diff --git a/cocos/math/Mat4.cpp b/cocos/math/Mat4.cpp index ff598d3da8..1e3dc5a972 100644 --- a/cocos/math/Mat4.cpp +++ b/cocos/math/Mat4.cpp @@ -414,8 +414,11 @@ void Mat4::add(float scalar) void Mat4::add(float scalar, Mat4* dst) { GP_ASSERT(dst); - +#ifdef __SSE__ + MathUtil::addMatrix(col, scalar, dst->col); +#else MathUtil::addMatrix(m, scalar, dst->m); +#endif } void Mat4::add(const Mat4& mat) @@ -426,8 +429,11 @@ void Mat4::add(const Mat4& mat) void Mat4::add(const Mat4& m1, const Mat4& m2, Mat4* dst) { GP_ASSERT(dst); - +#ifdef __SSE__ + MathUtil::addMatrix(m1.col, m2.col, dst->col); +#else MathUtil::addMatrix(m1.m, m2.m, dst->m); +#endif } bool Mat4::decompose(Vec3* scale, Quaternion* rotation, Vec3* translation) const @@ -700,8 +706,11 @@ void Mat4::multiply(float scalar, Mat4* dst) const void Mat4::multiply(const Mat4& m, float scalar, Mat4* dst) { GP_ASSERT(dst); - +#ifdef __SSE__ + MathUtil::multiplyMatrix(m.col, scalar, dst->col); +#else MathUtil::multiplyMatrix(m.m, scalar, dst->m); +#endif } void Mat4::multiply(const Mat4& mat) @@ -712,13 +721,20 @@ void Mat4::multiply(const Mat4& mat) void Mat4::multiply(const Mat4& m1, const Mat4& m2, Mat4* dst) { GP_ASSERT(dst); - +#ifdef __SSE__ + MathUtil::multiplyMatrix(m1.col, m2.col, dst->col); +#else MathUtil::multiplyMatrix(m1.m, m2.m, dst->m); +#endif } void Mat4::negate() { +#ifdef __SSE__ + MathUtil::negateMatrix(col, col); +#else MathUtil::negateMatrix(m, m); +#endif } Mat4 Mat4::getNegated() const @@ -870,8 +886,11 @@ void Mat4::subtract(const Mat4& mat) void Mat4::subtract(const Mat4& m1, const Mat4& m2, Mat4* dst) { GP_ASSERT(dst); - +#ifdef __SSE__ + MathUtil::subtractMatrix(m1.col, m2.col, dst->col); +#else MathUtil::subtractMatrix(m1.m, m2.m, dst->m); +#endif } void Mat4::transformPoint(Vec3* point) const @@ -912,8 +931,11 @@ void Mat4::transformVector(Vec4* vector) const void Mat4::transformVector(const Vec4& vector, Vec4* dst) const { GP_ASSERT(dst); - +#ifdef __SSE__ + MathUtil::transformVec4(col, vector.v, dst->v); +#else MathUtil::transformVec4(m, (const float*) &vector, (float*)dst); +#endif } void Mat4::translate(float x, float y, float z) @@ -940,7 +962,11 @@ void Mat4::translate(const Vec3& t, Mat4* dst) const void Mat4::transpose() { +#ifdef __SSE__ + MathUtil::transposeMatrix(col, col); +#else MathUtil::transposeMatrix(m, m); +#endif } Mat4 Mat4::getTransposed() const diff --git a/cocos/math/Mat4.h b/cocos/math/Mat4.h index 53b4b64da1..7616221943 100644 --- a/cocos/math/Mat4.h +++ b/cocos/math/Mat4.h @@ -24,6 +24,10 @@ #include "math/Vec3.h" #include "math/Vec4.h" +#ifdef __SSE__ +#include +#endif + NS_CC_MATH_BEGIN //class Plane; @@ -77,7 +81,14 @@ public: /** * Stores the columns of this 4x4 matrix. * */ +#ifdef __SSE__ + union { + __m128 col[4]; + float m[16]; + }; +#else float m[16]; +#endif /** * Constructs a matrix initialized to the identity matrix: diff --git a/cocos/math/MathUtil.h b/cocos/math/MathUtil.h index da5fe3c830..acf6ab0b42 100644 --- a/cocos/math/MathUtil.h +++ b/cocos/math/MathUtil.h @@ -21,6 +21,10 @@ #ifndef MATHUTIL_H_ #define MATHUTIL_H_ +#ifdef __SSE__ +#include +#endif + #include "CCMathBase.h" NS_CC_MATH_BEGIN @@ -67,7 +71,23 @@ public: static void smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime); private: - +#ifdef __SSE__ + inline static void addMatrix(const __m128 m[4], float scalar, __m128 dst[4]); + + inline static void addMatrix(const __m128 m1[4], const __m128 m2[4], __m128 dst[4]); + + inline static void subtractMatrix(const __m128 m1[4], const __m128 m2[4], __m128 dst[4]); + + inline static void multiplyMatrix(const __m128 m[4], float scalar, __m128 dst[4]); + + inline static void multiplyMatrix(const __m128 m1[4], const __m128 m2[4], __m128 dst[4]); + + inline static void negateMatrix(const __m128 m[4], __m128 dst[4]); + + inline static void transposeMatrix(const __m128 m[4], __m128 dst[4]); + + inline static void transformVec4(const __m128 m[4], const __m128& v, __m128& dst); +#endif inline static void addMatrix(const float* m, float scalar, float* dst); inline static void addMatrix(const float* m1, const float* m2, float* dst); @@ -99,6 +119,9 @@ NS_CC_MATH_END #include "MathUtilNeon.inl" #else #include "MathUtil.inl" +#if defined(__SSE__) +#include "MathUtilSSE.inl" +#endif #endif #endif diff --git a/cocos/math/MathUtilSSE.inl b/cocos/math/MathUtilSSE.inl new file mode 100644 index 0000000000..b701bb51ca --- /dev/null +++ b/cocos/math/MathUtilSSE.inl @@ -0,0 +1,152 @@ +NS_CC_MATH_BEGIN + +inline void MathUtil::addMatrix(const __m128 m[4], float scalar, __m128 dst[4]) +{ + __m128 s = _mm_set1_ps(scalar); + dst[0] = _mm_add_ps(m[0], s); + dst[1] = _mm_add_ps(m[1], s); + dst[2] = _mm_add_ps(m[2], s); + dst[3] = _mm_add_ps(m[3], s); +} + +inline void MathUtil::addMatrix(const __m128 m1[4], const __m128 m2[4], __m128 dst[4]) +{ + dst[0] = _mm_add_ps(m1[0], m2[0]); + dst[1] = _mm_add_ps(m1[1], m2[1]); + dst[2] = _mm_add_ps(m1[2], m2[2]); + dst[3] = _mm_add_ps(m1[3], m2[3]); +} + +inline void MathUtil::subtractMatrix(const __m128 m1[4], const __m128 m2[4], __m128 dst[4]) +{ + dst[0] = _mm_sub_ps(m1[0], m2[0]); + dst[1] = _mm_sub_ps(m1[1], m2[1]); + dst[2] = _mm_sub_ps(m1[2], m2[2]); + dst[3] = _mm_sub_ps(m1[3], m2[3]); +} + +inline void MathUtil::multiplyMatrix(const __m128 m[4], float scalar, __m128 dst[4]) +{ + __m128 s = _mm_set1_ps(scalar); + dst[0] = _mm_mul_ps(m[0], s); + dst[1] = _mm_mul_ps(m[1], s); + dst[2] = _mm_mul_ps(m[2], s); + dst[3] = _mm_mul_ps(m[3], s); +} + +inline void MathUtil::multiplyMatrix(const __m128 m1[4], const __m128 m2[4], __m128 dst[4]) +{ + __m128 dst0, dst1, dst2, dst3; + { + __m128 e0 = _mm_shuffle_ps(m2[0], m2[0], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(m2[0], m2[0], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(m2[0], m2[0], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(m2[0], m2[0], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 v0 = _mm_mul_ps(m1[0], e0); + __m128 v1 = _mm_mul_ps(m1[1], e1); + __m128 v2 = _mm_mul_ps(m1[2], e2); + __m128 v3 = _mm_mul_ps(m1[3], e3); + + __m128 a0 = _mm_add_ps(v0, v1); + __m128 a1 = _mm_add_ps(v2, v3); + __m128 a2 = _mm_add_ps(a0, a1); + + dst0 = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(m2[1], m2[1], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(m2[1], m2[1], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(m2[1], m2[1], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(m2[1], m2[1], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 v0 = _mm_mul_ps(m1[0], e0); + __m128 v1 = _mm_mul_ps(m1[1], e1); + __m128 v2 = _mm_mul_ps(m1[2], e2); + __m128 v3 = _mm_mul_ps(m1[3], e3); + + __m128 a0 = _mm_add_ps(v0, v1); + __m128 a1 = _mm_add_ps(v2, v3); + __m128 a2 = _mm_add_ps(a0, a1); + + dst1 = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(m2[2], m2[2], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(m2[2], m2[2], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(m2[2], m2[2], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(m2[2], m2[2], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 v0 = _mm_mul_ps(m1[0], e0); + __m128 v1 = _mm_mul_ps(m1[1], e1); + __m128 v2 = _mm_mul_ps(m1[2], e2); + __m128 v3 = _mm_mul_ps(m1[3], e3); + + __m128 a0 = _mm_add_ps(v0, v1); + __m128 a1 = _mm_add_ps(v2, v3); + __m128 a2 = _mm_add_ps(a0, a1); + + dst2 = a2; + } + + { + __m128 e0 = _mm_shuffle_ps(m2[3], m2[3], _MM_SHUFFLE(0, 0, 0, 0)); + __m128 e1 = _mm_shuffle_ps(m2[3], m2[3], _MM_SHUFFLE(1, 1, 1, 1)); + __m128 e2 = _mm_shuffle_ps(m2[3], m2[3], _MM_SHUFFLE(2, 2, 2, 2)); + __m128 e3 = _mm_shuffle_ps(m2[3], m2[3], _MM_SHUFFLE(3, 3, 3, 3)); + + __m128 v0 = _mm_mul_ps(m1[0], e0); + __m128 v1 = _mm_mul_ps(m1[1], e1); + __m128 v2 = _mm_mul_ps(m1[2], e2); + __m128 v3 = _mm_mul_ps(m1[3], e3); + + __m128 a0 = _mm_add_ps(v0, v1); + __m128 a1 = _mm_add_ps(v2, v3); + __m128 a2 = _mm_add_ps(a0, a1); + + dst3 = a2; + } + dst[0] = dst0; + dst[1] = dst1; + dst[2] = dst2; + dst[3] = dst3; +} + +inline void MathUtil::negateMatrix(const __m128 m[4], __m128 dst[4]) +{ + __m128 z = _mm_setzero_ps(); + dst[0] = _mm_sub_ps(z, m[0]); + dst[1] = _mm_sub_ps(z, m[1]); + dst[2] = _mm_sub_ps(z, m[2]); + dst[3] = _mm_sub_ps(z, m[3]); +} + +inline void MathUtil::transposeMatrix(const __m128 m[4], __m128 dst[4]) +{ + __m128 tmp0 = _mm_shuffle_ps(m[0], m[1], 0x44); + __m128 tmp2 = _mm_shuffle_ps(m[0], m[1], 0xEE); + __m128 tmp1 = _mm_shuffle_ps(m[2], m[3], 0x44); + __m128 tmp3 = _mm_shuffle_ps(m[2], m[3], 0xEE); + + dst[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88); + dst[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD); + dst[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88); + dst[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD); +} + +inline void MathUtil::transformVec4(const __m128 m[4], const __m128& v, __m128& dst) +{ + __m128 col1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); + __m128 col2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); + __m128 col3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + __m128 col4 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)); + + dst = _mm_add_ps( + _mm_add_ps(_mm_mul_ps(m[0], col1), _mm_mul_ps(m[1], col2)), + _mm_add_ps(_mm_mul_ps(m[2], col3), _mm_mul_ps(m[3], col4)) + ); +} + +NS_CC_MATH_END diff --git a/cocos/math/Vec4.h b/cocos/math/Vec4.h index d6399fb339..712f60fd4f 100644 --- a/cocos/math/Vec4.h +++ b/cocos/math/Vec4.h @@ -21,6 +21,10 @@ #ifndef MATH_VEC4_H #define MATH_VEC4_H +#ifdef __SSE__ +#include +#endif + #include "math/CCMathBase.h" NS_CC_MATH_BEGIN @@ -33,7 +37,17 @@ class Mat4; class CC_DLL Vec4 { public: - +#ifdef __SSE__ + union { + struct { + float x; + float y; + float z; + float w; + }; + __m128 v; + }; +#else /** * The x-coordinate. */ @@ -53,7 +67,7 @@ public: * The w-coordinate. */ float w; - +#endif /** * Constructs a new vector initialized to all zeros. */ diff --git a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.cpp b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.cpp index 6958a28aa3..1f1c29dacd 100644 --- a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.cpp +++ b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.cpp @@ -8511,6 +8511,50 @@ int lua_cocos2dx_extension_ScrollView_setMaxScale(lua_State* tolua_S) return 0; } +int lua_cocos2dx_extension_ScrollView_hasVisibleParents(lua_State* tolua_S) +{ + int argc = 0; + cocos2d::extension::ScrollView* cobj = nullptr; + bool ok = true; + +#if COCOS2D_DEBUG >= 1 + tolua_Error tolua_err; +#endif + + +#if COCOS2D_DEBUG >= 1 + if (!tolua_isusertype(tolua_S,1,"cc.ScrollView",0,&tolua_err)) goto tolua_lerror; +#endif + + cobj = (cocos2d::extension::ScrollView*)tolua_tousertype(tolua_S,1,0); + +#if COCOS2D_DEBUG >= 1 + if (!cobj) + { + tolua_error(tolua_S,"invalid 'cobj' in function 'lua_cocos2dx_extension_ScrollView_hasVisibleParents'", nullptr); + return 0; + } +#endif + + argc = lua_gettop(tolua_S)-1; + if (argc == 0) + { + if(!ok) + return 0; + bool ret = cobj->hasVisibleParents(); + tolua_pushboolean(tolua_S,(bool)ret); + return 1; + } + CCLOG("%s has wrong number of arguments: %d, was expecting %d \n", "cc.ScrollView:hasVisibleParents",argc, 0); + return 0; + +#if COCOS2D_DEBUG >= 1 + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_extension_ScrollView_hasVisibleParents'.",&tolua_err); +#endif + + return 0; +} int lua_cocos2dx_extension_ScrollView_getDirection(lua_State* tolua_S) { int argc = 0; @@ -9937,6 +9981,7 @@ int lua_register_cocos2dx_extension_ScrollView(lua_State* tolua_S) tolua_function(tolua_S,"setZoomScaleInDuration",lua_cocos2dx_extension_ScrollView_setZoomScaleInDuration); tolua_function(tolua_S,"updateTweenAction",lua_cocos2dx_extension_ScrollView_updateTweenAction); tolua_function(tolua_S,"setMaxScale",lua_cocos2dx_extension_ScrollView_setMaxScale); + tolua_function(tolua_S,"hasVisibleParents",lua_cocos2dx_extension_ScrollView_hasVisibleParents); tolua_function(tolua_S,"getDirection",lua_cocos2dx_extension_ScrollView_getDirection); tolua_function(tolua_S,"getContainer",lua_cocos2dx_extension_ScrollView_getContainer); tolua_function(tolua_S,"setMinScale",lua_cocos2dx_extension_ScrollView_setMinScale); diff --git a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.hpp b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.hpp index cbd41e6a6b..483cbe013a 100644 --- a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.hpp +++ b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_extension_auto.hpp @@ -262,6 +262,7 @@ int register_all_cocos2dx_extension(lua_State* tolua_S); + #endif // __cocos2dx_extension_h__ diff --git a/cocos/scripting/lua-bindings/proj.ios_mac/cocos2d_lua_bindings.xcodeproj/project.pbxproj b/cocos/scripting/lua-bindings/proj.ios_mac/cocos2d_lua_bindings.xcodeproj/project.pbxproj index 260b98b268..05f642556d 100644 --- a/cocos/scripting/lua-bindings/proj.ios_mac/cocos2d_lua_bindings.xcodeproj/project.pbxproj +++ b/cocos/scripting/lua-bindings/proj.ios_mac/cocos2d_lua_bindings.xcodeproj/project.pbxproj @@ -871,7 +871,7 @@ 1551A336158F2AB200E66CFE /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0600; ORGANIZATIONNAME = ""; }; buildConfigurationList = 1551A339158F2AB200E66CFE /* Build configuration list for PBXProject "cocos2d_lua_bindings" */; @@ -1107,7 +1107,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = ""; @@ -1129,7 +1129,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_PREFIX = ""; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/cocos/ui/UIScale9Sprite.cpp b/cocos/ui/UIScale9Sprite.cpp index 13f6f2f92d..f5e61c659e 100644 --- a/cocos/ui/UIScale9Sprite.cpp +++ b/cocos/ui/UIScale9Sprite.cpp @@ -814,8 +814,9 @@ y+=ytranslate; \ for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) (*it)->visit(renderer, _modelViewTransform, flags); - // reset for next frame - _orderOfArrival = 0; + // FIX ME: Why need to set _orderOfArrival to 0?? + // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 + // setOrderOfArrival(0); director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); diff --git a/extensions/GUI/CCScrollView/CCScrollView.cpp b/extensions/GUI/CCScrollView/CCScrollView.cpp index e97d2672be..68181bd899 100644 --- a/extensions/GUI/CCScrollView/CCScrollView.cpp +++ b/extensions/GUI/CCScrollView/CCScrollView.cpp @@ -343,6 +343,19 @@ void ScrollView::setContainer(Node * pContainer) this->setViewSize(this->_viewSize); } +bool ScrollView::hasVisibleParents() const +{ + auto parent = this->getParent(); + for( auto c = parent; c != nullptr; c = c->getParent() ) + { + if( !c->isVisible() ) + { + return false; + } + } + return true; +} + void ScrollView::relocateContainer(bool animated) { Vec2 oldPoint, min, max; @@ -625,7 +638,7 @@ void ScrollView::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t bool ScrollView::onTouchBegan(Touch* touch, Event* event) { - if (!this->isVisible()) + if (!this->isVisible() || !this->hasVisibleParents()) { return false; } diff --git a/extensions/GUI/CCScrollView/CCScrollView.h b/extensions/GUI/CCScrollView/CCScrollView.h index 72695df5c7..36f94d39f8 100644 --- a/extensions/GUI/CCScrollView/CCScrollView.h +++ b/extensions/GUI/CCScrollView/CCScrollView.h @@ -256,6 +256,8 @@ public: * CCActionTweenDelegate */ void updateTweenAction(float value, const std::string& key); + + bool hasVisibleParents() const; protected: /** * Relocates the container at the proper offset, in bounds of max/min offsets. diff --git a/templates/cocos2dx_files.json b/templates/cocos2dx_files.json index 160b526f0f..1aa5d8d70e 100644 --- a/templates/cocos2dx_files.json +++ b/templates/cocos2dx_files.json @@ -664,6 +664,7 @@ "cocos/math/MathUtil.h", "cocos/math/MathUtil.inl", "cocos/math/MathUtilNeon.inl", + "cocos/math/MathUtilSSE.inl", "cocos/math/Quaternion.cpp", "cocos/math/Quaternion.h", "cocos/math/Quaternion.inl", diff --git a/tests/cpp-tests/Android.mk b/tests/cpp-tests/Android.mk index 44c9521d69..52eb45fcf3 100644 --- a/tests/cpp-tests/Android.mk +++ b/tests/cpp-tests/Android.mk @@ -39,6 +39,7 @@ Classes/ChipmunkTest/ChipmunkTest.cpp \ Classes/ClickAndMoveTest/ClickAndMoveTest.cpp \ Classes/ClippingNodeTest/ClippingNodeTest.cpp \ Classes/CocosDenshionTest/CocosDenshionTest.cpp \ +Classes/NewAudioEngineTest/NewAudioEngineTest.cpp \ Classes/ConfigurationTest/ConfigurationTest.cpp \ Classes/ConsoleTest/ConsoleTest.cpp \ Classes/CurlTest/CurlTest.cpp \ diff --git a/tests/cpp-tests/Classes/NewAudioEngineTest/NewAudioEngineTest.cpp b/tests/cpp-tests/Classes/NewAudioEngineTest/NewAudioEngineTest.cpp new file mode 100644 index 0000000000..ae82703326 --- /dev/null +++ b/tests/cpp-tests/Classes/NewAudioEngineTest/NewAudioEngineTest.cpp @@ -0,0 +1,715 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS +#include "NewAudioEngineTest.h" +#include "ui/CocosGUI.h" + +using namespace cocos2d::ui; + +namespace { + +std::function createFunctions[] = +{ + CL(AudioControlTest), + CL(PlaySimultaneouslyTest), + CL(AudioProfileTest), + CL(InvalidAudioFileTest), + CL(LargeAudioFileTest) +}; + +unsigned int TEST_CASE_COUNT = sizeof(createFunctions) / sizeof(createFunctions[0]); + +int s_sceneIdx = -1; +Layer* createTest(int index) +{ + auto layer = (createFunctions[index])();; + return layer; +} + +Layer* nextAction() +{ + s_sceneIdx++; + s_sceneIdx = s_sceneIdx % TEST_CASE_COUNT; + + return createTest(s_sceneIdx); +} + +Layer* backAction() +{ + s_sceneIdx--; + if( s_sceneIdx < 0 ) + s_sceneIdx = TEST_CASE_COUNT -1; + + return createTest(s_sceneIdx); +} + +Layer* restartAction() +{ + return createTest(s_sceneIdx); +} + + class TextButton : public cocos2d::Label + { + public: + + static TextButton *create(const std::string& text, const std::function &onTriggered) + { + auto ret = new (std::nothrow) TextButton(); + + TTFConfig ttfconfig("fonts/arial.ttf",25); + if (ret && ret->setTTFConfig(ttfconfig)) { + ret->setString(text); + ret->_onTriggered = onTriggered; + + ret->autorelease(); + + return ret; + } + + delete ret; + return nullptr; + } + + void setEnabled(bool enabled) + { + _enabled = enabled; + if(_enabled){ + this->setColor(Color3B::WHITE); + } + else { + this->setColor(Color3B::GRAY); + } + } + + private: + TextButton() + : _enabled(true) + , _onTriggered(nullptr) + { + auto listener = EventListenerTouchOneByOne::create(); + listener->setSwallowTouches(true); + + listener->onTouchBegan = CC_CALLBACK_2(TextButton::onTouchBegan, this); + listener->onTouchEnded = CC_CALLBACK_2(TextButton::onTouchEnded, this); + listener->onTouchCancelled = CC_CALLBACK_2(TextButton::onTouchCancelled, this); + + _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); + + } + + bool touchHits(Touch *touch) + { + auto hitPos = this->convertToNodeSpace(touch->getLocation()); + if (hitPos.x >= 0 && hitPos.y >= 0 && hitPos.x <= _contentSize.width && hitPos.y <= _contentSize.height) { + return true; + } + return false; + } + + bool onTouchBegan(Touch *touch, Event *event) + { + auto hits = touchHits(touch); + if (hits){ + scaleButtonTo(0.95f); + } + return hits; + } + + void onTouchEnded(Touch *touch, Event *event) + { + if(_enabled) { + auto hits = touchHits(touch); + if (hits && _onTriggered){ + _onTriggered(this); + } + } + + scaleButtonTo(1); + } + + void onTouchCancelled(Touch *touch, Event *event) + { + scaleButtonTo(1); + } + + void scaleButtonTo(float scale) + { + auto action = ScaleTo::create(0.05f, scale); + action->setTag(10000); + stopActionByTag(10000); + runAction(action); + } + + std::function _onTriggered; + + bool _enabled; + }; + + class SliderEx : public ui::Slider + { + public: + enum class TouchEvent + { + DOWN, + MOVE, + UP, + CANCEL + }; + typedef std::function ccSliderExCallback; + + static SliderEx* create(){ + auto ret = new (std::nothrow) SliderEx(); + if (ret && ret->init()) + { + ret->_callback = nullptr; + ret->loadBarTexture("cocosui/sliderTrack.png"); + ret->loadSlidBallTextures("cocosui/sliderThumb.png", "cocosui/sliderThumb.png", ""); + ret->loadProgressBarTexture("cocosui/sliderProgress.png"); + + ret->autorelease(); + + return ret; + } + CC_SAFE_DELETE(ret); + return ret; + } + + void setCallBack(const ccSliderExCallback& callback){ + _callback = callback; + } + + void setRatio(float ratio) { + if (ratio > 1.0f){ + ratio = 1.0f; + } + else if (ratio < 0.0f){ + ratio = 0.0f; + } + + _ratio = ratio; + _percent = 100 * _ratio; + + float dis = _barLength * _ratio; + _slidBallRenderer->setPosition(Vec2(dis, _contentSize.height / 2.0f)); + if (_scale9Enabled){ + _progressBarRenderer->setPreferredSize(Size(dis,_progressBarTextureSize.height)); + } + else + { + auto spriteRenderer = _progressBarRenderer->getSprite(); + + if (nullptr != spriteRenderer) { + Rect rect = spriteRenderer->getTextureRect(); + rect.size.width = _progressBarTextureSize.width * _ratio; + spriteRenderer->setTextureRect(rect, spriteRenderer->isTextureRectRotated(), rect.size); + } + } + } + + virtual bool onTouchBegan(Touch *touch, Event *unusedEvent) override{ + auto ret = Slider::onTouchBegan(touch, unusedEvent); + if(ret && _callback){ + _touchEvent = TouchEvent::DOWN; + Vec2 nsp = convertToNodeSpace(_touchBeganPosition); + _ratio = nsp.x / _barLength; + if(_ratio < 0.0f) + _ratio = 0.0f; + else if(_ratio > 1.0f) + _ratio = 1.0f; + _callback(this,_ratio,_touchEvent); + } + return ret; + } + + virtual void onTouchMoved(Touch *touch, Event *unusedEvent) override{ + _touchEvent = TouchEvent::MOVE; + Slider::onTouchMoved(touch, unusedEvent); + Vec2 nsp = convertToNodeSpace(_touchMovePosition); + _ratio = nsp.x / _barLength; + if(_ratio < 0.0f) + _ratio = 0.0f; + else if(_ratio > 1.0f) + _ratio = 1.0f; + if(_callback){ + _callback(this,_ratio,_touchEvent); + } + } + + virtual void onTouchEnded(Touch *touch, Event *unusedEvent) override{ + _touchEvent = TouchEvent::UP; + Slider::onTouchEnded(touch, unusedEvent); + Vec2 nsp = convertToNodeSpace(_touchEndPosition); + _ratio = nsp.x / _barLength; + if(_ratio < 0.0f) + _ratio = 0.0f; + else if(_ratio > 1.0f) + _ratio = 1.0f; + if(_callback){ + _callback(this,_ratio,_touchEvent); + } + } + + virtual void onTouchCancelled(Touch *touch, Event *unusedEvent) override{ + _touchEvent = TouchEvent::CANCEL; + Slider::onTouchCancelled(touch, unusedEvent); + + if(_callback){ + _callback(this,_ratio,_touchEvent); + } + } + + private: + TouchEvent _touchEvent; + float _ratio; + ccSliderExCallback _callback; + }; +} + +void AudioEngineTestScene::runThisTest() +{ + CCASSERT(AudioEngine::lazyInit(),"Fail to initialize AudioEngine!"); + + s_sceneIdx = -1; + auto layer = nextAction(); + addChild(layer); + + Director::getInstance()->replaceScene(this); +} + +void AudioEngineTestDemo::backCallback(Ref* sender) +{ + AudioEngine::stopAll(); + auto scene = new AudioEngineTestScene(); + auto layer = backAction(); + + scene->addChild(layer); + Director::getInstance()->replaceScene(scene); + scene->release(); +} + +void AudioEngineTestDemo::nextCallback(Ref* sender) +{ + AudioEngine::stopAll(); + auto scene = new AudioEngineTestScene(); + auto layer = nextAction(); + + scene->addChild(layer); + Director::getInstance()->replaceScene(scene); + scene->release(); +} + +void AudioEngineTestDemo::restartCallback(Ref* sender) +{ + AudioEngine::stopAll(); + auto scene = new AudioEngineTestScene(); + auto layer = restartAction(); + + scene->addChild(layer); + Director::getInstance()->replaceScene(scene); + scene->release(); +} + +std::string AudioEngineTestDemo::title() const +{ + return "New Audio Engine Test"; +} + +// AudioControlTest +bool AudioControlTest::init() +{ + auto ret = AudioEngineTestDemo::init(); + _audioID = AudioEngine::INVAILD_AUDIO_ID; + _loopEnabled = false; + _volume = 1.0f; + _duration = AudioEngine::TIME_UNKNOWN; + _timeRatio = 0.0f; + _updateTimeSlider = true; + + std::string fontFilePath = "fonts/arial.ttf"; + + auto& layerSize = this->getContentSize(); + + auto playItem = TextButton::create("play", [&](TextButton* button){ + if (_audioID == AudioEngine::INVAILD_AUDIO_ID) { + _audioID = AudioEngine::play2d("background.mp3", _loopEnabled, _volume); + + if(_audioID != AudioEngine::INVAILD_AUDIO_ID) { + button->setEnabled(false); + AudioEngine::setFinishCallback(_audioID, [&](int id, const std::string& filePath){ + _audioID = AudioEngine::INVAILD_AUDIO_ID; + ((TextButton*)_playItem)->setEnabled(true); + + _timeRatio = 0.0f; + ((SliderEx*)_timeSlider)->setRatio(_timeRatio); + }); + } + } + }); + _playItem = playItem; + playItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.7f); + addChild(playItem); + + auto stopItem = TextButton::create("stop", [&](TextButton* button){ + if (_audioID != AudioEngine::INVAILD_AUDIO_ID ) { + AudioEngine::stop(_audioID); + + _audioID = AudioEngine::INVAILD_AUDIO_ID; + ((TextButton*)_playItem)->setEnabled(true); + } + }); + stopItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.7f); + addChild(stopItem); + + auto pauseItem = TextButton::create("pause", [&](TextButton* button){ + if (_audioID != AudioEngine::INVAILD_AUDIO_ID ) { + AudioEngine::pause(_audioID); + } + }); + pauseItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.6f); + addChild(pauseItem); + + auto resumeItem = TextButton::create("resume", [&](TextButton* button){ + if (_audioID != AudioEngine::INVAILD_AUDIO_ID ) { + AudioEngine::resume(_audioID); + } + }); + resumeItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.6f); + addChild(resumeItem); + + auto loopItem = TextButton::create("enable-loop", [&](TextButton* button){ + _loopEnabled = !_loopEnabled; + + if (_audioID != AudioEngine::INVAILD_AUDIO_ID ) { + AudioEngine::setLoop(_audioID, _loopEnabled); + } + if(_loopEnabled){ + button->setString("disable-loop"); + } + else { + button->setString("enable-loop"); + } + }); + loopItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.5f); + addChild(loopItem); + + auto uncacheItem = TextButton::create("uncache", [&](TextButton* button){ + AudioEngine::uncache("background.mp3"); + + _audioID = AudioEngine::INVAILD_AUDIO_ID; + ((TextButton*)_playItem)->setEnabled(true); + }); + uncacheItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.5f); + addChild(uncacheItem); + + auto volumeSlider = SliderEx::create(); + volumeSlider->setPercent(100); + volumeSlider->setCallBack([&](SliderEx* sender,float ratio,SliderEx::TouchEvent event){ + _volume = ratio; + log("_volume:%f,event:%d",_volume,event); + if (_audioID != AudioEngine::INVAILD_AUDIO_ID ) { + AudioEngine::setVolume(_audioID, _volume); + } + }); + volumeSlider->setPosition(Vec2(layerSize.width * 0.5f,layerSize.height * 0.35f)); + addChild(volumeSlider); + + auto timeSlider = SliderEx::create(); + timeSlider->setCallBack([&](SliderEx* sender,float ratio,SliderEx::TouchEvent event){ + switch(event){ + case SliderEx::TouchEvent::MOVE: + case SliderEx::TouchEvent::DOWN: + _updateTimeSlider = false; + break; + case SliderEx::TouchEvent::UP: + if (_audioID != AudioEngine::INVAILD_AUDIO_ID && _duration != AudioEngine::TIME_UNKNOWN) { + AudioEngine::setCurrentTime(_audioID,_duration * ratio); + } + case SliderEx::TouchEvent::CANCEL: + _updateTimeSlider = true; + break; + } + }); + timeSlider->setPosition(Vec2(layerSize.width * 0.5f,layerSize.height * 0.25f)); + addChild(timeSlider); + _timeSlider = timeSlider; + + auto& volumeSliderPos = volumeSlider->getPosition(); + auto& sliderSize = volumeSlider->getContentSize(); + auto volumeLabel = Label::createWithTTF("volume: ", fontFilePath, 20); + volumeLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_RIGHT); + volumeLabel->setPosition(volumeSliderPos.x - sliderSize.width / 2, volumeSliderPos.y); + addChild(volumeLabel); + + auto& timeSliderPos = timeSlider->getPosition(); + auto timeLabel = Label::createWithTTF("time: ", fontFilePath, 20); + timeLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_RIGHT); + timeLabel->setPosition(timeSliderPos.x - sliderSize.width / 2, timeSliderPos.y); + addChild(timeLabel); + + this->schedule(schedule_selector(AudioControlTest::update), 0.1f); + + return ret; +} + +void AudioControlTest::update(float dt) +{ + if (_audioID != AudioEngine::INVAILD_AUDIO_ID ) { + if(_duration == AudioEngine::TIME_UNKNOWN){ + _duration = AudioEngine::getDuration(_audioID); + } + if(_duration != AudioEngine::TIME_UNKNOWN){ + auto time = AudioEngine::getCurrentTime(_audioID); + _timeRatio = time / _duration; + if(_updateTimeSlider){ + ((SliderEx*)_timeSlider)->setRatio(_timeRatio); + } + } + } +} + +AudioControlTest::~AudioControlTest() +{ +} + +std::string AudioControlTest::title() const +{ + return "audio control test"; +} + +// PlaySimultaneouslyTest +bool PlaySimultaneouslyTest::init() +{ + auto ret = AudioEngineTestDemo::init(); + + char text[36]; + int tmp = 81; + for(int index = 0; index < TEST_COUNT; ++index){ + sprintf(text,"audio/SoundEffectsFX009/FX0%d.mp3",tmp + index); + _files[index] = text; + } + _playingcount = 0; + + auto playItem = TextButton::create("play-simultaneously", [&](TextButton* button){ + int audioId; + _playingcount = 0; + button->setEnabled(false); + auto startTime = utils::gettime(); + for(int index = 0; index < TEST_COUNT; ++index){ + audioId = AudioEngine::play2d(_files[index]); + if(audioId != AudioEngine::INVAILD_AUDIO_ID){ + _playingcount += 1; + + AudioEngine::setFinishCallback(audioId, [&](int id, const std::string& filePath){ + _playingcount -= 1; + if(_playingcount <= 0){ + ((TextButton*)_playItem)->setEnabled(true); + } + }); + } + else { + log("%s,%d,Fail to play file:%s",__FILE__,__LINE__ ,_files[index].c_str()); + } + } + log("diff time:%lf",utils::gettime() - startTime); + }); + playItem->setNormalizedPosition(Vec2(0.5f,0.5f)); + this->addChild(playItem); + _playItem = playItem; + + return ret; +} + +PlaySimultaneouslyTest::~PlaySimultaneouslyTest() +{ +} + +std::string PlaySimultaneouslyTest::title() const +{ + return "Simultaneously play multiple audio"; +} + +// AudioProfileTest +bool AudioProfileTest::init() +{ + auto ret = AudioEngineTestDemo::init(); + + char text[30]; + _files[0] = "background.mp3"; +#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS + _files[1] = "background.caf"; +#else + _files[1] = "background.ogg"; +#endif + _files[2] = "background.wav"; + _files[3] = "pew-pew-lei.wav"; + + std::string fontFilePath = "fonts/arial.ttf"; + _minDelay = 1.0f; + _time = 0.0f; + + _audioProfile.name = "AudioProfileTest"; + _audioProfile.maxInstances = 3; + _audioProfile.minDelay = 1.0; + + Vec2 pos(0.5f,0.7f); + + for(int index = 0; index < FILE_COUNT; ++index){ + sprintf(text,"play %s",_files[index].c_str()); + + auto playItem = TextButton::create(text, [&](TextButton* button){ + int index = button->getTag(); + auto id = AudioEngine::play2d(_files[index], false, 1.0f, &_audioProfile); + if(id != AudioEngine::INVAILD_AUDIO_ID){ + _time = _minDelay; + _audioCount += 1; + char show[30]; + sprintf(show,"audio count:%d",_audioCount); + _showLabel->setString(show); + + AudioEngine::setFinishCallback(id, [&](int id, const std::string& filePath){ + _audioCount -= 1; + char show[30]; + sprintf(show,"audio count:%d",_audioCount); + _showLabel->setString(show); + }); + } + + }); + playItem->setTag(index); + playItem->setNormalizedPosition(pos); + this->addChild(playItem); + pos.y -= 0.1f; + + } + + Vec2 origin = Director::getInstance()->getVisibleOrigin(); + Size size = Director::getInstance()->getVisibleSize(); + + auto profileInfoLabel = Label::createWithTTF("AudioProfile Info:\n max instance:3 \n minimum delay:1.0", fontFilePath, 12); + profileInfoLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + profileInfoLabel->setPosition(Vec2(origin.x, origin.y + size.height * 0.65f)); + addChild(profileInfoLabel); + + _audioCount = 0; + _showLabel = Label::createWithTTF("audio count:0", fontFilePath, 12); + _showLabel->setAnchorPoint(Vec2::ANCHOR_MIDDLE_LEFT); + _showLabel->setPosition(Vec2(origin.x, origin.y + size.height * 0.5f)); + addChild(_showLabel); + + auto timeSlider = SliderEx::create(); + timeSlider->setEnabled(false); + timeSlider->setNormalizedPosition(pos); + addChild(timeSlider); + _timeSlider = timeSlider; + + this->schedule(schedule_selector(AudioControlTest::update), 0.05f); + + return ret; +} + +void AudioProfileTest::update(float dt) +{ + if(_time > 0.0f) + { + _time -= dt; + ((SliderEx*)_timeSlider)->setRatio(_time / _minDelay); + } +} + +AudioProfileTest::~AudioProfileTest() +{ +} + +std::string AudioProfileTest::title() const +{ + return "AudioProfileTest"; +} + +std::string AudioProfileTest::subtitle() const +{ + return "See the console."; +} + +// InvalidAudioFileTest +bool InvalidAudioFileTest::init() +{ + auto ret = AudioEngineTestDemo::init(); + + auto playItem = TextButton::create("play unsupported media type", [&](TextButton* button){ +#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS + AudioEngine::play2d("background.ogg"); +#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID + AudioEngine::play2d("background.caf"); +#endif + }); + playItem->setNormalizedPosition(Vec2(0.5f, 0.6f)); + this->addChild(playItem); + + auto playItem2 = TextButton::create("play not-existent file", [&](TextButton* button){ + AudioEngine::play2d("not-existent file.mp3"); + }); + playItem2->setNormalizedPosition(Vec2(0.5f, 0.4f)); + this->addChild(playItem2); + + return ret; +} + +InvalidAudioFileTest::~InvalidAudioFileTest() +{ +} + +std::string InvalidAudioFileTest::title() const +{ + return "Test invalid audio file"; +} + +std::string InvalidAudioFileTest::subtitle() const +{ + return "Not crash,please see the console."; +} + +// LargeAudioFileTest +bool LargeAudioFileTest::init() +{ + auto ret = AudioEngineTestDemo::init(); + + auto playItem = TextButton::create("play large audio file", [&](TextButton* button){ + AudioEngine::play2d("audio/Chee Lai(Arise).mp3"); + }); + playItem->setNormalizedPosition(Vec2::ANCHOR_MIDDLE); + this->addChild(playItem); + + return ret; +} + +LargeAudioFileTest::~LargeAudioFileTest() +{ +} + +std::string LargeAudioFileTest::title() const +{ + return "Test large audio file"; +} + +#endif diff --git a/tests/cpp-tests/Classes/NewAudioEngineTest/NewAudioEngineTest.h b/tests/cpp-tests/Classes/NewAudioEngineTest/NewAudioEngineTest.h new file mode 100644 index 0000000000..e4c2133b6a --- /dev/null +++ b/tests/cpp-tests/Classes/NewAudioEngineTest/NewAudioEngineTest.h @@ -0,0 +1,153 @@ +/**************************************************************************** + Copyright (c) 2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS +#ifndef __NEWAUDIOENGINE_TEST_H_ +#define __NEWAUDIOENGINE_TEST_H_ + +#include "cocos2d.h" +#include "../testBasic.h" +#include "../BaseTest.h" + +#include "audio/include/AudioEngine.h" + +using namespace cocos2d; + +class AudioEngineTestScene : public TestScene +{ +public: + virtual void runThisTest(); +}; + +class AudioEngineTestDemo : public BaseTest +{ +public: + virtual std::string title() const override; + void backCallback(Ref* sender); + void nextCallback(Ref* sender); + void restartCallback(Ref* sender); + +}; + +class AudioControlTest : public AudioEngineTestDemo +{ +public: + CREATE_FUNC(AudioControlTest); + + virtual ~AudioControlTest(); + + virtual bool init(); + + virtual void update(float dt); + + virtual std::string title() const override; + +private: + int _audioID; + bool _loopEnabled; + float _volume; + float _duration; + float _timeRatio; + + void* _playItem; + void* _timeSlider; + bool _updateTimeSlider; +}; + +class PlaySimultaneouslyTest : public AudioEngineTestDemo +{ +public: + CREATE_FUNC(PlaySimultaneouslyTest); + + virtual ~PlaySimultaneouslyTest(); + + virtual bool init(); + + virtual std::string title() const override; +private: + static const int TEST_COUNT = 10; + std::string _files[TEST_COUNT]; + + void* _playItem; + int _playingcount; +}; + +class AudioProfileTest : public AudioEngineTestDemo +{ +public: + CREATE_FUNC(AudioProfileTest); + + virtual ~AudioProfileTest(); + + virtual bool init(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + + virtual void update(float dt); + +private: + static const int FILE_COUNT = 4; + std::string _files[FILE_COUNT]; + AudioProfile _audioProfile; + + int _audioCount; + Label* _showLabel; + float _time; + float _minDelay; + void* _timeSlider; +}; + +class InvalidAudioFileTest : public AudioEngineTestDemo +{ +public: + CREATE_FUNC(InvalidAudioFileTest); + + virtual ~InvalidAudioFileTest(); + + virtual bool init(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + +private: + +}; + +class LargeAudioFileTest : public AudioEngineTestDemo +{ +public: + CREATE_FUNC(LargeAudioFileTest); + + virtual ~LargeAudioFileTest(); + + virtual bool init(); + + virtual std::string title() const override; + +private: + +}; + +#endif /* defined(__NEWAUDIOENGINE_TEST_H_) */ +#endif diff --git a/tests/cpp-tests/Classes/controller.cpp b/tests/cpp-tests/Classes/controller.cpp index c10ad6ceb4..b5864d45ac 100644 --- a/tests/cpp-tests/Classes/controller.cpp +++ b/tests/cpp-tests/Classes/controller.cpp @@ -39,6 +39,9 @@ Controller g_aTestNames[] = { { "Actions - Ease", [](){return new ActionsEaseTestScene();} }, { "Actions - Progress", [](){return new ProgressActionsTestScene(); } }, { "Audio - CocosDenshion", []() { return new CocosDenshionTestScene(); } }, +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS) + { "Audio - NewAudioEngine", []() { return new AudioEngineTestScene(); } }, +#endif { "Box2d - Basic", []() { return new Box2DTestScene(); } }, { "Box2d - TestBed", []() { return new Box2dTestBedScene(); } }, { "Bugs", []() { return new BugsTestScene(); } }, diff --git a/tests/cpp-tests/Classes/tests.h b/tests/cpp-tests/Classes/tests.h index 4f59b55ad9..0fd5748a1e 100644 --- a/tests/cpp-tests/Classes/tests.h +++ b/tests/cpp-tests/Classes/tests.h @@ -37,6 +37,9 @@ #include "PerformanceTest/PerformanceTest.h" #include "ZwoptexTest/ZwoptexTest.h" #include "CocosDenshionTest/CocosDenshionTest.h" +#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS) +#include "NewAudioEngineTest/NewAudioEngineTest.h" +#endif #if (CC_TARGET_PLATFORM != CC_PLATFORM_EMSCRIPEN) #if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) // bada don't support libcurl diff --git a/tools/bindings-generator b/tools/bindings-generator index c1db553615..a8496d540c 160000 --- a/tools/bindings-generator +++ b/tools/bindings-generator @@ -1 +1 @@ -Subproject commit c1db553615789a1545d495d0d0fd6f620547f99d +Subproject commit a8496d540c174236bec0d5a33457340571699f19 diff --git a/tools/tolua/cocos2dx.ini b/tools/tolua/cocos2dx.ini index 958d4b72bd..dec87dfd0a 100644 --- a/tools/tolua/cocos2dx.ini +++ b/tools/tolua/cocos2dx.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android cocos_flags = -DANDROID diff --git a/tools/tolua/cocos2dx_3d.ini b/tools/tolua/cocos2dx_3d.ini index 9e0f2508e0..f12bd68618 100644 --- a/tools/tolua/cocos2dx_3d.ini +++ b/tools/tolua/cocos2dx_3d.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android cocos_flags = -DANDROID diff --git a/tools/tolua/cocos2dx_cocosbuilder.ini b/tools/tolua/cocos2dx_cocosbuilder.ini index 40a7de384b..410fdeb5a5 100644 --- a/tools/tolua/cocos2dx_cocosbuilder.ini +++ b/tools/tolua/cocos2dx_cocosbuilder.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_cocosdenshion.ini b/tools/tolua/cocos2dx_cocosdenshion.ini index b032989626..6e337f3b84 100644 --- a/tools/tolua/cocos2dx_cocosdenshion.ini +++ b/tools/tolua/cocos2dx_cocosdenshion.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_controller.ini b/tools/tolua/cocos2dx_controller.ini index d80733b677..aed359d313 100644 --- a/tools/tolua/cocos2dx_controller.ini +++ b/tools/tolua/cocos2dx_controller.ini @@ -13,7 +13,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/base -I%(cocosdir)s/cocos/platform/android cocos_flags = -DANDROID diff --git a/tools/tolua/cocos2dx_experimental.ini b/tools/tolua/cocos2dx_experimental.ini index 97d890abf1..3ab59b7e59 100644 --- a/tools/tolua/cocos2dx_experimental.ini +++ b/tools/tolua/cocos2dx_experimental.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_experimental_video.ini b/tools/tolua/cocos2dx_experimental_video.ini index e0c343b56e..3f92bf13d7 100644 --- a/tools/tolua/cocos2dx_experimental_video.ini +++ b/tools/tolua/cocos2dx_experimental_video.ini @@ -13,7 +13,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_extension.ini b/tools/tolua/cocos2dx_extension.ini index 3b474c792f..162ebddd02 100644 --- a/tools/tolua/cocos2dx_extension.ini +++ b/tools/tolua/cocos2dx_extension.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_physics.ini b/tools/tolua/cocos2dx_physics.ini index dca3e11f6f..c5042f1dde 100644 --- a/tools/tolua/cocos2dx_physics.ini +++ b/tools/tolua/cocos2dx_physics.ini @@ -13,7 +13,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_spine.ini b/tools/tolua/cocos2dx_spine.ini index 9ab910e8a2..b43c0ca4e3 100644 --- a/tools/tolua/cocos2dx_spine.ini +++ b/tools/tolua/cocos2dx_spine.ini @@ -11,7 +11,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_studio.ini b/tools/tolua/cocos2dx_studio.ini index a25e3b67b9..5aaf483758 100644 --- a/tools/tolua/cocos2dx_studio.ini +++ b/tools/tolua/cocos2dx_studio.ini @@ -14,7 +14,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/external -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android diff --git a/tools/tolua/cocos2dx_ui.ini b/tools/tolua/cocos2dx_ui.ini index 1852a16b97..90258ae875 100644 --- a/tools/tolua/cocos2dx_ui.ini +++ b/tools/tolua/cocos2dx_ui.ini @@ -14,7 +14,7 @@ android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include -clang_flags = -nostdinc -x c++ -std=c++11 +clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__ cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android