├── OC └── XDXAudioUnitCapture │ ├── XDXAudioUnitCapture.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ ├── lichengyang.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ │ └── xiaodongxie.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ ├── lichengyang.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ └── xiaodongxie.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist │ └── XDXAudioUnitCapture │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Audio │ ├── XDXAudioCaptureManager.h │ ├── XDXAudioCaptureManager.m │ ├── XDXAudioFileHandler.h │ └── XDXAudioFileHandler.m │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ ├── XDXSingleton.h │ └── main.m └── README.md /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 48BD2FC522852346005617E0 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 48BD2FC422852346005617E0 /* AppDelegate.m */; }; 11 | 48BD2FC822852346005617E0 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 48BD2FC722852346005617E0 /* ViewController.m */; }; 12 | 48BD2FCB22852346005617E0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 48BD2FC922852346005617E0 /* Main.storyboard */; }; 13 | 48BD2FCD22852348005617E0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 48BD2FCC22852348005617E0 /* Assets.xcassets */; }; 14 | 48BD2FD022852348005617E0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 48BD2FCE22852348005617E0 /* LaunchScreen.storyboard */; }; 15 | 48BD2FD322852348005617E0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 48BD2FD222852348005617E0 /* main.m */; }; 16 | 48BD2FDC228527A7005617E0 /* XDXAudioCaptureManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 48BD2FDB228527A7005617E0 /* XDXAudioCaptureManager.m */; }; 17 | 48BD2FDF22852B16005617E0 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48BD2FDE22852B15005617E0 /* AudioToolbox.framework */; }; 18 | 48BD2FE322857BF5005617E0 /* XDXAudioFileHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 48BD2FE122857BF5005617E0 /* XDXAudioFileHandler.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 48BD2FC022852346005617E0 /* XDXAudioUnitCapture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XDXAudioUnitCapture.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 48BD2FC322852346005617E0 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 24 | 48BD2FC422852346005617E0 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 25 | 48BD2FC622852346005617E0 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 26 | 48BD2FC722852346005617E0 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 27 | 48BD2FCA22852346005617E0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 28 | 48BD2FCC22852348005617E0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 29 | 48BD2FCF22852348005617E0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 30 | 48BD2FD122852348005617E0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 48BD2FD222852348005617E0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | 48BD2FDA228527A7005617E0 /* XDXAudioCaptureManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XDXAudioCaptureManager.h; sourceTree = ""; }; 33 | 48BD2FDB228527A7005617E0 /* XDXAudioCaptureManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XDXAudioCaptureManager.m; sourceTree = ""; }; 34 | 48BD2FDE22852B15005617E0 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 35 | 48BD2FE022856AFA005617E0 /* XDXSingleton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XDXSingleton.h; sourceTree = ""; }; 36 | 48BD2FE122857BF5005617E0 /* XDXAudioFileHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XDXAudioFileHandler.m; sourceTree = ""; }; 37 | 48BD2FE222857BF5005617E0 /* XDXAudioFileHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XDXAudioFileHandler.h; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | 48BD2FBD22852346005617E0 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | 48BD2FDF22852B16005617E0 /* AudioToolbox.framework in Frameworks */, 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 48BD2FB722852346005617E0 = { 53 | isa = PBXGroup; 54 | children = ( 55 | 48BD2FC222852346005617E0 /* XDXAudioUnitCapture */, 56 | 48BD2FC122852346005617E0 /* Products */, 57 | 48BD2FDD22852B15005617E0 /* Frameworks */, 58 | ); 59 | sourceTree = ""; 60 | }; 61 | 48BD2FC122852346005617E0 /* Products */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 48BD2FC022852346005617E0 /* XDXAudioUnitCapture.app */, 65 | ); 66 | name = Products; 67 | sourceTree = ""; 68 | }; 69 | 48BD2FC222852346005617E0 /* XDXAudioUnitCapture */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 48BD2FD92285276B005617E0 /* Audio */, 73 | 48BD2FC322852346005617E0 /* AppDelegate.h */, 74 | 48BD2FC422852346005617E0 /* AppDelegate.m */, 75 | 48BD2FC622852346005617E0 /* ViewController.h */, 76 | 48BD2FC722852346005617E0 /* ViewController.m */, 77 | 48BD2FC922852346005617E0 /* Main.storyboard */, 78 | 48BD2FCC22852348005617E0 /* Assets.xcassets */, 79 | 48BD2FCE22852348005617E0 /* LaunchScreen.storyboard */, 80 | 48BD2FD122852348005617E0 /* Info.plist */, 81 | 48BD2FD222852348005617E0 /* main.m */, 82 | 48BD2FE022856AFA005617E0 /* XDXSingleton.h */, 83 | ); 84 | path = XDXAudioUnitCapture; 85 | sourceTree = ""; 86 | }; 87 | 48BD2FD92285276B005617E0 /* Audio */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 48BD2FE222857BF5005617E0 /* XDXAudioFileHandler.h */, 91 | 48BD2FE122857BF5005617E0 /* XDXAudioFileHandler.m */, 92 | 48BD2FDA228527A7005617E0 /* XDXAudioCaptureManager.h */, 93 | 48BD2FDB228527A7005617E0 /* XDXAudioCaptureManager.m */, 94 | ); 95 | path = Audio; 96 | sourceTree = ""; 97 | }; 98 | 48BD2FDD22852B15005617E0 /* Frameworks */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 48BD2FDE22852B15005617E0 /* AudioToolbox.framework */, 102 | ); 103 | name = Frameworks; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXNativeTarget section */ 109 | 48BD2FBF22852346005617E0 /* XDXAudioUnitCapture */ = { 110 | isa = PBXNativeTarget; 111 | buildConfigurationList = 48BD2FD622852348005617E0 /* Build configuration list for PBXNativeTarget "XDXAudioUnitCapture" */; 112 | buildPhases = ( 113 | 48BD2FBC22852346005617E0 /* Sources */, 114 | 48BD2FBD22852346005617E0 /* Frameworks */, 115 | 48BD2FBE22852346005617E0 /* Resources */, 116 | ); 117 | buildRules = ( 118 | ); 119 | dependencies = ( 120 | ); 121 | name = XDXAudioUnitCapture; 122 | productName = XDXAudioUnitCapture; 123 | productReference = 48BD2FC022852346005617E0 /* XDXAudioUnitCapture.app */; 124 | productType = "com.apple.product-type.application"; 125 | }; 126 | /* End PBXNativeTarget section */ 127 | 128 | /* Begin PBXProject section */ 129 | 48BD2FB822852346005617E0 /* Project object */ = { 130 | isa = PBXProject; 131 | attributes = { 132 | LastUpgradeCheck = 1020; 133 | ORGANIZATIONNAME = "小东邪"; 134 | TargetAttributes = { 135 | 48BD2FBF22852346005617E0 = { 136 | CreatedOnToolsVersion = 10.2; 137 | }; 138 | }; 139 | }; 140 | buildConfigurationList = 48BD2FBB22852346005617E0 /* Build configuration list for PBXProject "XDXAudioUnitCapture" */; 141 | compatibilityVersion = "Xcode 9.3"; 142 | developmentRegion = en; 143 | hasScannedForEncodings = 0; 144 | knownRegions = ( 145 | en, 146 | Base, 147 | ); 148 | mainGroup = 48BD2FB722852346005617E0; 149 | productRefGroup = 48BD2FC122852346005617E0 /* Products */; 150 | projectDirPath = ""; 151 | projectRoot = ""; 152 | targets = ( 153 | 48BD2FBF22852346005617E0 /* XDXAudioUnitCapture */, 154 | ); 155 | }; 156 | /* End PBXProject section */ 157 | 158 | /* Begin PBXResourcesBuildPhase section */ 159 | 48BD2FBE22852346005617E0 /* Resources */ = { 160 | isa = PBXResourcesBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | 48BD2FD022852348005617E0 /* LaunchScreen.storyboard in Resources */, 164 | 48BD2FCD22852348005617E0 /* Assets.xcassets in Resources */, 165 | 48BD2FCB22852346005617E0 /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXSourcesBuildPhase section */ 172 | 48BD2FBC22852346005617E0 /* Sources */ = { 173 | isa = PBXSourcesBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | 48BD2FDC228527A7005617E0 /* XDXAudioCaptureManager.m in Sources */, 177 | 48BD2FC822852346005617E0 /* ViewController.m in Sources */, 178 | 48BD2FE322857BF5005617E0 /* XDXAudioFileHandler.m in Sources */, 179 | 48BD2FD322852348005617E0 /* main.m in Sources */, 180 | 48BD2FC522852346005617E0 /* AppDelegate.m in Sources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXSourcesBuildPhase section */ 185 | 186 | /* Begin PBXVariantGroup section */ 187 | 48BD2FC922852346005617E0 /* Main.storyboard */ = { 188 | isa = PBXVariantGroup; 189 | children = ( 190 | 48BD2FCA22852346005617E0 /* Base */, 191 | ); 192 | name = Main.storyboard; 193 | sourceTree = ""; 194 | }; 195 | 48BD2FCE22852348005617E0 /* LaunchScreen.storyboard */ = { 196 | isa = PBXVariantGroup; 197 | children = ( 198 | 48BD2FCF22852348005617E0 /* Base */, 199 | ); 200 | name = LaunchScreen.storyboard; 201 | sourceTree = ""; 202 | }; 203 | /* End PBXVariantGroup section */ 204 | 205 | /* Begin XCBuildConfiguration section */ 206 | 48BD2FD422852348005617E0 /* Debug */ = { 207 | isa = XCBuildConfiguration; 208 | buildSettings = { 209 | ALWAYS_SEARCH_USER_PATHS = NO; 210 | CLANG_ANALYZER_NONNULL = YES; 211 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 212 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 213 | CLANG_CXX_LIBRARY = "libc++"; 214 | CLANG_ENABLE_MODULES = YES; 215 | CLANG_ENABLE_OBJC_ARC = YES; 216 | CLANG_ENABLE_OBJC_WEAK = YES; 217 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_COMMA = YES; 220 | CLANG_WARN_CONSTANT_CONVERSION = YES; 221 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 223 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 224 | CLANG_WARN_EMPTY_BODY = YES; 225 | CLANG_WARN_ENUM_CONVERSION = YES; 226 | CLANG_WARN_INFINITE_RECURSION = YES; 227 | CLANG_WARN_INT_CONVERSION = YES; 228 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 229 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 230 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 232 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 233 | CLANG_WARN_STRICT_PROTOTYPES = YES; 234 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 235 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 236 | CLANG_WARN_UNREACHABLE_CODE = YES; 237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 238 | CODE_SIGN_IDENTITY = "iPhone Developer"; 239 | COPY_PHASE_STRIP = NO; 240 | DEBUG_INFORMATION_FORMAT = dwarf; 241 | ENABLE_STRICT_OBJC_MSGSEND = YES; 242 | ENABLE_TESTABILITY = YES; 243 | GCC_C_LANGUAGE_STANDARD = gnu11; 244 | GCC_DYNAMIC_NO_PIC = NO; 245 | GCC_NO_COMMON_BLOCKS = YES; 246 | GCC_OPTIMIZATION_LEVEL = 0; 247 | GCC_PREPROCESSOR_DEFINITIONS = ( 248 | "DEBUG=1", 249 | "$(inherited)", 250 | ); 251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 253 | GCC_WARN_UNDECLARED_SELECTOR = YES; 254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 255 | GCC_WARN_UNUSED_FUNCTION = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 258 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 259 | MTL_FAST_MATH = YES; 260 | ONLY_ACTIVE_ARCH = YES; 261 | SDKROOT = iphoneos; 262 | }; 263 | name = Debug; 264 | }; 265 | 48BD2FD522852348005617E0 /* Release */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_ANALYZER_NONNULL = YES; 270 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 271 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 272 | CLANG_CXX_LIBRARY = "libc++"; 273 | CLANG_ENABLE_MODULES = YES; 274 | CLANG_ENABLE_OBJC_ARC = YES; 275 | CLANG_ENABLE_OBJC_WEAK = YES; 276 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 277 | CLANG_WARN_BOOL_CONVERSION = YES; 278 | CLANG_WARN_COMMA = YES; 279 | CLANG_WARN_CONSTANT_CONVERSION = YES; 280 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 282 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 283 | CLANG_WARN_EMPTY_BODY = YES; 284 | CLANG_WARN_ENUM_CONVERSION = YES; 285 | CLANG_WARN_INFINITE_RECURSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 288 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 289 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 290 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 291 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 292 | CLANG_WARN_STRICT_PROTOTYPES = YES; 293 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 294 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 295 | CLANG_WARN_UNREACHABLE_CODE = YES; 296 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 297 | CODE_SIGN_IDENTITY = "iPhone Developer"; 298 | COPY_PHASE_STRIP = NO; 299 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 300 | ENABLE_NS_ASSERTIONS = NO; 301 | ENABLE_STRICT_OBJC_MSGSEND = YES; 302 | GCC_C_LANGUAGE_STANDARD = gnu11; 303 | GCC_NO_COMMON_BLOCKS = YES; 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 311 | MTL_ENABLE_DEBUG_INFO = NO; 312 | MTL_FAST_MATH = YES; 313 | SDKROOT = iphoneos; 314 | VALIDATE_PRODUCT = YES; 315 | }; 316 | name = Release; 317 | }; 318 | 48BD2FD722852348005617E0 /* Debug */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 322 | CODE_SIGN_STYLE = Automatic; 323 | DEVELOPMENT_TEAM = YDEVQQ22JR; 324 | INFOPLIST_FILE = XDXAudioUnitCapture/Info.plist; 325 | LD_RUNPATH_SEARCH_PATHS = ( 326 | "$(inherited)", 327 | "@executable_path/Frameworks", 328 | ); 329 | PRODUCT_BUNDLE_IDENTIFIER = com.xdx.XDXAudioUnitCapture; 330 | PRODUCT_NAME = "$(TARGET_NAME)"; 331 | TARGETED_DEVICE_FAMILY = "1,2"; 332 | }; 333 | name = Debug; 334 | }; 335 | 48BD2FD822852348005617E0 /* Release */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 339 | CODE_SIGN_STYLE = Automatic; 340 | DEVELOPMENT_TEAM = YDEVQQ22JR; 341 | INFOPLIST_FILE = XDXAudioUnitCapture/Info.plist; 342 | LD_RUNPATH_SEARCH_PATHS = ( 343 | "$(inherited)", 344 | "@executable_path/Frameworks", 345 | ); 346 | PRODUCT_BUNDLE_IDENTIFIER = com.xdx.XDXAudioUnitCapture; 347 | PRODUCT_NAME = "$(TARGET_NAME)"; 348 | TARGETED_DEVICE_FAMILY = "1,2"; 349 | }; 350 | name = Release; 351 | }; 352 | /* End XCBuildConfiguration section */ 353 | 354 | /* Begin XCConfigurationList section */ 355 | 48BD2FBB22852346005617E0 /* Build configuration list for PBXProject "XDXAudioUnitCapture" */ = { 356 | isa = XCConfigurationList; 357 | buildConfigurations = ( 358 | 48BD2FD422852348005617E0 /* Debug */, 359 | 48BD2FD522852348005617E0 /* Release */, 360 | ); 361 | defaultConfigurationIsVisible = 0; 362 | defaultConfigurationName = Release; 363 | }; 364 | 48BD2FD622852348005617E0 /* Build configuration list for PBXNativeTarget "XDXAudioUnitCapture" */ = { 365 | isa = XCConfigurationList; 366 | buildConfigurations = ( 367 | 48BD2FD722852348005617E0 /* Debug */, 368 | 48BD2FD822852348005617E0 /* Release */, 369 | ); 370 | defaultConfigurationIsVisible = 0; 371 | defaultConfigurationName = Release; 372 | }; 373 | /* End XCConfigurationList section */ 374 | }; 375 | rootObject = 48BD2FB822852346005617E0 /* Project object */; 376 | } 377 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.xcworkspace/xcuserdata/lichengyang.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoDongXie1024/XDXAudioUnitCapture/e23a43012c0cff3245e412a5ef34c4bc13e0d9f1/OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.xcworkspace/xcuserdata/lichengyang.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.xcworkspace/xcuserdata/xiaodongxie.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XiaoDongXie1024/XDXAudioUnitCapture/e23a43012c0cff3245e412a5ef34c4bc13e0d9f1/OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/project.xcworkspace/xcuserdata/xiaodongxie.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/xcuserdata/lichengyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/xcuserdata/lichengyang.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | XDXAudioUnitCapture.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/xcuserdata/xiaodongxie.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture.xcodeproj/xcuserdata/xiaodongxie.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | XDXAudioUnitCapture.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Audio/XDXAudioCaptureManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // XDXAudioCaptureManager.h 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XDXSingleton.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | struct XDXCaptureAudioData { 15 | void *data; 16 | int size; 17 | UInt32 inNumberFrames; 18 | int64_t pts; 19 | }; 20 | 21 | typedef struct XDXCaptureAudioData* XDXCaptureAudioDataRef; 22 | 23 | @protocol XDXAudioCaptureDelegate 24 | 25 | @optional 26 | - (void)receiveAudioDataByDevice:(XDXCaptureAudioDataRef)audioDataRef; 27 | 28 | @end 29 | 30 | @interface XDXAudioCaptureManager : NSObject 31 | SingletonH 32 | 33 | @property (nonatomic, assign, readonly) BOOL isRunning; 34 | 35 | @property (nonatomic, weak) id delegate; 36 | 37 | + (instancetype)getInstance; 38 | - (void)startAudioCapture; 39 | - (void)stopAudioCapture; 40 | 41 | - (void)stopRecordFile; 42 | - (void)startRecordFile; 43 | - (void)freeAudioUnit; 44 | 45 | - (AudioStreamBasicDescription)getAudioDataFormat; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Audio/XDXAudioCaptureManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // XDXAudioCaptureManager.m 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import "XDXAudioCaptureManager.h" 10 | #import 11 | 12 | #define kXDXAudioPCMFramesPerPacket 1 13 | #define KXDXAudioBitsPerChannel 16 14 | 15 | #define INPUT_BUS 1 ///< A I/O unit's bus 1 connects to input hardware (microphone). 16 | #define OUTPUT_BUS 0 ///< A I/O unit's bus 0 connects to output hardware (speaker). 17 | 18 | const static NSString *kModuleName = @"XDXAudioCapture"; 19 | 20 | static AudioUnit m_audioUnit; 21 | static AudioBufferList *m_buffList; 22 | static AudioStreamBasicDescription m_audioDataFormat; 23 | 24 | uint32_t g_av_base_time = 100; 25 | 26 | @interface XDXAudioCaptureManager () 27 | 28 | @property (nonatomic, assign, readwrite) BOOL isRunning; 29 | 30 | @end 31 | 32 | @implementation XDXAudioCaptureManager 33 | SingletonM 34 | 35 | static OSStatus AudioCaptureCallback(void *inRefCon, 36 | AudioUnitRenderActionFlags *ioActionFlags, 37 | const AudioTimeStamp *inTimeStamp, 38 | UInt32 inBusNumber, 39 | UInt32 inNumberFrames, 40 | AudioBufferList *ioData) { 41 | AudioUnitRender(m_audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, m_buffList); 42 | 43 | if (g_av_base_time == 0) { 44 | return noErr; 45 | } 46 | 47 | XDXAudioCaptureManager *manager = (__bridge XDXAudioCaptureManager *)inRefCon; 48 | 49 | Float64 currentTime = CMTimeGetSeconds(CMClockMakeHostTimeFromSystemUnits(inTimeStamp->mHostTime)); 50 | int64_t pts = (int64_t)((currentTime - g_av_base_time) * 1000); 51 | 52 | /* Test audio fps 53 | static Float64 lastTime = 0; 54 | Float64 currentTime = CMTimeGetSeconds(CMClockMakeHostTimeFromSystemUnits(inTimeStamp->mHostTime))*1000; 55 | NSLog(@"Test duration - %f",currentTime - lastTime); 56 | lastTime = currentTime; 57 | */ 58 | 59 | void *bufferData = m_buffList->mBuffers[0].mData; 60 | UInt32 bufferSize = m_buffList->mBuffers[0].mDataByteSize; 61 | 62 | // NSLog(@"demon = %d",bufferSize); 63 | 64 | struct XDXCaptureAudioData audioData = { 65 | .data = bufferData, 66 | .size = bufferSize, 67 | .inNumberFrames = inNumberFrames, 68 | .pts = pts, 69 | }; 70 | 71 | XDXCaptureAudioDataRef audioDataRef = &audioData; 72 | 73 | if ([manager.delegate respondsToSelector:@selector(receiveAudioDataByDevice:)]) { 74 | [manager.delegate receiveAudioDataByDevice:audioDataRef]; 75 | } 76 | 77 | return noErr; 78 | } 79 | 80 | #pragma mark - Public 81 | + (instancetype)getInstance { 82 | return [[self alloc] init]; 83 | } 84 | 85 | - (void)startAudioCapture { 86 | [self startAudioCaptureWithAudioUnit:m_audioUnit 87 | isRunning:&_isRunning]; 88 | } 89 | 90 | - (void)stopAudioCapture { 91 | [self stopAudioCaptureWithAudioUnit:m_audioUnit 92 | isRunning:&_isRunning]; 93 | } 94 | 95 | - (void)freeAudioUnit { 96 | [self freeAudioUnit:m_audioUnit]; 97 | self.isRunning = NO; 98 | } 99 | - (AudioStreamBasicDescription)getAudioDataFormat { 100 | return m_audioDataFormat; 101 | } 102 | 103 | #pragma mark - Init 104 | - (instancetype)init { 105 | static dispatch_once_t onceToken; 106 | dispatch_once(&onceToken, ^{ 107 | _instace = [super init]; 108 | 109 | // Note: audioBufferSize couldn't more than durationSec max size. 110 | [_instace configureAudioInfoWithDataFormat:&m_audioDataFormat 111 | formatID:kAudioFormatLinearPCM 112 | sampleRate:44100 113 | channelCount:1 114 | audioBufferSize:2048 115 | durationSec:0.02 116 | callBack:AudioCaptureCallback]; 117 | }); 118 | return _instace; 119 | } 120 | 121 | #pragma mark - Private 122 | - (void)configureAudioInfoWithDataFormat:(AudioStreamBasicDescription *)dataFormat formatID:(UInt32)formatID sampleRate:(Float64)sampleRate channelCount:(UInt32)channelCount audioBufferSize:(int)audioBufferSize durationSec:(float)durationSec callBack:(AURenderCallback)callBack { 123 | // Configure ASBD 124 | [self configureAudioToAudioFormat:dataFormat 125 | byParamFormatID:formatID 126 | sampleRate:sampleRate 127 | channelCount:channelCount]; 128 | 129 | // Set sample time 130 | [[AVAudioSession sharedInstance] setPreferredIOBufferDuration:durationSec error:NULL]; 131 | 132 | // Configure Audio Unit 133 | m_audioUnit = [self configreAudioUnitWithDataFormat:*dataFormat 134 | audioBufferSize:audioBufferSize 135 | callBack:callBack]; 136 | } 137 | 138 | - (void)startAudioCaptureWithAudioUnit:(AudioUnit)audioUnit isRunning:(BOOL *)isRunning { 139 | OSStatus status; 140 | 141 | if (*isRunning) { 142 | NSLog(@"%@: %s - start recorder repeat \n",kModuleName,__func__); 143 | return; 144 | } 145 | 146 | status = AudioOutputUnitStart(audioUnit); 147 | if (status == noErr) { 148 | *isRunning = YES; 149 | NSLog(@"%@: %s - start audio unit success \n",kModuleName,__func__); 150 | }else { 151 | *isRunning = NO; 152 | NSLog(@"%@: %s - start audio unit failed \n",kModuleName,__func__); 153 | } 154 | } 155 | 156 | -(void)stopAudioCaptureWithAudioUnit:(AudioUnit)audioUnit isRunning:(BOOL *)isRunning { 157 | if (*isRunning == NO) { 158 | NSLog(@"%@: %s - stop capture repeat \n",kModuleName,__func__); 159 | return; 160 | } 161 | 162 | *isRunning = NO; 163 | if (audioUnit != NULL) { 164 | OSStatus status = AudioOutputUnitStop(audioUnit); 165 | if (status != noErr){ 166 | NSLog(@"%@: %s - stop audio unit failed. \n",kModuleName,__func__); 167 | }else { 168 | NSLog(@"%@: %s - stop audio unit successful",kModuleName,__func__); 169 | } 170 | } 171 | } 172 | 173 | - (void)freeAudioUnit:(AudioUnit)audioUnit { 174 | if (!audioUnit) { 175 | NSLog(@"%@: %s - repeat call!",kModuleName,__func__); 176 | return; 177 | } 178 | 179 | OSStatus result = AudioOutputUnitStop(audioUnit); 180 | if (result != noErr){ 181 | NSLog(@"%@: %s - stop audio unit failed.",kModuleName,__func__); 182 | } 183 | 184 | result = AudioUnitUninitialize(m_audioUnit); 185 | if (result != noErr) { 186 | NSLog(@"%@: %s - uninitialize audio unit failed, status : %d",kModuleName,__func__,result); 187 | } 188 | 189 | // It will trigger audio route change repeatedly 190 | result = AudioComponentInstanceDispose(m_audioUnit); 191 | if (result != noErr) { 192 | NSLog(@"%@: %s - dispose audio unit failed. status : %d",kModuleName,__func__,result); 193 | }else { 194 | audioUnit = nil; 195 | } 196 | } 197 | 198 | #pragma mark - Audio Unit 199 | - (AudioUnit)configreAudioUnitWithDataFormat:(AudioStreamBasicDescription)dataFormat audioBufferSize:(int)audioBufferSize callBack:(AURenderCallback)callBack { 200 | AudioUnit audioUnit = [self createAudioUnitObject]; 201 | 202 | if (!audioUnit) { 203 | return NULL; 204 | } 205 | 206 | [self initCaptureAudioBufferWithAudioUnit:audioUnit 207 | channelCount:dataFormat.mChannelsPerFrame 208 | dataByteSize:audioBufferSize]; 209 | 210 | 211 | [self setAudioUnitPropertyWithAudioUnit:audioUnit 212 | dataFormat:dataFormat]; 213 | 214 | [self initCaptureCallbackWithAudioUnit:audioUnit callBack:callBack]; 215 | 216 | // Calls to AudioUnitInitialize() can fail if called back-to-back on different ADM instances. A fall-back solution is to allow multiple sequential calls with as small delay between each. This factor sets the max number of allowed initialization attempts. 217 | OSStatus status = AudioUnitInitialize(audioUnit); 218 | if (status != noErr) { 219 | NSLog(@"%@: %s - couldn't init audio unit instance, status : %d \n",kModuleName,__func__,status); 220 | } 221 | 222 | return audioUnit; 223 | } 224 | 225 | - (AudioUnit)createAudioUnitObject { 226 | AudioUnit audioUnit; 227 | AudioComponentDescription audioDesc; 228 | audioDesc.componentType = kAudioUnitType_Output; 229 | audioDesc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;//kAudioUnitSubType_RemoteIO; 230 | audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple; 231 | audioDesc.componentFlags = 0; 232 | audioDesc.componentFlagsMask = 0; 233 | 234 | AudioComponent inputComponent = AudioComponentFindNext(NULL, &audioDesc); 235 | OSStatus status = AudioComponentInstanceNew(inputComponent, &audioUnit); 236 | if (status != noErr) { 237 | NSLog(@"%@: %s - create audio unit failed, status : %d \n",kModuleName, __func__, status); 238 | return NULL; 239 | }else { 240 | return audioUnit; 241 | } 242 | } 243 | 244 | - (void)initCaptureAudioBufferWithAudioUnit:(AudioUnit)audioUnit channelCount:(int)channelCount dataByteSize:(int)dataByteSize { 245 | // Disable AU buffer allocation for the recorder, we allocate our own. 246 | UInt32 flag = 0; 247 | OSStatus status = AudioUnitSetProperty(audioUnit, 248 | kAudioUnitProperty_ShouldAllocateBuffer, 249 | kAudioUnitScope_Output, 250 | INPUT_BUS, 251 | &flag, 252 | sizeof(flag)); 253 | if (status != noErr) { 254 | NSLog(@"%@: %s - couldn't allocate buffer of callback, status : %d \n", kModuleName, __func__, status); 255 | } 256 | 257 | AudioBufferList * buffList = (AudioBufferList*)malloc(sizeof(AudioBufferList)); 258 | buffList->mNumberBuffers = 1; 259 | buffList->mBuffers[0].mNumberChannels = channelCount; 260 | buffList->mBuffers[0].mDataByteSize = dataByteSize; 261 | buffList->mBuffers[0].mData = (UInt32 *)malloc(dataByteSize); 262 | m_buffList = buffList; 263 | } 264 | 265 | 266 | - (void)setAudioUnitPropertyWithAudioUnit:(AudioUnit)audioUnit dataFormat:(AudioStreamBasicDescription)dataFormat { 267 | OSStatus status; 268 | status = AudioUnitSetProperty(audioUnit, 269 | kAudioUnitProperty_StreamFormat, 270 | kAudioUnitScope_Output, 271 | INPUT_BUS, 272 | &dataFormat, 273 | sizeof(dataFormat)); 274 | if (status != noErr) { 275 | NSLog(@"%@: %s - set audio unit stream format failed, status : %d \n",kModuleName, __func__,status); 276 | } 277 | 278 | /* 279 | // remove echo but can't effect by testing. 280 | UInt32 echoCancellation = 0; 281 | AudioUnitSetProperty(m_audioUnit, 282 | kAUVoiceIOProperty_BypassVoiceProcessing, 283 | kAudioUnitScope_Global, 284 | 0, 285 | &echoCancellation, 286 | sizeof(echoCancellation)); 287 | */ 288 | 289 | UInt32 enableFlag = 1; 290 | status = AudioUnitSetProperty(audioUnit, 291 | kAudioOutputUnitProperty_EnableIO, 292 | kAudioUnitScope_Input, 293 | INPUT_BUS, 294 | &enableFlag, 295 | sizeof(enableFlag)); 296 | if (status != noErr) { 297 | NSLog(@"%@: %s - could not enable input on AURemoteIO, status : %d \n",kModuleName, __func__, status); 298 | } 299 | 300 | UInt32 disableFlag = 0; 301 | status = AudioUnitSetProperty(audioUnit, 302 | kAudioOutputUnitProperty_EnableIO, 303 | kAudioUnitScope_Output, 304 | OUTPUT_BUS, 305 | &disableFlag, 306 | sizeof(disableFlag)); 307 | if (status != noErr) { 308 | NSLog(@"%@: %s - could not enable output on AURemoteIO, status : %d \n",kModuleName, __func__,status); 309 | } 310 | } 311 | 312 | - (void)initCaptureCallbackWithAudioUnit:(AudioUnit)audioUnit callBack:(AURenderCallback)callBack { 313 | AURenderCallbackStruct captureCallback; 314 | captureCallback.inputProc = callBack; 315 | captureCallback.inputProcRefCon = (__bridge void *)self; 316 | OSStatus status = AudioUnitSetProperty(audioUnit, 317 | kAudioOutputUnitProperty_SetInputCallback, 318 | kAudioUnitScope_Global, 319 | INPUT_BUS, 320 | &captureCallback, 321 | sizeof(captureCallback)); 322 | 323 | if (status != noErr) { 324 | NSLog(@"%@: %s - Audio Unit set capture callback failed, status : %d \n",kModuleName, __func__,status); 325 | } 326 | } 327 | 328 | #pragma mark - ASBD Audio Format 329 | -(void)configureAudioToAudioFormat:(AudioStreamBasicDescription *)audioFormat byParamFormatID:(UInt32)formatID sampleRate:(Float64)sampleRate channelCount:(UInt32)channelCount { 330 | AudioStreamBasicDescription dataFormat = {0}; 331 | UInt32 size = sizeof(dataFormat.mSampleRate); 332 | // Get hardware origin sample rate. (Recommended it) 333 | Float64 hardwareSampleRate = 0; 334 | AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, 335 | &size, 336 | &hardwareSampleRate); 337 | // Manual set sample rate 338 | dataFormat.mSampleRate = sampleRate; 339 | 340 | size = sizeof(dataFormat.mChannelsPerFrame); 341 | // Get hardware origin channels number. (Must refer to it) 342 | UInt32 hardwareNumberChannels = 0; 343 | AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, 344 | &size, 345 | &hardwareNumberChannels); 346 | dataFormat.mChannelsPerFrame = channelCount; 347 | 348 | dataFormat.mFormatID = formatID; 349 | 350 | if (formatID == kAudioFormatLinearPCM) { 351 | dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; 352 | dataFormat.mBitsPerChannel = KXDXAudioBitsPerChannel; 353 | dataFormat.mBytesPerPacket = dataFormat.mBytesPerFrame = (dataFormat.mBitsPerChannel / 8) * dataFormat.mChannelsPerFrame; 354 | dataFormat.mFramesPerPacket = kXDXAudioPCMFramesPerPacket; 355 | } 356 | 357 | memcpy(audioFormat, &dataFormat, sizeof(dataFormat)); 358 | NSLog(@"%@: %s - sample rate:%f, channel count:%d",kModuleName, __func__,sampleRate,channelCount); 359 | } 360 | 361 | @end 362 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Audio/XDXAudioFileHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // XDXAudioFileHandler.h 3 | // XDXAudioQueueRecordAndPlayback 4 | // 5 | // Created by 小东邪 on 2019/5/3. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XDXSingleton.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface XDXAudioFileHandler : NSObject 15 | SingletonH 16 | 17 | + (instancetype)getInstance; 18 | 19 | /** 20 | * Write audio data to file. 21 | */ 22 | - (void)writeFileWithInNumBytes:(UInt32)inNumBytes 23 | ioNumPackets:(UInt32 )ioNumPackets 24 | inBuffer:(const void *)inBuffer 25 | inPacketDesc:(nullable const AudioStreamPacketDescription*)inPacketDesc; 26 | 27 | #pragma mark - Audio Queue 28 | /** 29 | * Start / Stop record By Audio Queue. 30 | */ 31 | -(void)startVoiceRecordByAudioQueue:(AudioQueueRef)audioQueue 32 | isNeedMagicCookie:(BOOL)isNeedMagicCookie 33 | audioDesc:(AudioStreamBasicDescription)audioDesc; 34 | 35 | -(void)stopVoiceRecordByAudioQueue:(AudioQueueRef)audioQueue 36 | needMagicCookie:(BOOL)isNeedMagicCookie; 37 | 38 | 39 | /** 40 | * Start / Stop record By Audio Converter. 41 | */ 42 | -(void)startVoiceRecordByAudioUnitByAudioConverter:(nullable AudioConverterRef)audioConverter 43 | needMagicCookie:(BOOL)isNeedMagicCookie 44 | audioDesc:(AudioStreamBasicDescription)audioDesc; 45 | 46 | -(void)stopVoiceRecordAudioConverter:(nullable AudioConverterRef)audioConverter 47 | needMagicCookie:(BOOL)isNeedMagicCookie; 48 | @end 49 | 50 | NS_ASSUME_NONNULL_END 51 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Audio/XDXAudioFileHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // XDXAudioFileHandler.m 3 | // XDXAudioQueueRecordAndPlayback 4 | // 5 | // Created by 小东邪 on 2019/5/3. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import "XDXAudioFileHandler.h" 10 | 11 | static const NSString *kModuleName = @"Audio File"; 12 | 13 | @interface XDXAudioFileHandler () 14 | { 15 | AudioFileID m_recordFile; 16 | SInt64 m_recordCurrentPacket; // current packet number in record file 17 | } 18 | 19 | @property (nonatomic, copy) NSString *recordFilePath; 20 | 21 | @end 22 | 23 | @implementation XDXAudioFileHandler 24 | SingletonM 25 | 26 | #pragma mark - Init 27 | + (instancetype)getInstance { 28 | return [[self alloc] init]; 29 | } 30 | 31 | #pragma mark - Public 32 | -(void)startVoiceRecordByAudioUnitByAudioConverter:(nullable AudioConverterRef)audioConverter needMagicCookie:(BOOL)isNeedMagicCookie audioDesc:(AudioStreamBasicDescription)audioDesc { 33 | self.recordFilePath = [self createFilePath]; 34 | NSLog(@"%@:%s - record file path:%@",kModuleName,__func__,self.recordFilePath); 35 | 36 | // create the audio file 37 | m_recordFile = [self createAudioFileWithFilePath:self.recordFilePath 38 | AudioDesc:audioDesc]; 39 | 40 | if (isNeedMagicCookie) { 41 | // add magic cookie contain header file info for VBR data 42 | [self copyEncoderCookieToFileByAudioConverter:audioConverter 43 | inFile:m_recordFile]; 44 | } 45 | } 46 | 47 | -(void)stopVoiceRecordAudioConverter:(nullable AudioConverterRef)audioConverter needMagicCookie:(BOOL)isNeedMagicCookie { 48 | if (isNeedMagicCookie) { 49 | // reconfirm magic cookie at the end. 50 | [self copyEncoderCookieToFileByAudioConverter:audioConverter 51 | inFile:m_recordFile]; 52 | } 53 | 54 | AudioFileClose(m_recordFile); 55 | m_recordCurrentPacket = 0; 56 | } 57 | 58 | -(void)startVoiceRecordByAudioQueue:(AudioQueueRef)audioQueue isNeedMagicCookie:(BOOL)isNeedMagicCookie audioDesc:(AudioStreamBasicDescription)audioDesc { 59 | self.recordFilePath = [self createFilePath]; 60 | NSLog(@"%@:%s - record file path:%@",kModuleName,__func__,self.recordFilePath); 61 | 62 | // create the audio file 63 | m_recordFile = [self createAudioFileWithFilePath:self.recordFilePath 64 | AudioDesc:audioDesc]; 65 | 66 | if (isNeedMagicCookie) { 67 | // add magic cookie contain header file info for VBR data 68 | [self copyEncoderCookieToFileByAudioQueue:audioQueue 69 | inFile:m_recordFile]; 70 | } 71 | } 72 | 73 | -(void)stopVoiceRecordByAudioQueue:(AudioQueueRef)audioQueue needMagicCookie:(BOOL)isNeedMagicCookie { 74 | if (isNeedMagicCookie) { 75 | // reconfirm magic cookie at the end. 76 | [self copyEncoderCookieToFileByAudioQueue:audioQueue 77 | inFile:m_recordFile]; 78 | } 79 | 80 | AudioFileClose(m_recordFile); 81 | m_recordCurrentPacket = 0; 82 | } 83 | 84 | - (void)writeFileWithInNumBytes:(UInt32)inNumBytes ioNumPackets:(UInt32 )ioNumPackets inBuffer:(const void *)inBuffer inPacketDesc:(nullable const AudioStreamPacketDescription*)inPacketDesc { 85 | if (!m_recordFile) { 86 | return; 87 | } 88 | 89 | // AudioStreamPacketDescription outputPacketDescriptions; 90 | OSStatus status = AudioFileWritePackets(m_recordFile, 91 | false, 92 | inNumBytes, 93 | inPacketDesc, 94 | m_recordCurrentPacket, 95 | &ioNumPackets, 96 | inBuffer); 97 | 98 | if (status == noErr) { 99 | m_recordCurrentPacket += ioNumPackets; // 用于记录起始位置 100 | }else { 101 | NSLog(@"%@:%s - write file status = %d \n",kModuleName,__func__,(int)status); 102 | } 103 | 104 | } 105 | 106 | #pragma mark - Private 107 | #pragma mark File Path 108 | - (NSString *)createFilePath { 109 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 110 | dateFormatter.dateFormat = @"yyyy_MM_dd__HH_mm_ss"; 111 | NSString *date = [dateFormatter stringFromDate:[NSDate date]]; 112 | 113 | NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 114 | NSUserDomainMask, 115 | YES); 116 | 117 | NSString *documentPath = [[searchPaths objectAtIndex:0] stringByAppendingPathComponent:@"Voice"]; 118 | 119 | // 先创建子目录. 注意,若果直接调用AudioFileCreateWithURL创建一个不存在的目录创建文件会失败 120 | NSFileManager *fileManager = [NSFileManager defaultManager]; 121 | if (![fileManager fileExistsAtPath:documentPath]) { 122 | [fileManager createDirectoryAtPath:documentPath withIntermediateDirectories:YES attributes:nil error:nil]; 123 | } 124 | 125 | NSString *fullFileName = [NSString stringWithFormat:@"%@.caf",date]; 126 | NSString *filePath = [documentPath stringByAppendingPathComponent:fullFileName]; 127 | return filePath; 128 | } 129 | 130 | - (AudioFileID)createAudioFileWithFilePath:(NSString *)filePath AudioDesc:(AudioStreamBasicDescription)audioDesc { 131 | CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)filePath, NULL); 132 | NSLog(@"%@:%s - record file path:%@",kModuleName,__func__,filePath); 133 | 134 | AudioFileID audioFile; 135 | // create the audio file 136 | OSStatus status = AudioFileCreateWithURL(url, 137 | kAudioFileCAFType, 138 | &audioDesc, 139 | kAudioFileFlags_EraseFile, 140 | &audioFile); 141 | if (status != noErr) { 142 | NSLog(@"%@:%s - AudioFileCreateWithURL Failed, status:%d",kModuleName,__func__,(int)status); 143 | } 144 | 145 | CFRelease(url); 146 | 147 | return audioFile; 148 | } 149 | 150 | #pragma mark Magic Cookie 151 | - (void)copyEncoderCookieToFileByAudioQueue:(AudioQueueRef)inQueue inFile:(AudioFileID)inFile { 152 | OSStatus result = noErr; 153 | UInt32 cookieSize; 154 | 155 | result = AudioQueueGetPropertySize ( 156 | inQueue, 157 | kAudioQueueProperty_MagicCookie, 158 | &cookieSize 159 | ); 160 | if (result == noErr) { 161 | char* magicCookie = (char *) malloc (cookieSize); 162 | result =AudioQueueGetProperty ( 163 | inQueue, 164 | kAudioQueueProperty_MagicCookie, 165 | magicCookie, 166 | &cookieSize 167 | ); 168 | if (result == noErr) { 169 | result = AudioFileSetProperty ( 170 | inFile, 171 | kAudioFilePropertyMagicCookieData, 172 | cookieSize, 173 | magicCookie 174 | ); 175 | if (result == noErr) { 176 | NSLog(@"%@:%s - set Magic cookie successful.",kModuleName,__func__); 177 | }else { 178 | NSLog(@"%@:%s - set Magic cookie failed.",kModuleName,__func__); 179 | } 180 | }else { 181 | NSLog(@"%@:%s - get Magic cookie failed.",kModuleName,__func__); 182 | } 183 | free (magicCookie); 184 | 185 | }else { 186 | NSLog(@"%@:%s - Magic cookie: get size failed.",kModuleName,__func__); 187 | } 188 | 189 | } 190 | 191 | -(void)copyEncoderCookieToFileByAudioConverter:(AudioConverterRef)audioConverter inFile:(AudioFileID)inFile { 192 | // Grab the cookie from the converter and write it to the destination file. 193 | UInt32 cookieSize = 0; 194 | OSStatus error = AudioConverterGetPropertyInfo(audioConverter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL); 195 | 196 | if (error == noErr && cookieSize != 0) { 197 | char *cookie = (char *)malloc(cookieSize * sizeof(char)); 198 | error = AudioConverterGetProperty(audioConverter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie); 199 | 200 | if (error == noErr) { 201 | error = AudioFileSetProperty(inFile, kAudioFilePropertyMagicCookieData, cookieSize, cookie); 202 | if (error == noErr) { 203 | UInt32 willEatTheCookie = false; 204 | error = AudioFileGetPropertyInfo(inFile, kAudioFilePropertyMagicCookieData, NULL, &willEatTheCookie); 205 | if (error == noErr) { 206 | NSLog(@"%@:%s - Writing magic cookie to destination file: %u cookie:%d \n",kModuleName,__func__, (unsigned int)cookieSize, willEatTheCookie); 207 | }else { 208 | NSLog(@"%@:%s - Could not Writing magic cookie to destination file status:%d \n",kModuleName,__func__,(int)error); 209 | } 210 | } else { 211 | NSLog(@"%@:%s - Even though some formats have cookies, some files don't take them and that's OK,set cookie status:%d \n",kModuleName,__func__,(int)error); 212 | } 213 | } else { 214 | NSLog(@"%@:%s - Could not Get kAudioConverterCompressionMagicCookie from Audio Converter!\n status:%d ",kModuleName,__func__,(int)error); 215 | } 216 | 217 | free(cookie); 218 | }else { 219 | // If there is an error here, then the format doesn't have a cookie - this is perfectly fine as som formats do not. 220 | NSLog(@"%@:%s - cookie status:%d, %d \n",kModuleName,__func__,(int)error, cookieSize); 221 | } 222 | } 223 | 224 | 225 | @end 226 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 33 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSMicrophoneUsageDescription 6 | 需要麦克风 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "XDXAudioCaptureManager.h" 11 | #import 12 | #import "XDXAudioFileHandler.h" 13 | 14 | @interface ViewController () 15 | 16 | @property (nonatomic, assign) BOOL isRecordVoice; 17 | 18 | @end 19 | 20 | @implementation ViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | [XDXAudioCaptureManager getInstance].delegate = self; 25 | [[XDXAudioCaptureManager getInstance] startAudioCapture]; 26 | } 27 | 28 | - (IBAction)startRecord:(id)sender { 29 | [self startRecordFile]; 30 | } 31 | 32 | - (IBAction)stopRecord:(id)sender { 33 | [self stopRecordFile]; 34 | } 35 | 36 | - (void)dealloc { 37 | [[XDXAudioCaptureManager getInstance] stopAudioCapture]; 38 | } 39 | #pragma mark - Record 40 | - (void)startRecordFile { 41 | AudioStreamBasicDescription audioFormat = [[XDXAudioCaptureManager getInstance] getAudioDataFormat]; 42 | [[XDXAudioFileHandler getInstance] startVoiceRecordByAudioUnitByAudioConverter:nil 43 | needMagicCookie:NO 44 | audioDesc:audioFormat]; 45 | self.isRecordVoice = YES; 46 | } 47 | 48 | - (void)stopRecordFile { 49 | self.isRecordVoice = NO; 50 | [[XDXAudioFileHandler getInstance] stopVoiceRecordAudioConverter:nil 51 | needMagicCookie:NO]; 52 | } 53 | #pragma mark - Delegate 54 | - (void)receiveAudioDataByDevice:(XDXCaptureAudioDataRef)audioDataRef { 55 | if (self.isRecordVoice) { 56 | [[XDXAudioFileHandler getInstance] writeFileWithInNumBytes:audioDataRef->size 57 | ioNumPackets:audioDataRef->inNumberFrames 58 | inBuffer:audioDataRef->data 59 | inPacketDesc:NULL]; 60 | } 61 | 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/XDXSingleton.h: -------------------------------------------------------------------------------- 1 | // 2 | // XDXSingleton.h 3 | // 4 | // Created by 小东邪 on 2018/6/15. 5 | // Copyright © 2018 小东邪. All rights reserved. 6 | // 7 | 8 | #ifndef XDXSingleton_h 9 | #define XDXSingleton_h 10 | 11 | // .h文件的实现 12 | #define SingletonH 13 | 14 | // .m文件的实现 15 | #if __has_feature(objc_arc) // 是ARC 16 | #define SingletonM \ 17 | static id _instace = nil; \ 18 | + (id)allocWithZone:(struct _NSZone *)zone \ 19 | { \ 20 | if (_instace == nil) { \ 21 | static dispatch_once_t onceToken; \ 22 | dispatch_once(&onceToken, ^{ \ 23 | _instace = [super allocWithZone:zone]; \ 24 | }); \ 25 | } \ 26 | return _instace; \ 27 | } \ 28 | \ 29 | + (id)copyWithZone:(struct _NSZone *)zone \ 30 | { \ 31 | return _instace; \ 32 | } \ 33 | \ 34 | + (id)mutableCopyWithZone:(struct _NSZone *)zone \ 35 | { \ 36 | return _instace; \ 37 | } 38 | 39 | #else // 不是ARC 40 | 41 | #define SingletonM \ 42 | static id _instace = nil; \ 43 | + (id)allocWithZone:(struct _NSZone *)zone \ 44 | { \ 45 | if (_instace == nil) { \ 46 | static dispatch_once_t onceToken; \ 47 | dispatch_once(&onceToken, ^{ \ 48 | _instace = [super allocWithZone:zone]; \ 49 | }); \ 50 | } \ 51 | return _instace; \ 52 | } \ 53 | \ 54 | - (id)init \ 55 | { \ 56 | static dispatch_once_t onceToken; \ 57 | dispatch_once(&onceToken, ^{ \ 58 | _instace = [super init]; \ 59 | }); \ 60 | return _instace; \ 61 | } \ 62 | \ 63 | - (oneway void)release \ 64 | { \ 65 | \ 66 | } \ 67 | \ 68 | - (id)retain \ 69 | { \ 70 | return self; \ 71 | } \ 72 | \ 73 | - (NSUInteger)retainCount \ 74 | { \ 75 | return 1; \ 76 | } \ 77 | + (id)copyWithZone:(struct _NSZone *)zone \ 78 | { \ 79 | return _instace; \ 80 | } \ 81 | \ 82 | + (id)mutableCopyWithZone:(struct _NSZone *)zone \ 83 | { \ 84 | return _instace; \ 85 | } 86 | #endif 87 | 88 | #endif /* XDXSingleton_h */ 89 | -------------------------------------------------------------------------------- /OC/XDXAudioUnitCapture/XDXAudioUnitCapture/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // XDXAudioUnitCapture 4 | // 5 | // Created by 小东邪 on 2019/5/10. 6 | // Copyright © 2019 小东邪. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XDXAudioUnitCapture 2 | iOS: Audio Capture - Base on Audio Unit (Remote IO/ Voice-Processing I/O) 3 | --------------------------------------------------------------------------------