├── ACBAVPlayerExtension ├── Screenshots │ ├── AVPlayerGif1.gif │ └── AVPlayerScreen1.png ├── Classes │ ├── ViewControllers │ │ ├── ViewController.h │ │ └── ViewController.m │ ├── General │ │ ├── AppDelegate.h │ │ └── AppDelegate.m │ └── AudioProcessing │ │ ├── ACBAudioProcessHelper.h │ │ ├── AVPlayer+ACBHelper.h │ │ ├── MYAudioTapProcessor.h │ │ ├── AVPlayer+ACBHelper.m │ │ ├── ACBAudioProcessHelper.m │ │ └── MYAudioTapProcessor.m ├── main.m ├── Info.plist └── Resources │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ └── Assets.xcassets │ └── AppIcon.appiconset │ └── Contents.json ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── ACBAVPlayerExtension.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ └── ACBAVPlayer.xcscheme └── project.pbxproj ├── ACBAVPlayer ├── ACBAVPlayer.h └── Info.plist ├── .gitignore ├── Package.swift ├── ACBAVPlayerTests ├── Info.plist └── ACBAVPlayerTests.swift ├── ACBAVPlayer.podspec ├── LICENSE └── README.md /ACBAVPlayerExtension/Screenshots/AVPlayerGif1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akhilcb/ACBAVPlayerExtension/HEAD/ACBAVPlayerExtension/Screenshots/AVPlayerGif1.gif -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Screenshots/AVPlayerScreen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akhilcb/ACBAVPlayerExtension/HEAD/ACBAVPlayerExtension/Screenshots/AVPlayerScreen1.png -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/ViewControllers/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ACBAVPlayerExtension 4 | // 5 | // Created by Akhil on 8/10/17. 6 | // Copyright © 2017 akhil. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/General/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ACBAVPlayerExtension 4 | // 5 | // Created by Akhil on 8/10/17. 6 | // Copyright © 2017 akhil. 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 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ACBAVPlayerExtension 4 | // 5 | // Created by Akhil on 8/10/17. 6 | // Copyright © 2017 akhil. 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 | -------------------------------------------------------------------------------- /ACBAVPlayer/ACBAVPlayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACBAVPlayer.h 3 | // ACBAVPlayer 4 | // 5 | // Created by Akhil C Balan on 1/7/18. 6 | // Copyright © 2018 akhil. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for ACBAVPlayer. 12 | FOUNDATION_EXPORT double ACBAVPlayerVersionNumber; 13 | 14 | //! Project version string for ACBAVPlayer. 15 | FOUNDATION_EXPORT const unsigned char ACBAVPlayerVersionString[]; 16 | 17 | 18 | #import 19 | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | 3 | ## Build generated 4 | build/ 5 | DerivedData/ 6 | 7 | ## Various settings 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata/ 17 | 18 | ## Other 19 | *.moved-aside 20 | *.xccheckout 21 | *.xcscmblueprint 22 | 23 | ## Obj-C/Swift specific 24 | *.hmap 25 | *.ipa 26 | *.dSYM.zip 27 | *.dSYM 28 | 29 | ## CocoaPods 30 | Pods/ 31 | 32 | ## Carthage 33 | Carthage/Checkouts 34 | Carthage/Build -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.6 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "ACBAVPlayerExtension", 8 | platforms: [ 9 | .iOS(.v14), 10 | .macOS(.v10_12) 11 | ], 12 | products: [ 13 | .library( 14 | name: "ACBAVPlayerExtension", 15 | targets: ["ACBAVPlayerExtension"]) 16 | ], 17 | dependencies: [ 18 | ], 19 | targets: [ 20 | .target( 21 | name: "ACBAVPlayerExtension", 22 | dependencies: [], 23 | path: "ACBAVPlayerExtension/Classes/AudioProcessing", 24 | publicHeadersPath: ".") 25 | ], 26 | swiftLanguageVersions: [.v5] 27 | ) 28 | -------------------------------------------------------------------------------- /ACBAVPlayerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ACBAVPlayer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.1 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ACBAVPlayer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ACBAVPlayer" 3 | s.version = "2.1" 4 | s.summary = "An extension on AVPlayer which converts it to have all useful features of AVAudioPlayer but with streaming support." 5 | s.description = <<-DESC 6 | An extension on AVPlayer which converts it to have all useful features of AVAudioPlayer but with streaming support. Also added additional methods to support Audio visualization from AVPlayer streaming. This extension adds some missing features to AVPlayer. 7 | DESC 8 | s.homepage = "https://github.com/akhilcb/ACBAVPlayerExtension" 9 | s.license = "MIT" 10 | s.author = "Akhil" 11 | s.platform = :ios 12 | s.source = { :git => "https://github.com/akhilcb/ACBAVPlayerExtension.git", :tag => "2.1" } 13 | s.source_files = "ACBAVPlayerExtension", "ACBAVPlayerExtension/Classes/AudioProcessing/*.{h,m}" 14 | s.exclude_files = "ACBAVPlayerExtension/main.m" 15 | s.public_header_files = "ACBAVPlayerExtension/Classes/AudioProcessing/AVPlayer+ACBHelper.h" 16 | end 17 | -------------------------------------------------------------------------------- /ACBAVPlayerTests/ACBAVPlayerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ACBAVPlayerTests.swift 3 | // ACBAVPlayerTests 4 | // 5 | // Created by Akhil C Balan on 1/7/18. 6 | // Copyright © 2018 akhil. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ACBAVPlayer 11 | 12 | class ACBAVPlayerTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017, Akhil C Balan(https://github.com/akhilcb) 4 | 5 | All rights reserved 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/AudioProcessing/ACBAudioProcessHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACBAudioProcessHelper.h 3 | // ACBAudioPlayer 4 | // 5 | // Created by Akhil C Balan on 3/3/16. 6 | // Copyright © 2016 Akhil. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^ACBAudioProcessHelperMeteringBlock) (NSArray *iAvgPowerList, BOOL iSuccess); 13 | typedef void (^ACBAudioProcessHelperBufferFetchedBlock) (AVAudioPCMBuffer *audioPCMBuffer, BOOL iSuccess); 14 | 15 | @interface ACBAudioProcessHelper : NSObject 16 | 17 | @property (nonatomic, readonly, assign) int numberOfChannels; 18 | @property (nonatomic, weak) AVPlayer *player; 19 | @property (nonatomic, getter=isMeteringEnabled) BOOL meteringEnabled; /* turns level metering on or off. default is off. */ 20 | 21 | - (float)averagePowerInLinearFormForChannel:(NSUInteger)channelNumber; //returns in average power in linear form. Value is in between 0 to 1. 22 | - (float)averagePowerForChannel:(NSUInteger)channelNumber; /* returns average power in decibels for a given channel */ 23 | 24 | - (void)averagePowerListWithCallbackBlock:(ACBAudioProcessHelperMeteringBlock)iMeteringCallbackBlock; 25 | - (void)averagePowerListInLinearFormWithCallbackBlock:(ACBAudioProcessHelperMeteringBlock)iMeteringCallbackBlock; 26 | - (void)audioPCMBufferFetchedWithCallbackBlock:(ACBAudioProcessHelperBufferFetchedBlock)iAudioBufferFetchedBlock; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 2.1 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UIRequiresFullScreen 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Resources/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 | 27 | 28 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Resources/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 | } -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/AudioProcessing/AVPlayer+ACBHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // AVPlayer+ACBHelper.h 3 | // ACBAudioPlayer 4 | // 5 | // Created by Akhil C Balan on 3/3/16. 6 | // Copyright © 2016 Akhil. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^ACBAVPlayerMeteringBlock) (NSArray * _Nullable iAvgPowerList, BOOL iSuccess); 13 | typedef void (^ACBAVPlayerBufferFetchedBlock) (AVAudioPCMBuffer * _Nullable audioPCMBuffer, BOOL iSuccess); 14 | 15 | 16 | @interface AVPlayer(ACBHelper) 17 | 18 | @property (nonatomic, readonly, assign) int numberOfChannels; 19 | 20 | //stop video 21 | - (void)stop; 22 | 23 | 24 | /* metering */ 25 | @property (nonatomic, getter=isMeteringEnabled) BOOL meteringEnabled; /* turns level metering on or off. default is off. */ 26 | 27 | - (void)updateMeters; /* call to refresh meter values */ //does nothing for now 28 | 29 | - (float)peakPowerForChannel:(NSUInteger)channelNumber; /* for peak power in decibels for a given channel. returns average power for now */ 30 | - (float)averagePowerForChannel:(NSUInteger)channelNumber; /* returns average power in decibels for a given channel */ 31 | 32 | 33 | //use this to repeatedly fetch average power list(in decibels) for all channels in iMeteringCallbackBlock. This block will be executed each time a value is fetched. Index of array is channel number 34 | - (void)averagePowerListWithCallbackBlock:(ACBAVPlayerMeteringBlock _Nullable )iMeteringCallbackBlock; 35 | 36 | - (float)averagePowerInLinearFormForChannel:(NSUInteger)channelNumber; //returns in average power in linear form. Value is in between 0 to 1. 37 | 38 | //fetch average power list in linear form(values in between 0 and 1) 39 | - (void)averagePowerListInLinearFormWithCallbackBlock:(ACBAVPlayerMeteringBlock _Nullable )iMeteringCallbackBlock; 40 | 41 | //fetch AVAudioPCMBuffer. it has useful methods to manipuate buffers or to display a visualizer 42 | - (void)audioPCMBufferFetchedWithCallbackBlock:(ACBAVPlayerBufferFetchedBlock _Nullable )iAudioBufferFetchedBlock; 43 | 44 | //use this instead of "replaceCurrentItemWithPlayerItem" for metering to work. 45 | - (void)replaceCurrentItemAndUpdateMeteringForPlayerItem:(nullable AVPlayerItem *)item; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/General/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ACBAVPlayerExtension 4 | // 5 | // Created by Akhil on 8/10/17. 6 | // Copyright © 2017 akhil. 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 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension.xcodeproj/xcshareddata/xcschemes/ACBAVPlayer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/AudioProcessing/MYAudioTapProcessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: MYAudioTapProcessor.h 3 | Abstract: Audio tap processor using MTAudioProcessingTap for audio visualization and processing. 4 | Version: 1.0.1 5 | 6 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 | Inc. ("Apple") in consideration of your agreement to the following 8 | terms, and your use, installation, modification or redistribution of 9 | this Apple software constitutes acceptance of these terms. If you do 10 | not agree with these terms, please do not use, install, modify or 11 | redistribute this Apple software. 12 | 13 | In consideration of your agreement to abide by the following terms, and 14 | subject to these terms, Apple grants you a personal, non-exclusive 15 | license, under Apple's copyrights in this original Apple software (the 16 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 | Software, with or without modifications, in source and/or binary forms; 18 | provided that if you redistribute the Apple Software in its entirety and 19 | without modifications, you must retain this notice and the following 20 | text and disclaimers in all such redistributions of the Apple Software. 21 | Neither the name, trademarks, service marks or logos of Apple Inc. may 22 | be used to endorse or promote products derived from the Apple Software 23 | without specific prior written permission from Apple. Except as 24 | expressly stated in this notice, no other rights or licenses, express or 25 | implied, are granted by Apple herein, including but not limited to any 26 | patent rights that may be infringed by your derivative works or by other 27 | works in which the Apple Software may be incorporated. 28 | 29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 | 35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 | POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2013 Apple Inc. All Rights Reserved. 45 | 46 | Modified to add additional methods 47 | */ 48 | 49 | #import 50 | 51 | @class AVAudioMix; 52 | @class AVAssetTrack; 53 | @class AVAudioPCMBuffer; 54 | 55 | @protocol MYAudioTabProcessorDelegate; 56 | 57 | @interface MYAudioTapProcessor : NSObject 58 | 59 | // Designated initializer. 60 | - (id)initWithAudioAssetTrack:(AVAssetTrack *)audioAssetTrack; 61 | 62 | // Properties 63 | @property (readonly, nonatomic) AVAssetTrack *audioAssetTrack; 64 | @property (readonly, nonatomic) AVAudioMix *audioMix; 65 | @property (weak, nonatomic) id delegate; 66 | @property (nonatomic, getter = isBandpassFilterEnabled) BOOL enableBandpassFilter; 67 | @property (nonatomic) float centerFrequency; // [0 .. 1] 68 | @property (nonatomic) float bandwidth; // [0 .. 1] 69 | @property (nonatomic, assign) int numberOfChannels; 70 | 71 | - (void)stopProcessing; 72 | 73 | @end 74 | 75 | #pragma mark - Protocols 76 | 77 | @protocol MYAudioTabProcessorDelegate 78 | 79 | // Add comment… 80 | - (void)audioTabProcessor:(MYAudioTapProcessor *)audioTabProcessor hasNewLeftChannelValue:(float)leftChannelValue rightChannelValue:(float)rightChannelValue; 81 | - (void)audioTabProcessor:(MYAudioTapProcessor *)audioTabProcessor hasNewChannelVolumeList:(NSArray *)iChannelVolumeList; 82 | - (void)audioTabProcessor:(MYAudioTapProcessor *)audioTabProcessor didReceiveBuffer:(AVAudioPCMBuffer *)buffer; 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/ViewControllers/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ACBAVPlayerExtension 4 | // 5 | // Created by Akhil on 8/10/17. 6 | // Copyright © 2017 akhil. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "AVPlayer+ACBHelper.h" 11 | #import 12 | 13 | 14 | @interface ViewController () 15 | 16 | @property (nonatomic, strong) AVPlayer *player; 17 | @property (nonatomic, weak) IBOutlet UIProgressView *progressBar; 18 | @property (nonatomic, strong) NSString *url; 19 | @property (nonatomic, strong) NSString *firstUrl; 20 | @property (nonatomic, strong) NSString *secondUrl; 21 | 22 | @end 23 | 24 | 25 | @implementation ViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | self.progressBar.progress = 0.0; 30 | self.firstUrl = @"https://archive.org/download/WildlifeSampleVideo/Wildlife.mp4"; 31 | // @"http://content.viki.com/test_ios/ios_240.m3u8"; 32 | //@"https://scontent.cdninstagram.com/hphotos-xfa1/t50.2886-16/11719145_918467924880620_816495633_n.mp4"; 33 | //http://techslides.com/demos/sample-videos/small.mp4 34 | self.secondUrl = @"https://files.inqscribe.com/samples/IS_Intro.mp4"; 35 | 36 | self.url = self.firstUrl; 37 | [self setupPlayer]; 38 | } 39 | 40 | 41 | - (void)itemDidFinishPlaying:(NSNotification *)notification { 42 | [self.player pause]; 43 | [self.player seekToTime:kCMTimeZero]; 44 | } 45 | 46 | 47 | - (void)setupPlayer { 48 | NSURL *audioURL = [NSURL URLWithString:self.url]; 49 | 50 | if (self.player) { 51 | [self.player stop]; 52 | [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem]; 53 | self.player = nil; 54 | } 55 | 56 | self.player = [[AVPlayer alloc] initWithURL:audioURL]; 57 | self.player.meteringEnabled = true; 58 | 59 | // Subscribe to the AVPlayerItem's DidPlayToEndTime notification. 60 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem]; 61 | 62 | 63 | [self.player averagePowerListInLinearFormWithCallbackBlock:^(NSArray *iAvgPowerList, BOOL iSuccess) { 64 | if (iAvgPowerList.count > 0) { 65 | double power = [iAvgPowerList[0] doubleValue]; 66 | if (iAvgPowerList.count > 1) { 67 | double secondPower = [iAvgPowerList[1] doubleValue]; 68 | power = (power + secondPower) / 2; 69 | } 70 | 71 | dispatch_async(dispatch_get_main_queue(), ^{ 72 | [self.progressBar setProgress:(power * 10)]; 73 | }); 74 | 75 | } 76 | }]; 77 | 78 | //********************************* 79 | //Similar to an AVAudioPlayer, you can use different methods on AVPlayer while streaming such as: 80 | //Checkout AVPlayer+ACBHelper.h for details 81 | // [self.player averagePowerForChannel:0]; 82 | // [self.player averagePowerInLinearFormForChannel:0]; 83 | // [self.player peakPowerForChannel:0]; 84 | //Additional method which fetches AVAudioPCMBuffer for the stream 85 | // [self.player audioPCMBufferFetchedWithCallbackBlock:^(AVAudioPCMBuffer *audioPCMBuffer, BOOL iSuccess) { 86 | // }]; 87 | //********************************* 88 | } 89 | 90 | 91 | - (IBAction)playTapped:(id)sender { 92 | [self.player play]; 93 | } 94 | 95 | 96 | - (IBAction)stopTapped:(id)sender { 97 | [self.player stop]; 98 | [self setupPlayer]; 99 | [self.progressBar performSelector:@selector(setProgress:) withObject:@(0.0) afterDelay:0.2f]; 100 | } 101 | 102 | 103 | - (IBAction)pauseTapped:(id)sender { 104 | [self.player pause]; 105 | } 106 | 107 | 108 | - (IBAction)segmentTapped:(id)sender { 109 | UISegmentedControl *segment = (UISegmentedControl *)sender; 110 | 111 | if (segment.selectedSegmentIndex == 0 && self.url != self.firstUrl) { 112 | self.url = self.firstUrl; 113 | [self setupPlayer]; 114 | [self.progressBar performSelector:@selector(setProgress:) withObject:@(0.0) afterDelay:0.2f]; 115 | } else if (segment.selectedSegmentIndex == 1 && self.url != self.secondUrl) { 116 | self.url = self.secondUrl; 117 | [self setupPlayer]; 118 | [self.progressBar performSelector:@selector(setProgress:) withObject:@(0.0) afterDelay:0.2f]; 119 | } 120 | } 121 | 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACBAVPlayerExtension 2 | 3 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/ACBAVPlayer.svg)](https://img.shields.io/cocoapods/v/ACBAVPlayer.svg) 4 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Platform](https://img.shields.io/cocoapods/p/ACBAVPlayer.svg?style=flat)](https://github.com/akhilcb/ACBAVPlayerExtension) 6 | [![License](https://img.shields.io/cocoapods/l/ACBAVPlayer.svg?style=flat)](http://cocoapods.org/pods/ACBAVPlayer) 7 | 8 | An extension on `AVPlayer` which converts it to have all useful features of `AVAudioPlayer` but with streaming support. Also added additional methods to support Audio visualization from `AVPlayer` streaming. This extension adds some missing features to `AVPlayer`. 9 | 10 | This projects shows a simple example on how to use it. ViewController has a `UIProgressView` which displays `averagePower` as a volume meter while streaming an audio through `AVPlayer`. This is very similar to how we would normally use `AVAudioPlayer`, but with some additional methods which makes it easy to display the `averagePower`. `audioPCMBufferFetchedWithCallbackBlock` can be used to fetch `AVAudioPCMBuffer` which can be used for Audio Visualization. Added `stop` method to stop player. 11 | 12 | 13 | ## Demo 14 | 15 | 16 |
17 | 18 |
19 |
20 | 21 |

22 | 23 | 24 | ## Setup 25 | 26 | Carthage or Cocoapods can be used to integrate this to a project. 27 | 28 | ### Carthage 29 | 30 | ``` 31 | github "akhilcb/ACBAVPlayerExtension" ~> 2.1 32 | 33 | ``` 34 | 35 | ### Cocoapods 36 | 37 | ``` 38 | pod 'ACBAVPlayer' 39 | 40 | ``` 41 | 42 | ## AVPlayer Extension Interface 43 | 44 | ``` 45 | @property (nonatomic, readonly, assign) int numberOfChannels; 46 | //stop video 47 | - (void)stop; 48 | 49 | /* metering */ 50 | @property (nonatomic, getter=isMeteringEnabled) BOOL meteringEnabled; /* turns level metering on or off. default is off. */ 51 | 52 | - (void)updateMeters; /* call to refresh meter values */ 53 | - (float)peakPowerForChannel:(NSUInteger)channelNumber; /* for peak power in decibels for a given channel. returns average power for now */ 54 | - (float)averagePowerForChannel:(NSUInteger)channelNumber; /* returns average power in decibels for a given channel */ 55 | //use this to repeatedly fetch average power list(in decibels) for all channels in iMeteringCallbackBlock. This block will be executed each time a value is fetched. Index of array is channel number 56 | - (void)averagePowerListWithCallbackBlock:(ACBAVPlayerMeteringBlock)iMeteringCallbackBlock; 57 | - (float)averagePowerInLinearFormForChannel:(NSUInteger)channelNumber; //returns in average power in linear form. Value is in between 0 to 1. 58 | //fetch average power list in linear form(values in between 0 and 1) 59 | - (void)averagePowerListInLinearFormWithCallbackBlock:(ACBAVPlayerMeteringBlock)iMeteringCallbackBlock; 60 | //fetch AVAudioPCMBuffer. it has useful methods to manipuate buffers or to display a visualizer 61 | - (void)audioPCMBufferFetchedWithCallbackBlock:(ACBAVPlayerBufferFetchedBlock)iAudioBufferFetchedBlock; 62 | - (void)replaceCurrentItemAndUpdateMeteringForPlayerItem:(AVPlayerItem *)item; //use this instead of "replaceCurrentItemWithPlayerItem" for metering to work. 63 | ``` 64 | 65 | ___Note: This is a beta version. There could be some issues(Hopefully minor). Use at your own risk.___ 66 | 67 | 68 | ## Usage 69 | 70 | ``` 71 | self.player = [[AVPlayer alloc] initWithURL:remoteURL]; 72 | self.player.meteringEnabled = true; 73 | 74 | [self.player averagePowerListInLinearFormWithCallbackBlock:^(NSArray *iAvgPowerList, BOOL iSuccess) { 75 | if (iAvgPowerList.count > 0) { 76 | double power = [iAvgPowerList[0] doubleValue]; 77 | if (iAvgPowerList.count > 1) { 78 | double secondPower = [iAvgPowerList[1] doubleValue]; 79 | power = (power + secondPower) / 2; 80 | } 81 | dispatch_async(dispatch_get_main_queue(), ^{ 82 | [self.progressBar setProgress:(power * 10)]; 83 | }); 84 | } 85 | }]; 86 | ``` 87 | 88 | ## Screenshots 89 | 90 |
91 | 92 |
93 |
94 | 95 | ## License 96 | 97 | MIT License 98 | 99 | Copyright (c) 2017, Akhil C Balan(https://github.com/akhilcb) 100 | 101 | All rights reserved. 102 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/AudioProcessing/AVPlayer+ACBHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // AVPlayer+ACBHelper.m 3 | // ACBAudioPlayer 4 | // 5 | // Created by Akhil C Balan on 3/3/16. 6 | // Copyright © 2016 Akhil. All rights reserved. 7 | // 8 | 9 | #import "AVPlayer+ACBHelper.h" 10 | #import "ACBAudioProcessHelper.h" 11 | #import 12 | 13 | 14 | NSString const *ACBAVPlayerAudioProcessHelperkey = @"ACBAVPlayerAudioProcessHelperkey"; 15 | 16 | @interface AVPlayer (ACBHelper_Private) 17 | 18 | @property (nonatomic, strong) ACBAudioProcessHelper *audioProcessHelper; 19 | 20 | @end 21 | 22 | 23 | @implementation AVPlayer (ACBHelper_Private) 24 | 25 | - (void)setAudioProcessHelper:(ACBAudioProcessHelper *)iAudioProcessHelper { 26 | objc_setAssociatedObject(self, &ACBAVPlayerAudioProcessHelperkey, iAudioProcessHelper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 27 | } 28 | 29 | 30 | - (ACBAudioProcessHelper *)audioProcessHelper { 31 | return objc_getAssociatedObject(self, &ACBAVPlayerAudioProcessHelperkey); 32 | } 33 | 34 | @end 35 | 36 | 37 | @implementation AVPlayer(ACBHelper) 38 | 39 | 40 | - (void)stop { 41 | [self seekToTime:kCMTimeZero]; 42 | [self pause]; 43 | [self replaceCurrentItemWithPlayerItem:nil]; 44 | } 45 | 46 | 47 | - (ACBAudioProcessHelper *)createAudioProcessHelper { 48 | if (!self.audioProcessHelper) { 49 | self.audioProcessHelper = [[ACBAudioProcessHelper alloc] init]; 50 | self.audioProcessHelper.player = self; 51 | } 52 | return self.audioProcessHelper; 53 | } 54 | 55 | 56 | - (int)numberOfChannels { 57 | return self.audioProcessHelper.numberOfChannels; 58 | } 59 | 60 | 61 | - (void)setMeteringEnabled:(BOOL)iMeteringEnabled { 62 | 63 | if (!self.audioProcessHelper) { 64 | [self createAudioProcessHelper]; 65 | } 66 | 67 | [self.audioProcessHelper setMeteringEnabled:iMeteringEnabled]; 68 | } 69 | 70 | 71 | - (BOOL)isMeteringEnabled { 72 | return self.audioProcessHelper.isMeteringEnabled; 73 | } 74 | 75 | 76 | - (void)replaceCurrentItemAndUpdateMeteringForPlayerItem:(nullable AVPlayerItem *)item { 77 | BOOL prevMetering = self.isMeteringEnabled; 78 | if (prevMetering) { 79 | self.meteringEnabled = false; 80 | } 81 | [self replaceCurrentItemWithPlayerItem:item]; 82 | self.meteringEnabled = prevMetering; 83 | } 84 | 85 | 86 | - (float)averagePowerForChannel:(NSUInteger)channelNumber { 87 | 88 | if (!self.audioProcessHelper) { 89 | NSLog(@"Enable Metering before calling this method"); 90 | return 0.0f; 91 | } 92 | 93 | return [self.audioProcessHelper averagePowerForChannel:channelNumber]; 94 | } 95 | 96 | 97 | - (float)averagePowerInLinearFormForChannel:(NSUInteger)channelNumber { 98 | 99 | if (!self.audioProcessHelper) { 100 | NSLog(@"Enable Metering before calling this method"); 101 | return 0.0f; 102 | } 103 | 104 | return [self.audioProcessHelper averagePowerInLinearFormForChannel:channelNumber]; 105 | } 106 | 107 | 108 | - (void)averagePowerListWithCallbackBlock:(ACBAVPlayerMeteringBlock)iMeteringCallbackBlock { 109 | 110 | if (!self.audioProcessHelper) { 111 | NSLog(@"Enable Metering before calling this method"); 112 | iMeteringCallbackBlock(nil, false); 113 | } 114 | 115 | [self.audioProcessHelper averagePowerListWithCallbackBlock:^(NSArray *iAvgPowerList, BOOL iSuccess) { 116 | iMeteringCallbackBlock(iAvgPowerList, iSuccess); 117 | }]; 118 | } 119 | 120 | 121 | - (void)averagePowerListInLinearFormWithCallbackBlock:(ACBAVPlayerMeteringBlock)iMeteringCallbackBlock { 122 | 123 | if (!self.audioProcessHelper) { 124 | NSLog(@"Enable Metering before calling this method"); 125 | iMeteringCallbackBlock(nil, false); 126 | } 127 | 128 | [self.audioProcessHelper averagePowerListInLinearFormWithCallbackBlock:^(NSArray *iAvgPowerList, BOOL iSuccess) { 129 | iMeteringCallbackBlock(iAvgPowerList, iSuccess); 130 | }]; 131 | } 132 | 133 | 134 | - (void)audioPCMBufferFetchedWithCallbackBlock:(ACBAVPlayerBufferFetchedBlock)iAudioBufferFetchedBlock { 135 | 136 | if (!self.audioProcessHelper) { 137 | NSLog(@"Enable Metering before calling this method"); 138 | iAudioBufferFetchedBlock(nil, false); 139 | } 140 | 141 | [self.audioProcessHelper audioPCMBufferFetchedWithCallbackBlock:^(AVAudioPCMBuffer *audioPCMBuffer, BOOL iSuccess) { 142 | iAudioBufferFetchedBlock(audioPCMBuffer, iSuccess); 143 | }]; 144 | } 145 | 146 | 147 | - (void)updateMeters { 148 | //do nothing 149 | } 150 | 151 | 152 | - (float)peakPowerForChannel:(NSUInteger)channelNumber { 153 | 154 | return [self averagePowerForChannel:channelNumber]; 155 | } 156 | 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/AudioProcessing/ACBAudioProcessHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACBAudioProcessHelper.m 3 | // ACBAudioPlayer 4 | // 5 | // Created by Akhil C Balan on 3/3/16. 6 | // Copyright © 2016 Akhil. All rights reserved. 7 | // 8 | 9 | #import "ACBAudioProcessHelper.h" 10 | #import "MYAudioTapProcessor.h" 11 | 12 | 13 | static void *ACBAVPlayerStatusObserverContext = &ACBAVPlayerStatusObserverContext; 14 | 15 | NSString *const kACBAVPlayerCurrentItemKey = @"currentItem"; 16 | NSString *const kACBAVPlayerStatusKey = @"status"; 17 | 18 | 19 | @interface ACBAudioProcessHelper () 20 | 21 | @property (strong, nonatomic) MYAudioTapProcessor *audioTapProcessor; 22 | @property (assign) float averagePower; 23 | @property (strong) NSArray *averagePowerList; 24 | @property (strong) NSArray *averagePowerListInLinearForm; 25 | @property (strong) AVAudioPCMBuffer *audioPCMBuffer; 26 | @property (copy) ACBAudioProcessHelperMeteringBlock meteringBlock; 27 | @property (copy) ACBAudioProcessHelperMeteringBlock meteringBlockInLinearForm; 28 | @property (copy) ACBAudioProcessHelperBufferFetchedBlock audioBufferFetchedBlock; 29 | @property (strong) AVPlayerItem *playerItem; 30 | 31 | 32 | - (void)setupMetering; 33 | 34 | @end 35 | 36 | 37 | @implementation ACBAudioProcessHelper 38 | 39 | - (void)createAudioTapProcessor { 40 | 41 | if (!self.audioTapProcessor) { 42 | AVAssetTrack *firstAudioAssetTrack; 43 | NSArray *audioTracks = [self.player.currentItem.asset tracksWithMediaType:AVMediaTypeAudio]; 44 | NSLog(@"audioTracks = %@", audioTracks); 45 | 46 | for (AVAssetTrack *assetTrack in self.player.currentItem.asset.tracks) { 47 | if ([assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) { 48 | firstAudioAssetTrack = assetTrack; 49 | break; 50 | } 51 | } 52 | 53 | if (firstAudioAssetTrack) { 54 | self.audioTapProcessor = [[MYAudioTapProcessor alloc] initWithAudioAssetTrack:firstAudioAssetTrack]; 55 | self.audioTapProcessor.delegate = self; 56 | } 57 | } 58 | } 59 | 60 | 61 | - (void)setMeteringEnabled:(BOOL)iMeteringEnabled { 62 | 63 | if (!self.isMeteringEnabled && iMeteringEnabled) { 64 | [self setupMetering]; 65 | } else if (self.isMeteringEnabled && !iMeteringEnabled) { 66 | self.player.currentItem.audioMix = nil; 67 | [self releaseAudioTapProcessor]; 68 | } 69 | 70 | _meteringEnabled = iMeteringEnabled; 71 | } 72 | 73 | - (void)releaseAudioTapProcessor { 74 | 75 | if (!self.audioTapProcessor) { 76 | return; 77 | } 78 | 79 | [self.audioTapProcessor stopProcessing]; 80 | self.audioTapProcessor = nil; 81 | } 82 | 83 | - (void)setupMetering { 84 | 85 | if (!self.player.currentItem) { 86 | //wait for currentItem using observer 87 | [self addCurrentItemObserverForPlayer]; 88 | } else { 89 | 90 | [self createAudioTapProcessor]; 91 | 92 | if (self.audioTapProcessor) { 93 | 94 | if (self.player.currentItem.status == AVPlayerStatusReadyToPlay) { 95 | [self setupAudioMix]; 96 | } else { 97 | [self addStatusObserverForPlayerItem]; 98 | } 99 | } else { 100 | NSLog(@"failed to setup processor"); 101 | } 102 | } 103 | } 104 | 105 | 106 | - (void)setupAudioMix { 107 | // Add audio mix with audio tap processor to current player item. 108 | AVAudioMix *audioMix = self.audioTapProcessor.audioMix; 109 | if (audioMix) { 110 | // Add audio mix with first audio track. 111 | self.player.currentItem.audioMix = audioMix; 112 | } 113 | } 114 | 115 | 116 | #pragma mark - Add/Remove observers 117 | 118 | - (void)addCurrentItemObserverForPlayer { 119 | [self.player addObserver:self 120 | forKeyPath:kACBAVPlayerCurrentItemKey 121 | options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew 122 | context:ACBAVPlayerStatusObserverContext]; 123 | 124 | } 125 | 126 | 127 | - (void)addStatusObserverForPlayerItem { 128 | if (self.player.currentItem) { 129 | self.playerItem = self.player.currentItem; 130 | [self.playerItem addObserver:self 131 | forKeyPath:kACBAVPlayerStatusKey 132 | options:NSKeyValueObservingOptionNew 133 | context:ACBAVPlayerStatusObserverContext]; 134 | } 135 | } 136 | 137 | 138 | - (void)removeCurrentItemObserverFromPlayer { 139 | [self.player removeObserver:self forKeyPath:kACBAVPlayerCurrentItemKey context:ACBAVPlayerStatusObserverContext]; 140 | } 141 | 142 | 143 | - (void)removeStatusObserverFromPlayerItem { 144 | 145 | if (self.playerItem) { 146 | [self.playerItem removeObserver:self forKeyPath:kACBAVPlayerStatusKey context:ACBAVPlayerStatusObserverContext]; 147 | self.playerItem = nil; 148 | } 149 | } 150 | 151 | 152 | #pragma mark - Key Value Observing 153 | 154 | - (void)observeValueForKeyPath:(NSString*)path 155 | ofObject:(id)object 156 | change:(NSDictionary*)change 157 | context:(void*)context { 158 | 159 | if (context == ACBAVPlayerStatusObserverContext) { 160 | 161 | if ([path isEqualToString:kACBAVPlayerCurrentItemKey]) { 162 | 163 | AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey]; 164 | 165 | if (newPlayerItem != (id)[NSNull null]) { 166 | [self setupMetering]; 167 | } 168 | 169 | [self removeCurrentItemObserverFromPlayer]; 170 | } else { 171 | if (self.playerItem && object == self.playerItem) { 172 | 173 | if ([path isEqualToString:kACBAVPlayerStatusKey]) { 174 | 175 | AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue]; 176 | 177 | if (status == AVPlayerStatusReadyToPlay) { 178 | 179 | [self setupAudioMix]; 180 | } 181 | 182 | [self removeStatusObserverFromPlayerItem]; 183 | } 184 | } 185 | } 186 | } else { 187 | [super observeValueForKeyPath:path ofObject:object change:change context:context]; 188 | } 189 | } 190 | 191 | 192 | - (void)averagePowerListWithCallbackBlock:(ACBAudioProcessHelperMeteringBlock)iMeteringCallbackBlock { 193 | self.meteringBlock = iMeteringCallbackBlock; 194 | } 195 | 196 | 197 | - (void)averagePowerListInLinearFormWithCallbackBlock:(ACBAudioProcessHelperMeteringBlock)iMeteringCallbackBlock { 198 | self.meteringBlockInLinearForm = iMeteringCallbackBlock; 199 | } 200 | 201 | 202 | - (void)audioPCMBufferFetchedWithCallbackBlock:(ACBAudioProcessHelperBufferFetchedBlock)iAudioBufferFetchedBlock { 203 | self.audioBufferFetchedBlock = iAudioBufferFetchedBlock; 204 | } 205 | 206 | 207 | - (int)numberOfChannels { 208 | 209 | if (self.audioTapProcessor) { 210 | if (self.audioTapProcessor.numberOfChannels == -1) { 211 | return 0; 212 | } else { 213 | return self.audioTapProcessor.numberOfChannels; 214 | } 215 | } 216 | 217 | return 1; 218 | } 219 | 220 | 221 | #pragma mark - MYAudioTabProcessorDelegate 222 | 223 | - (void)audioTabProcessor:(MYAudioTapProcessor *)audioTabProcessor hasNewLeftChannelValue:(float)leftChannelValue rightChannelValue:(float)rightChannelValue { 224 | // Update left and right channel volume unit meter. 225 | 226 | self.averagePower = (leftChannelValue + rightChannelValue) / 2.0f; 227 | } 228 | 229 | 230 | - (void)audioTabProcessor:(MYAudioTapProcessor *)audioTabProcessor hasNewChannelVolumeList:(NSArray *)iChannelVolumeList { 231 | 232 | self.averagePowerListInLinearForm = iChannelVolumeList; 233 | self.averagePowerList = [self convertAveragePowerListToDecibelFormat:iChannelVolumeList]; 234 | 235 | if (self.meteringBlock) { 236 | self.meteringBlock(self.averagePowerList, true); 237 | } 238 | 239 | if (self.meteringBlockInLinearForm) { 240 | self.meteringBlockInLinearForm(self.averagePowerListInLinearForm, true); 241 | } 242 | } 243 | 244 | 245 | - (void)audioTabProcessor:(MYAudioTapProcessor *)audioTabProcessor didReceiveBuffer:(AVAudioPCMBuffer *)buffer { 246 | self.audioPCMBuffer = buffer; 247 | 248 | if (self.audioBufferFetchedBlock) { 249 | self.audioBufferFetchedBlock(buffer, true); 250 | } 251 | } 252 | 253 | 254 | - (float)averagePowerForChannel:(NSUInteger)channelNumber { 255 | 256 | if (channelNumber < self.averagePowerList.count) { 257 | return [self.averagePowerList[channelNumber] floatValue]; 258 | } 259 | 260 | return self.averagePower; 261 | } 262 | 263 | 264 | - (float)averagePowerInLinearFormForChannel:(NSUInteger)channelNumber { 265 | 266 | if (channelNumber < self.averagePowerListInLinearForm.count) { 267 | return [self.averagePowerListInLinearForm[channelNumber] floatValue] * 2.8f; //temp fix for correcting to match with avaudiorecorder level measured 268 | } 269 | 270 | return self.averagePower * 2.8f; 271 | } 272 | 273 | 274 | - (NSArray *)convertAveragePowerListToDecibelFormat:(NSArray *)iChannelVolumeList { 275 | 276 | NSMutableArray *aDbChannelVolumeList = [NSMutableArray array]; 277 | 278 | for (NSNumber *aChannelVolume in iChannelVolumeList) { 279 | float dB = 20 * log10(aChannelVolume.floatValue); 280 | 281 | if (aChannelVolume.floatValue <= 0.0f) { 282 | dB = -160.0f;//set min to -160.0f 283 | } 284 | 285 | [aDbChannelVolumeList addObject:@(dB)]; 286 | } 287 | 288 | return aDbChannelVolumeList; 289 | } 290 | 291 | @end 292 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Resources/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 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension/Classes/AudioProcessing/MYAudioTapProcessor.m: -------------------------------------------------------------------------------- 1 | /* 2 | File: MYAudioTapProcessor.m 3 | Abstract: Audio tap processor using MTAudioProcessingTap for audio visualization and processing. 4 | Version: 1.0.1 5 | 6 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 7 | Inc. ("Apple") in consideration of your agreement to the following 8 | terms, and your use, installation, modification or redistribution of 9 | this Apple software constitutes acceptance of these terms. If you do 10 | not agree with these terms, please do not use, install, modify or 11 | redistribute this Apple software. 12 | 13 | In consideration of your agreement to abide by the following terms, and 14 | subject to these terms, Apple grants you a personal, non-exclusive 15 | license, under Apple's copyrights in this original Apple software (the 16 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 17 | Software, with or without modifications, in source and/or binary forms; 18 | provided that if you redistribute the Apple Software in its entirety and 19 | without modifications, you must retain this notice and the following 20 | text and disclaimers in all such redistributions of the Apple Software. 21 | Neither the name, trademarks, service marks or logos of Apple Inc. may 22 | be used to endorse or promote products derived from the Apple Software 23 | without specific prior written permission from Apple. Except as 24 | expressly stated in this notice, no other rights or licenses, express or 25 | implied, are granted by Apple herein, including but not limited to any 26 | patent rights that may be infringed by your derivative works or by other 27 | works in which the Apple Software may be incorporated. 28 | 29 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 30 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 31 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 32 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 33 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 34 | 35 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 36 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 39 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 40 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 41 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 42 | POSSIBILITY OF SUCH DAMAGE. 43 | 44 | Copyright (C) 2013 Apple Inc. All Rights Reserved. 45 | 46 | Modified to add additional methods 47 | */ 48 | 49 | #import "MYAudioTapProcessor.h" 50 | 51 | #import 52 | 53 | // This struct is used to pass along data between the MTAudioProcessingTap callbacks. 54 | typedef struct AVAudioTapProcessorContext { 55 | Boolean supportedTapProcessingFormat; 56 | Boolean isNonInterleaved; 57 | Float64 sampleRate; 58 | AudioUnit audioUnit; 59 | Float64 sampleCount; 60 | float leftChannelVolume; 61 | float rightChannelVolume; 62 | float *channelVolumeList; 63 | float numberOfChannels; 64 | AudioBufferList *bufferList; 65 | AVAudioFrameCount numberOfFrames; 66 | void *self; 67 | } AVAudioTapProcessorContext; 68 | 69 | // MTAudioProcessingTap callbacks. 70 | static void tap_InitCallback(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut); 71 | static void tap_FinalizeCallback(MTAudioProcessingTapRef tap); 72 | static void tap_PrepareCallback(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat); 73 | static void tap_UnprepareCallback(MTAudioProcessingTapRef tap); 74 | static void tap_ProcessCallback(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut); 75 | 76 | // Audio Unit callbacks. 77 | static OSStatus AU_RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); 78 | 79 | @interface MYAudioTapProcessor () 80 | { 81 | AVAudioMix *_audioMix; 82 | } 83 | 84 | @property (nonatomic, nullable) AVAudioFormat *format; 85 | 86 | @end 87 | 88 | 89 | @implementation MYAudioTapProcessor 90 | 91 | 92 | - (id)initWithAudioAssetTrack:(AVAssetTrack *)audioAssetTrack 93 | { 94 | NSParameterAssert(audioAssetTrack && [audioAssetTrack.mediaType isEqualToString:AVMediaTypeAudio]); 95 | 96 | self = [super init]; 97 | 98 | if (self) 99 | { 100 | _audioAssetTrack = audioAssetTrack; 101 | _centerFrequency = (4980.0f / 23980.0f); // equals 5000 Hz (assuming sample rate is 48k) 102 | _bandwidth = (500.0f / 11900.0f); // equals 600 Cents 103 | _numberOfChannels = -1; 104 | } 105 | 106 | return self; 107 | } 108 | 109 | #pragma mark - Properties 110 | 111 | - (AVAudioMix *)audioMix 112 | { 113 | if (!_audioMix) 114 | { 115 | AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix]; 116 | if (audioMix) 117 | { 118 | AVMutableAudioMixInputParameters *audioMixInputParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:self.audioAssetTrack]; 119 | if (audioMixInputParameters) 120 | { 121 | MTAudioProcessingTapCallbacks callbacks; 122 | 123 | callbacks.version = kMTAudioProcessingTapCallbacksVersion_0; 124 | callbacks.clientInfo = (__bridge void *)self; 125 | callbacks.init = tap_InitCallback; 126 | callbacks.finalize = tap_FinalizeCallback; 127 | callbacks.prepare = tap_PrepareCallback; 128 | callbacks.unprepare = tap_UnprepareCallback; 129 | callbacks.process = tap_ProcessCallback; 130 | 131 | MTAudioProcessingTapRef audioProcessingTap; 132 | if (noErr == MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks, kMTAudioProcessingTapCreationFlag_PreEffects, &audioProcessingTap)) 133 | { 134 | audioMixInputParameters.audioTapProcessor = audioProcessingTap; 135 | 136 | CFRelease(audioProcessingTap); 137 | 138 | audioMix.inputParameters = @[audioMixInputParameters]; 139 | 140 | _audioMix = audioMix; 141 | } 142 | } 143 | } 144 | } 145 | 146 | return _audioMix; 147 | } 148 | 149 | - (void)setCenterFrequency:(float)centerFrequency 150 | { 151 | if (_centerFrequency != centerFrequency) 152 | { 153 | _centerFrequency = centerFrequency; 154 | 155 | AVAudioMix *audioMix = self.audioMix; 156 | if (audioMix) 157 | { 158 | // Get pointer to Audio Unit stored in MTAudioProcessingTap context. 159 | MTAudioProcessingTapRef audioProcessingTap = ((AVMutableAudioMixInputParameters *)audioMix.inputParameters[0]).audioTapProcessor; 160 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(audioProcessingTap); 161 | AudioUnit audioUnit = context->audioUnit; 162 | if (audioUnit) 163 | { 164 | // Update center frequency of bandpass filter Audio Unit. 165 | Float32 newCenterFrequency = (20.0f + ((context->sampleRate * 0.5f) - 20.0f) * self.centerFrequency); // Global, Hz, 20->(SampleRate/2), 5000 166 | OSStatus status = AudioUnitSetParameter(audioUnit, kBandpassParam_CenterFrequency, kAudioUnitScope_Global, 0, newCenterFrequency, 0); 167 | if (noErr != status) 168 | NSLog(@"AudioUnitSetParameter(kBandpassParam_CenterFrequency): %d", (int)status); 169 | } 170 | } 171 | } 172 | } 173 | 174 | - (void)setBandwidth:(float)bandwidth 175 | { 176 | if (_bandwidth != bandwidth) 177 | { 178 | _bandwidth = bandwidth; 179 | 180 | AVAudioMix *audioMix = self.audioMix; 181 | if (audioMix) 182 | { 183 | // Get pointer to Audio Unit stored in MTAudioProcessingTap context. 184 | MTAudioProcessingTapRef audioProcessingTap = ((AVMutableAudioMixInputParameters *)audioMix.inputParameters[0]).audioTapProcessor; 185 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(audioProcessingTap); 186 | AudioUnit audioUnit = context->audioUnit; 187 | if (audioUnit) 188 | { 189 | // Update bandwidth of bandpass filter Audio Unit. 190 | Float32 newBandwidth = (100.0f + 11900.0f * self.bandwidth); 191 | OSStatus status = AudioUnitSetParameter(audioUnit, kBandpassParam_Bandwidth, kAudioUnitScope_Global, 0, newBandwidth, 0); // Global, Cents, 100->12000, 600 192 | if (noErr != status) 193 | NSLog(@"AudioUnitSetParameter(kBandpassParam_Bandwidth): %d", (int)status); 194 | } 195 | } 196 | } 197 | } 198 | 199 | #pragma mark - 200 | 201 | - (void)updateLeftChannelVolume:(float)leftChannelVolume rightChannelVolume:(float)rightChannelVolume 202 | { 203 | @autoreleasepool 204 | { 205 | dispatch_async(dispatch_get_main_queue(), ^{ 206 | // Forward left and right channel volume to delegate. 207 | if (self.delegate && [self.delegate respondsToSelector:@selector(audioTabProcessor:hasNewLeftChannelValue:rightChannelValue:)]) 208 | [self.delegate audioTabProcessor:self hasNewLeftChannelValue:leftChannelVolume rightChannelValue:rightChannelVolume]; 209 | }); 210 | } 211 | } 212 | 213 | 214 | - (void)updateChannelVolumeList:(float *)channelVolumeList withChannelVolumeListCount:(UInt32)iCount { 215 | @autoreleasepool 216 | { 217 | dispatch_async(dispatch_get_main_queue(), ^{ 218 | 219 | NSMutableArray *aVolumeList = [NSMutableArray array]; 220 | for (int i = 0; i < iCount; i++) { 221 | [aVolumeList addObject:[NSNumber numberWithFloat:channelVolumeList[i]]]; 222 | } 223 | 224 | if (self.numberOfChannels != iCount) { 225 | self.numberOfChannels = (int)iCount; 226 | } 227 | 228 | // Forward left and right channel volume to delegate. 229 | if (self.delegate && [self.delegate respondsToSelector:@selector(audioTabProcessor:hasNewChannelVolumeList:)]) { 230 | [self.delegate audioTabProcessor:self hasNewChannelVolumeList:aVolumeList]; 231 | } 232 | }); 233 | } 234 | } 235 | 236 | 237 | - (void)updateWithAudioBuffer:(NSValue *)bufferList capacity:(AVAudioFrameCount)capacity { 238 | AudioBufferList *list = bufferList.pointerValue; 239 | 240 | AudioBuffer *pBuffer = &list->mBuffers[0]; 241 | AVAudioPCMBuffer *outBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:self.format frameCapacity:capacity]; 242 | outBuffer.frameLength = pBuffer->mDataByteSize / sizeof(float); 243 | float *pData = (float *)pBuffer->mData; 244 | memcpy(outBuffer.floatChannelData[0], pData, pBuffer->mDataByteSize); 245 | if (self.numberOfChannels > 1) { 246 | memcpy(outBuffer.floatChannelData[1], pData, pBuffer->mDataByteSize); 247 | } 248 | [self.delegate audioTabProcessor:self didReceiveBuffer:outBuffer]; 249 | } 250 | 251 | - (void)stopProcessing { 252 | NSLog(@"AudioTapProcessor - stopProcessing"); 253 | AVMutableAudioMixInputParameters *params = (AVMutableAudioMixInputParameters *)_audioMix.inputParameters[0]; 254 | MTAudioProcessingTapRef audioProcessingTap = params.audioTapProcessor; 255 | 256 | if (audioProcessingTap == NULL) 257 | return; 258 | 259 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(audioProcessingTap); 260 | 261 | // nils out the pointer so that we know in tapProcessorCallbacks that self will be dealloc'ed 262 | context->self = NULL; 263 | } 264 | 265 | @end 266 | 267 | 268 | #pragma mark - MTAudioProcessingTap Callbacks 269 | 270 | static void tap_InitCallback(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut) 271 | { 272 | AVAudioTapProcessorContext *context = calloc(1, sizeof(AVAudioTapProcessorContext)); 273 | 274 | // Initialize MTAudioProcessingTap context. 275 | context->supportedTapProcessingFormat = false; 276 | context->isNonInterleaved = false; 277 | context->sampleRate = NAN; 278 | context->audioUnit = NULL; 279 | context->sampleCount = 0.0f; 280 | context->leftChannelVolume = 0.0f; 281 | context->rightChannelVolume = 0.0f; 282 | context->channelVolumeList = NULL; 283 | context->numberOfChannels = 0.0f; 284 | context->bufferList = NULL; 285 | context->numberOfFrames = 0; 286 | context->self = clientInfo; 287 | 288 | *tapStorageOut = context; 289 | } 290 | 291 | static void tap_FinalizeCallback(MTAudioProcessingTapRef tap) 292 | { 293 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(tap); 294 | 295 | // Clear MTAudioProcessingTap context. 296 | context->self = NULL; 297 | 298 | free(context); 299 | } 300 | 301 | static void tap_PrepareCallback(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat) 302 | { 303 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(tap); 304 | 305 | MYAudioTapProcessor *self = ((__bridge MYAudioTapProcessor *)context->self); 306 | self.format = [[AVAudioFormat alloc] initWithStreamDescription:processingFormat]; 307 | 308 | // Store sample rate for -setCenterFrequency:. 309 | context->sampleRate = processingFormat->mSampleRate; 310 | 311 | /* Verify processing format (this is not needed for Audio Unit, but for RMS calculation). */ 312 | 313 | context->supportedTapProcessingFormat = true; 314 | 315 | if (processingFormat->mFormatID != kAudioFormatLinearPCM) 316 | { 317 | NSLog(@"Unsupported audio format ID for audioProcessingTap. LinearPCM only."); 318 | context->supportedTapProcessingFormat = false; 319 | } 320 | 321 | if (!(processingFormat->mFormatFlags & kAudioFormatFlagIsFloat)) 322 | { 323 | NSLog(@"Unsupported audio format flag for audioProcessingTap. Float only."); 324 | context->supportedTapProcessingFormat = false; 325 | } 326 | 327 | if (processingFormat->mFormatFlags & kAudioFormatFlagIsNonInterleaved) 328 | { 329 | context->isNonInterleaved = true; 330 | } 331 | 332 | /* Create bandpass filter Audio Unit */ 333 | 334 | AudioUnit audioUnit; 335 | 336 | AudioComponentDescription audioComponentDescription; 337 | audioComponentDescription.componentType = kAudioUnitType_Effect; 338 | audioComponentDescription.componentSubType = kAudioUnitSubType_BandPassFilter; 339 | audioComponentDescription.componentManufacturer = kAudioUnitManufacturer_Apple; 340 | audioComponentDescription.componentFlags = 0; 341 | audioComponentDescription.componentFlagsMask = 0; 342 | 343 | AudioComponent audioComponent = AudioComponentFindNext(NULL, &audioComponentDescription); 344 | if (audioComponent) 345 | { 346 | if (noErr == AudioComponentInstanceNew(audioComponent, &audioUnit)) 347 | { 348 | OSStatus status = noErr; 349 | 350 | // Set audio unit input/output stream format to processing format. 351 | if (noErr == status) 352 | { 353 | status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, processingFormat, sizeof(AudioStreamBasicDescription)); 354 | } 355 | if (noErr == status) 356 | { 357 | status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, processingFormat, sizeof(AudioStreamBasicDescription)); 358 | } 359 | 360 | // Set audio unit render callback. 361 | if (noErr == status) 362 | { 363 | AURenderCallbackStruct renderCallbackStruct; 364 | renderCallbackStruct.inputProc = AU_RenderCallback; 365 | renderCallbackStruct.inputProcRefCon = (void *)tap; 366 | status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallbackStruct, sizeof(AURenderCallbackStruct)); 367 | } 368 | 369 | // Set audio unit maximum frames per slice to max frames. 370 | if (noErr == status) 371 | { 372 | UInt32 maximumFramesPerSlice = (UInt32)maxFrames; 373 | status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maximumFramesPerSlice, (UInt32)sizeof(UInt32)); 374 | } 375 | 376 | // Initialize audio unit. 377 | if (noErr == status) 378 | { 379 | status = AudioUnitInitialize(audioUnit); 380 | } 381 | 382 | if (noErr != status) 383 | { 384 | AudioComponentInstanceDispose(audioUnit); 385 | audioUnit = NULL; 386 | } 387 | 388 | context->audioUnit = audioUnit; 389 | } 390 | } 391 | } 392 | 393 | static void tap_UnprepareCallback(MTAudioProcessingTapRef tap) 394 | { 395 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(tap); 396 | 397 | /* Release bandpass filter Audio Unit */ 398 | 399 | if (context->audioUnit) 400 | { 401 | AudioUnitUninitialize(context->audioUnit); 402 | AudioComponentInstanceDispose(context->audioUnit); 403 | context->audioUnit = NULL; 404 | } 405 | 406 | if (context->channelVolumeList) { 407 | free(context->channelVolumeList); 408 | context->channelVolumeList = NULL; 409 | } 410 | } 411 | 412 | static void tap_ProcessCallback(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut) 413 | { 414 | AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(tap); 415 | 416 | OSStatus status; 417 | 418 | // Skip processing when format not supported. 419 | if (!context->supportedTapProcessingFormat) 420 | { 421 | NSLog(@"Unsupported tap processing format."); 422 | return; 423 | } 424 | 425 | MYAudioTapProcessor *self = ((__bridge MYAudioTapProcessor *)context->self); 426 | 427 | if (!self) { 428 | NSLog(@"AudioTapProcessor - processCallback CANCELLED (self is nil)"); 429 | return; 430 | } 431 | 432 | if (self.isBandpassFilterEnabled) 433 | { 434 | // Apply bandpass filter Audio Unit. 435 | AudioUnit audioUnit = context->audioUnit; 436 | if (audioUnit) 437 | { 438 | AudioTimeStamp audioTimeStamp; 439 | audioTimeStamp.mSampleTime = context->sampleCount; 440 | audioTimeStamp.mFlags = kAudioTimeStampSampleTimeValid; 441 | 442 | status = AudioUnitRender(audioUnit, 0, &audioTimeStamp, 0, (UInt32)numberFrames, bufferListInOut); 443 | if (noErr != status) 444 | { 445 | NSLog(@"AudioUnitRender(): %d", (int)status); 446 | return; 447 | } 448 | 449 | // Increment sample count for audio unit. 450 | context->sampleCount += numberFrames; 451 | 452 | // Set number of frames out. 453 | *numberFramesOut = numberFrames; 454 | } 455 | } 456 | else 457 | { 458 | // Get actual audio buffers from MTAudioProcessingTap (AudioUnitRender() will fill bufferListInOut otherwise). 459 | status = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, NULL, numberFramesOut); 460 | if (noErr != status) 461 | { 462 | NSLog(@"MTAudioProcessingTapGetSourceAudio: %d", (int)status); 463 | return; 464 | } 465 | } 466 | 467 | UInt32 aCount = bufferListInOut->mNumberBuffers; 468 | 469 | context->numberOfChannels = (float)aCount; 470 | 471 | if (aCount > 0) { 472 | if (context->channelVolumeList) { 473 | free(context->channelVolumeList); 474 | context->channelVolumeList = NULL; 475 | } 476 | context->channelVolumeList = malloc(aCount * sizeof(float)); 477 | 478 | if (context->channelVolumeList == 0) { 479 | NSLog(@"Error! could not initialize channel volume list"); 480 | } 481 | } 482 | 483 | context->bufferList = bufferListInOut; 484 | context->numberOfFrames = (AVAudioFrameCount)numberFrames; 485 | 486 | NSValue *audioBufferList = [NSValue valueWithBytes:&bufferListInOut objCType:@encode(AudioBufferList *)]; 487 | 488 | // Calculate root mean square (RMS) for left and right audio channel. 489 | for (UInt32 i = 0; i < bufferListInOut->mNumberBuffers; i++) 490 | { 491 | AudioBuffer *pBuffer = &bufferListInOut->mBuffers[i]; 492 | UInt32 cSamples = (UInt32) (numberFrames * (context->isNonInterleaved ? 1 : pBuffer->mNumberChannels)); 493 | 494 | float *pData = (float *)pBuffer->mData; 495 | 496 | float rms = 0.0f; 497 | for (UInt32 j = 0; j < cSamples; j++) 498 | { 499 | rms += pData[j] * pData[j]; 500 | } 501 | if (cSamples > 0) 502 | { 503 | rms = sqrtf(rms / cSamples); 504 | } 505 | 506 | if (0 == i) 507 | { 508 | context->leftChannelVolume = rms; 509 | } 510 | if (1 == i || (0 == i && 1 == bufferListInOut->mNumberBuffers)) 511 | { 512 | context->rightChannelVolume = rms; 513 | } 514 | 515 | context->channelVolumeList[i] = rms; 516 | } 517 | 518 | // Pass calculated left and right channel volume to VU meters. 519 | [self updateLeftChannelVolume:context->leftChannelVolume rightChannelVolume:context->rightChannelVolume]; 520 | [self updateChannelVolumeList:context->channelVolumeList withChannelVolumeListCount:aCount]; 521 | [self updateWithAudioBuffer:audioBufferList capacity:(AVAudioFrameCount)numberFrames]; 522 | } 523 | 524 | #pragma mark - Audio Unit Callbacks 525 | 526 | OSStatus AU_RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) 527 | { 528 | // Just return audio buffers from MTAudioProcessingTap. 529 | return MTAudioProcessingTapGetSourceAudio(inRefCon, inNumberFrames, ioData, NULL, NULL, NULL); 530 | } 531 | -------------------------------------------------------------------------------- /ACBAVPlayerExtension.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E912446B2002FFCE00DC8139 /* MYAudioTapProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE1721F3D7DBC005EF6B1 /* MYAudioTapProcessor.m */; }; 11 | E950DDBC200211B3002F56AE /* ACBAVPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E950DDB3200211B3002F56AE /* ACBAVPlayer.framework */; }; 12 | E950DDC3200211B3002F56AE /* ACBAVPlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E950DDC2200211B3002F56AE /* ACBAVPlayerTests.swift */; }; 13 | E950DDC5200211B3002F56AE /* ACBAVPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = E950DDB5200211B3002F56AE /* ACBAVPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | E950DDC8200211B3002F56AE /* ACBAVPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E950DDB3200211B3002F56AE /* ACBAVPlayer.framework */; }; 15 | E950DDCA200211B3002F56AE /* ACBAVPlayer.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E950DDB3200211B3002F56AE /* ACBAVPlayer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | E950DDD1200211B7002F56AE /* AVPlayer+ACBHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE1701F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.m */; }; 17 | E950DDD2200211B9002F56AE /* ACBAudioProcessHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE16E1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.m */; }; 18 | E950DDD4200211D3002F56AE /* AVPlayer+ACBHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = E99BE16F1F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | E950DDD5200211D3002F56AE /* ACBAudioProcessHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = E99BE16D1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.h */; }; 20 | E950DDD6200211D3002F56AE /* MYAudioTapProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = E99BE1711F3D7DBC005EF6B1 /* MYAudioTapProcessor.h */; }; 21 | E950DDD920021247002F56AE /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E950DDD820021247002F56AE /* AVFoundation.framework */; }; 22 | E99BE1501F3D7D09005EF6B1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE14F1F3D7D09005EF6B1 /* main.m */; }; 23 | E99BE1791F3D7DBC005EF6B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E99BE1661F3D7DBC005EF6B1 /* Assets.xcassets */; }; 24 | E99BE17A1F3D7DBC005EF6B1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E99BE1671F3D7DBC005EF6B1 /* LaunchScreen.storyboard */; }; 25 | E99BE17B1F3D7DBC005EF6B1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E99BE1691F3D7DBC005EF6B1 /* Main.storyboard */; }; 26 | E99BE17C1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE16E1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.m */; }; 27 | E99BE17D1F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE1701F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.m */; }; 28 | E99BE17E1F3D7DBC005EF6B1 /* MYAudioTapProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE1721F3D7DBC005EF6B1 /* MYAudioTapProcessor.m */; }; 29 | E99BE17F1F3D7DBC005EF6B1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE1751F3D7DBC005EF6B1 /* AppDelegate.m */; }; 30 | E99BE1801F3D7DBC005EF6B1 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E99BE1781F3D7DBC005EF6B1 /* ViewController.m */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | E950DDBD200211B3002F56AE /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = E99BE1431F3D7D09005EF6B1 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = E950DDB2200211B3002F56AE; 39 | remoteInfo = ACBAVPlayer; 40 | }; 41 | E950DDBF200211B3002F56AE /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = E99BE1431F3D7D09005EF6B1 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = E99BE14A1F3D7D09005EF6B1; 46 | remoteInfo = ACBAVPlayerExtension; 47 | }; 48 | E950DDC6200211B3002F56AE /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = E99BE1431F3D7D09005EF6B1 /* Project object */; 51 | proxyType = 1; 52 | remoteGlobalIDString = E950DDB2200211B3002F56AE; 53 | remoteInfo = ACBAVPlayer; 54 | }; 55 | /* End PBXContainerItemProxy section */ 56 | 57 | /* Begin PBXCopyFilesBuildPhase section */ 58 | E950DDC9200211B3002F56AE /* Embed Frameworks */ = { 59 | isa = PBXCopyFilesBuildPhase; 60 | buildActionMask = 2147483647; 61 | dstPath = ""; 62 | dstSubfolderSpec = 10; 63 | files = ( 64 | E950DDCA200211B3002F56AE /* ACBAVPlayer.framework in Embed Frameworks */, 65 | ); 66 | name = "Embed Frameworks"; 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXCopyFilesBuildPhase section */ 70 | 71 | /* Begin PBXFileReference section */ 72 | E950DDB3200211B3002F56AE /* ACBAVPlayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ACBAVPlayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | E950DDB5200211B3002F56AE /* ACBAVPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ACBAVPlayer.h; sourceTree = ""; }; 74 | E950DDB6200211B3002F56AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 75 | E950DDBB200211B3002F56AE /* ACBAVPlayerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ACBAVPlayerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 76 | E950DDC2200211B3002F56AE /* ACBAVPlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACBAVPlayerTests.swift; sourceTree = ""; }; 77 | E950DDC4200211B3002F56AE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78 | E950DDD820021247002F56AE /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 79 | E99BE14B1F3D7D09005EF6B1 /* ACBAVPlayerExtension.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ACBAVPlayerExtension.app; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | E99BE14F1F3D7D09005EF6B1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 81 | E99BE15F1F3D7D09005EF6B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | E99BE1661F3D7DBC005EF6B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 83 | E99BE1681F3D7DBC005EF6B1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 84 | E99BE16A1F3D7DBC005EF6B1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 85 | E99BE16D1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ACBAudioProcessHelper.h; sourceTree = ""; }; 86 | E99BE16E1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ACBAudioProcessHelper.m; sourceTree = ""; }; 87 | E99BE16F1F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AVPlayer+ACBHelper.h"; sourceTree = ""; }; 88 | E99BE1701F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AVPlayer+ACBHelper.m"; sourceTree = ""; }; 89 | E99BE1711F3D7DBC005EF6B1 /* MYAudioTapProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYAudioTapProcessor.h; sourceTree = ""; }; 90 | E99BE1721F3D7DBC005EF6B1 /* MYAudioTapProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYAudioTapProcessor.m; sourceTree = ""; }; 91 | E99BE1741F3D7DBC005EF6B1 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 92 | E99BE1751F3D7DBC005EF6B1 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 93 | E99BE1771F3D7DBC005EF6B1 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 94 | E99BE1781F3D7DBC005EF6B1 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 95 | /* End PBXFileReference section */ 96 | 97 | /* Begin PBXFrameworksBuildPhase section */ 98 | E950DDAF200211B3002F56AE /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | E950DDD920021247002F56AE /* AVFoundation.framework in Frameworks */, 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | E950DDB8200211B3002F56AE /* Frameworks */ = { 107 | isa = PBXFrameworksBuildPhase; 108 | buildActionMask = 2147483647; 109 | files = ( 110 | E950DDBC200211B3002F56AE /* ACBAVPlayer.framework in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | E99BE1481F3D7D09005EF6B1 /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | E950DDC8200211B3002F56AE /* ACBAVPlayer.framework in Frameworks */, 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | /* End PBXFrameworksBuildPhase section */ 123 | 124 | /* Begin PBXGroup section */ 125 | E950DDB4200211B3002F56AE /* ACBAVPlayer */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | E950DDB5200211B3002F56AE /* ACBAVPlayer.h */, 129 | E950DDB6200211B3002F56AE /* Info.plist */, 130 | ); 131 | path = ACBAVPlayer; 132 | sourceTree = ""; 133 | }; 134 | E950DDC1200211B3002F56AE /* ACBAVPlayerTests */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | E950DDC2200211B3002F56AE /* ACBAVPlayerTests.swift */, 138 | E950DDC4200211B3002F56AE /* Info.plist */, 139 | ); 140 | path = ACBAVPlayerTests; 141 | sourceTree = ""; 142 | }; 143 | E950DDD720021246002F56AE /* Frameworks */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | E950DDD820021247002F56AE /* AVFoundation.framework */, 147 | ); 148 | name = Frameworks; 149 | sourceTree = ""; 150 | }; 151 | E99BE1421F3D7D09005EF6B1 = { 152 | isa = PBXGroup; 153 | children = ( 154 | E99BE14D1F3D7D09005EF6B1 /* ACBAVPlayerExtension */, 155 | E950DDB4200211B3002F56AE /* ACBAVPlayer */, 156 | E950DDC1200211B3002F56AE /* ACBAVPlayerTests */, 157 | E99BE14C1F3D7D09005EF6B1 /* Products */, 158 | E950DDD720021246002F56AE /* Frameworks */, 159 | ); 160 | sourceTree = ""; 161 | }; 162 | E99BE14C1F3D7D09005EF6B1 /* Products */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | E99BE14B1F3D7D09005EF6B1 /* ACBAVPlayerExtension.app */, 166 | E950DDB3200211B3002F56AE /* ACBAVPlayer.framework */, 167 | E950DDBB200211B3002F56AE /* ACBAVPlayerTests.xctest */, 168 | ); 169 | name = Products; 170 | sourceTree = ""; 171 | }; 172 | E99BE14D1F3D7D09005EF6B1 /* ACBAVPlayerExtension */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | E99BE16B1F3D7DBC005EF6B1 /* Classes */, 176 | E99BE1651F3D7DBC005EF6B1 /* Resources */, 177 | E99BE14E1F3D7D09005EF6B1 /* Supporting Files */, 178 | ); 179 | path = ACBAVPlayerExtension; 180 | sourceTree = ""; 181 | }; 182 | E99BE14E1F3D7D09005EF6B1 /* Supporting Files */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | E99BE15F1F3D7D09005EF6B1 /* Info.plist */, 186 | E99BE14F1F3D7D09005EF6B1 /* main.m */, 187 | ); 188 | name = "Supporting Files"; 189 | sourceTree = ""; 190 | }; 191 | E99BE1651F3D7DBC005EF6B1 /* Resources */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | E99BE1661F3D7DBC005EF6B1 /* Assets.xcassets */, 195 | E99BE1671F3D7DBC005EF6B1 /* LaunchScreen.storyboard */, 196 | E99BE1691F3D7DBC005EF6B1 /* Main.storyboard */, 197 | ); 198 | path = Resources; 199 | sourceTree = ""; 200 | }; 201 | E99BE16B1F3D7DBC005EF6B1 /* Classes */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | E99BE1731F3D7DBC005EF6B1 /* General */, 205 | E99BE16C1F3D7DBC005EF6B1 /* AudioProcessing */, 206 | E99BE1761F3D7DBC005EF6B1 /* ViewControllers */, 207 | ); 208 | path = Classes; 209 | sourceTree = ""; 210 | }; 211 | E99BE16C1F3D7DBC005EF6B1 /* AudioProcessing */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | E99BE16F1F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.h */, 215 | E99BE1701F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.m */, 216 | E99BE16D1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.h */, 217 | E99BE16E1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.m */, 218 | E99BE1711F3D7DBC005EF6B1 /* MYAudioTapProcessor.h */, 219 | E99BE1721F3D7DBC005EF6B1 /* MYAudioTapProcessor.m */, 220 | ); 221 | path = AudioProcessing; 222 | sourceTree = ""; 223 | }; 224 | E99BE1731F3D7DBC005EF6B1 /* General */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | E99BE1741F3D7DBC005EF6B1 /* AppDelegate.h */, 228 | E99BE1751F3D7DBC005EF6B1 /* AppDelegate.m */, 229 | ); 230 | path = General; 231 | sourceTree = ""; 232 | }; 233 | E99BE1761F3D7DBC005EF6B1 /* ViewControllers */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | E99BE1771F3D7DBC005EF6B1 /* ViewController.h */, 237 | E99BE1781F3D7DBC005EF6B1 /* ViewController.m */, 238 | ); 239 | path = ViewControllers; 240 | sourceTree = ""; 241 | }; 242 | /* End PBXGroup section */ 243 | 244 | /* Begin PBXHeadersBuildPhase section */ 245 | E950DDB0200211B3002F56AE /* Headers */ = { 246 | isa = PBXHeadersBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | E950DDC5200211B3002F56AE /* ACBAVPlayer.h in Headers */, 250 | E950DDD4200211D3002F56AE /* AVPlayer+ACBHelper.h in Headers */, 251 | E950DDD5200211D3002F56AE /* ACBAudioProcessHelper.h in Headers */, 252 | E950DDD6200211D3002F56AE /* MYAudioTapProcessor.h in Headers */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | /* End PBXHeadersBuildPhase section */ 257 | 258 | /* Begin PBXNativeTarget section */ 259 | E950DDB2200211B3002F56AE /* ACBAVPlayer */ = { 260 | isa = PBXNativeTarget; 261 | buildConfigurationList = E950DDCF200211B3002F56AE /* Build configuration list for PBXNativeTarget "ACBAVPlayer" */; 262 | buildPhases = ( 263 | E950DDAE200211B3002F56AE /* Sources */, 264 | E950DDAF200211B3002F56AE /* Frameworks */, 265 | E950DDB0200211B3002F56AE /* Headers */, 266 | E950DDB1200211B3002F56AE /* Resources */, 267 | ); 268 | buildRules = ( 269 | ); 270 | dependencies = ( 271 | ); 272 | name = ACBAVPlayer; 273 | productName = ACBAVPlayer; 274 | productReference = E950DDB3200211B3002F56AE /* ACBAVPlayer.framework */; 275 | productType = "com.apple.product-type.framework"; 276 | }; 277 | E950DDBA200211B3002F56AE /* ACBAVPlayerTests */ = { 278 | isa = PBXNativeTarget; 279 | buildConfigurationList = E950DDD0200211B3002F56AE /* Build configuration list for PBXNativeTarget "ACBAVPlayerTests" */; 280 | buildPhases = ( 281 | E950DDB7200211B3002F56AE /* Sources */, 282 | E950DDB8200211B3002F56AE /* Frameworks */, 283 | E950DDB9200211B3002F56AE /* Resources */, 284 | ); 285 | buildRules = ( 286 | ); 287 | dependencies = ( 288 | E950DDBE200211B3002F56AE /* PBXTargetDependency */, 289 | E950DDC0200211B3002F56AE /* PBXTargetDependency */, 290 | ); 291 | name = ACBAVPlayerTests; 292 | productName = ACBAVPlayerTests; 293 | productReference = E950DDBB200211B3002F56AE /* ACBAVPlayerTests.xctest */; 294 | productType = "com.apple.product-type.bundle.unit-test"; 295 | }; 296 | E99BE14A1F3D7D09005EF6B1 /* ACBAVPlayerExtension */ = { 297 | isa = PBXNativeTarget; 298 | buildConfigurationList = E99BE1621F3D7D09005EF6B1 /* Build configuration list for PBXNativeTarget "ACBAVPlayerExtension" */; 299 | buildPhases = ( 300 | E99BE1471F3D7D09005EF6B1 /* Sources */, 301 | E99BE1481F3D7D09005EF6B1 /* Frameworks */, 302 | E99BE1491F3D7D09005EF6B1 /* Resources */, 303 | E950DDC9200211B3002F56AE /* Embed Frameworks */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | E950DDC7200211B3002F56AE /* PBXTargetDependency */, 309 | ); 310 | name = ACBAVPlayerExtension; 311 | productName = ACBAVPlayerExtension; 312 | productReference = E99BE14B1F3D7D09005EF6B1 /* ACBAVPlayerExtension.app */; 313 | productType = "com.apple.product-type.application"; 314 | }; 315 | /* End PBXNativeTarget section */ 316 | 317 | /* Begin PBXProject section */ 318 | E99BE1431F3D7D09005EF6B1 /* Project object */ = { 319 | isa = PBXProject; 320 | attributes = { 321 | BuildIndependentTargetsInParallel = YES; 322 | LastSwiftUpdateCheck = 0920; 323 | LastUpgradeCheck = 1540; 324 | ORGANIZATIONNAME = akhil; 325 | TargetAttributes = { 326 | E950DDB2200211B3002F56AE = { 327 | CreatedOnToolsVersion = 9.2; 328 | ProvisioningStyle = Automatic; 329 | }; 330 | E950DDBA200211B3002F56AE = { 331 | CreatedOnToolsVersion = 9.2; 332 | LastSwiftMigration = 1540; 333 | ProvisioningStyle = Automatic; 334 | TestTargetID = E99BE14A1F3D7D09005EF6B1; 335 | }; 336 | E99BE14A1F3D7D09005EF6B1 = { 337 | CreatedOnToolsVersion = 8.3.3; 338 | ProvisioningStyle = Automatic; 339 | }; 340 | }; 341 | }; 342 | buildConfigurationList = E99BE1461F3D7D09005EF6B1 /* Build configuration list for PBXProject "ACBAVPlayerExtension" */; 343 | compatibilityVersion = "Xcode 3.2"; 344 | developmentRegion = en; 345 | hasScannedForEncodings = 0; 346 | knownRegions = ( 347 | en, 348 | Base, 349 | ); 350 | mainGroup = E99BE1421F3D7D09005EF6B1; 351 | productRefGroup = E99BE14C1F3D7D09005EF6B1 /* Products */; 352 | projectDirPath = ""; 353 | projectRoot = ""; 354 | targets = ( 355 | E99BE14A1F3D7D09005EF6B1 /* ACBAVPlayerExtension */, 356 | E950DDB2200211B3002F56AE /* ACBAVPlayer */, 357 | E950DDBA200211B3002F56AE /* ACBAVPlayerTests */, 358 | ); 359 | }; 360 | /* End PBXProject section */ 361 | 362 | /* Begin PBXResourcesBuildPhase section */ 363 | E950DDB1200211B3002F56AE /* Resources */ = { 364 | isa = PBXResourcesBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | ); 368 | runOnlyForDeploymentPostprocessing = 0; 369 | }; 370 | E950DDB9200211B3002F56AE /* Resources */ = { 371 | isa = PBXResourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | E99BE1491F3D7D09005EF6B1 /* Resources */ = { 378 | isa = PBXResourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | E99BE1791F3D7DBC005EF6B1 /* Assets.xcassets in Resources */, 382 | E99BE17B1F3D7DBC005EF6B1 /* Main.storyboard in Resources */, 383 | E99BE17A1F3D7DBC005EF6B1 /* LaunchScreen.storyboard in Resources */, 384 | ); 385 | runOnlyForDeploymentPostprocessing = 0; 386 | }; 387 | /* End PBXResourcesBuildPhase section */ 388 | 389 | /* Begin PBXSourcesBuildPhase section */ 390 | E950DDAE200211B3002F56AE /* Sources */ = { 391 | isa = PBXSourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | E912446B2002FFCE00DC8139 /* MYAudioTapProcessor.m in Sources */, 395 | E950DDD1200211B7002F56AE /* AVPlayer+ACBHelper.m in Sources */, 396 | E950DDD2200211B9002F56AE /* ACBAudioProcessHelper.m in Sources */, 397 | ); 398 | runOnlyForDeploymentPostprocessing = 0; 399 | }; 400 | E950DDB7200211B3002F56AE /* Sources */ = { 401 | isa = PBXSourcesBuildPhase; 402 | buildActionMask = 2147483647; 403 | files = ( 404 | E950DDC3200211B3002F56AE /* ACBAVPlayerTests.swift in Sources */, 405 | ); 406 | runOnlyForDeploymentPostprocessing = 0; 407 | }; 408 | E99BE1471F3D7D09005EF6B1 /* Sources */ = { 409 | isa = PBXSourcesBuildPhase; 410 | buildActionMask = 2147483647; 411 | files = ( 412 | E99BE17E1F3D7DBC005EF6B1 /* MYAudioTapProcessor.m in Sources */, 413 | E99BE1801F3D7DBC005EF6B1 /* ViewController.m in Sources */, 414 | E99BE17C1F3D7DBC005EF6B1 /* ACBAudioProcessHelper.m in Sources */, 415 | E99BE1501F3D7D09005EF6B1 /* main.m in Sources */, 416 | E99BE17D1F3D7DBC005EF6B1 /* AVPlayer+ACBHelper.m in Sources */, 417 | E99BE17F1F3D7DBC005EF6B1 /* AppDelegate.m in Sources */, 418 | ); 419 | runOnlyForDeploymentPostprocessing = 0; 420 | }; 421 | /* End PBXSourcesBuildPhase section */ 422 | 423 | /* Begin PBXTargetDependency section */ 424 | E950DDBE200211B3002F56AE /* PBXTargetDependency */ = { 425 | isa = PBXTargetDependency; 426 | target = E950DDB2200211B3002F56AE /* ACBAVPlayer */; 427 | targetProxy = E950DDBD200211B3002F56AE /* PBXContainerItemProxy */; 428 | }; 429 | E950DDC0200211B3002F56AE /* PBXTargetDependency */ = { 430 | isa = PBXTargetDependency; 431 | target = E99BE14A1F3D7D09005EF6B1 /* ACBAVPlayerExtension */; 432 | targetProxy = E950DDBF200211B3002F56AE /* PBXContainerItemProxy */; 433 | }; 434 | E950DDC7200211B3002F56AE /* PBXTargetDependency */ = { 435 | isa = PBXTargetDependency; 436 | target = E950DDB2200211B3002F56AE /* ACBAVPlayer */; 437 | targetProxy = E950DDC6200211B3002F56AE /* PBXContainerItemProxy */; 438 | }; 439 | /* End PBXTargetDependency section */ 440 | 441 | /* Begin PBXVariantGroup section */ 442 | E99BE1671F3D7DBC005EF6B1 /* LaunchScreen.storyboard */ = { 443 | isa = PBXVariantGroup; 444 | children = ( 445 | E99BE1681F3D7DBC005EF6B1 /* Base */, 446 | ); 447 | name = LaunchScreen.storyboard; 448 | sourceTree = ""; 449 | }; 450 | E99BE1691F3D7DBC005EF6B1 /* Main.storyboard */ = { 451 | isa = PBXVariantGroup; 452 | children = ( 453 | E99BE16A1F3D7DBC005EF6B1 /* Base */, 454 | ); 455 | name = Main.storyboard; 456 | sourceTree = ""; 457 | }; 458 | /* End PBXVariantGroup section */ 459 | 460 | /* Begin XCBuildConfiguration section */ 461 | E950DDCB200211B3002F56AE /* Debug */ = { 462 | isa = XCBuildConfiguration; 463 | buildSettings = { 464 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 465 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 466 | CLANG_WARN_COMMA = YES; 467 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 468 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 469 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 470 | CLANG_WARN_STRICT_PROTOTYPES = YES; 471 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 472 | CODE_SIGN_IDENTITY = ""; 473 | CODE_SIGN_STYLE = Automatic; 474 | CURRENT_PROJECT_VERSION = 1; 475 | DEFINES_MODULE = YES; 476 | DEVELOPMENT_TEAM = ""; 477 | DYLIB_COMPATIBILITY_VERSION = 1; 478 | DYLIB_CURRENT_VERSION = 1; 479 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 480 | ENABLE_MODULE_VERIFIER = YES; 481 | GCC_C_LANGUAGE_STANDARD = gnu11; 482 | INFOPLIST_FILE = ACBAVPlayer/Info.plist; 483 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 484 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 485 | LD_RUNPATH_SEARCH_PATHS = ( 486 | "$(inherited)", 487 | "@executable_path/Frameworks", 488 | "@loader_path/Frameworks", 489 | ); 490 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; 491 | OTHER_LDFLAGS = "-ObjC"; 492 | PRODUCT_BUNDLE_IDENTIFIER = com.akhil.ACBAVPlayer; 493 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 494 | SKIP_INSTALL = YES; 495 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 496 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 497 | SWIFT_VERSION = 4.0; 498 | TARGETED_DEVICE_FAMILY = "1,2"; 499 | VERSIONING_SYSTEM = "apple-generic"; 500 | VERSION_INFO_PREFIX = ""; 501 | }; 502 | name = Debug; 503 | }; 504 | E950DDCC200211B3002F56AE /* Release */ = { 505 | isa = XCBuildConfiguration; 506 | buildSettings = { 507 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 508 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 509 | CLANG_WARN_COMMA = YES; 510 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 511 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 512 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 513 | CLANG_WARN_STRICT_PROTOTYPES = YES; 514 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 515 | CODE_SIGN_IDENTITY = ""; 516 | CODE_SIGN_STYLE = Automatic; 517 | CURRENT_PROJECT_VERSION = 1; 518 | DEFINES_MODULE = YES; 519 | DEVELOPMENT_TEAM = ""; 520 | DYLIB_COMPATIBILITY_VERSION = 1; 521 | DYLIB_CURRENT_VERSION = 1; 522 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 523 | ENABLE_MODULE_VERIFIER = YES; 524 | GCC_C_LANGUAGE_STANDARD = gnu11; 525 | INFOPLIST_FILE = ACBAVPlayer/Info.plist; 526 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 527 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 528 | LD_RUNPATH_SEARCH_PATHS = ( 529 | "$(inherited)", 530 | "@executable_path/Frameworks", 531 | "@loader_path/Frameworks", 532 | ); 533 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; 534 | OTHER_LDFLAGS = "-ObjC"; 535 | PRODUCT_BUNDLE_IDENTIFIER = com.akhil.ACBAVPlayer; 536 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 537 | SKIP_INSTALL = YES; 538 | SWIFT_COMPILATION_MODE = wholemodule; 539 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 540 | SWIFT_VERSION = 4.0; 541 | TARGETED_DEVICE_FAMILY = "1,2"; 542 | VERSIONING_SYSTEM = "apple-generic"; 543 | VERSION_INFO_PREFIX = ""; 544 | }; 545 | name = Release; 546 | }; 547 | E950DDCD200211B3002F56AE /* Debug */ = { 548 | isa = XCBuildConfiguration; 549 | buildSettings = { 550 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 551 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 552 | CLANG_WARN_COMMA = YES; 553 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 554 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 555 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 556 | CLANG_WARN_STRICT_PROTOTYPES = YES; 557 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 558 | CODE_SIGN_IDENTITY = "iPhone Developer"; 559 | CODE_SIGN_STYLE = Automatic; 560 | GCC_C_LANGUAGE_STANDARD = gnu11; 561 | INFOPLIST_FILE = ACBAVPlayerTests/Info.plist; 562 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 563 | LD_RUNPATH_SEARCH_PATHS = ( 564 | "$(inherited)", 565 | "@executable_path/Frameworks", 566 | "@loader_path/Frameworks", 567 | ); 568 | PRODUCT_BUNDLE_IDENTIFIER = com.akhil.ACBAVPlayerTests; 569 | PRODUCT_NAME = "$(TARGET_NAME)"; 570 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 571 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 572 | SWIFT_VERSION = 5.0; 573 | TARGETED_DEVICE_FAMILY = "1,2"; 574 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ACBAVPlayerExtension.app/ACBAVPlayerExtension"; 575 | }; 576 | name = Debug; 577 | }; 578 | E950DDCE200211B3002F56AE /* Release */ = { 579 | isa = XCBuildConfiguration; 580 | buildSettings = { 581 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 582 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 583 | CLANG_WARN_COMMA = YES; 584 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 585 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 586 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 587 | CLANG_WARN_STRICT_PROTOTYPES = YES; 588 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 589 | CODE_SIGN_IDENTITY = "iPhone Developer"; 590 | CODE_SIGN_STYLE = Automatic; 591 | GCC_C_LANGUAGE_STANDARD = gnu11; 592 | INFOPLIST_FILE = ACBAVPlayerTests/Info.plist; 593 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 594 | LD_RUNPATH_SEARCH_PATHS = ( 595 | "$(inherited)", 596 | "@executable_path/Frameworks", 597 | "@loader_path/Frameworks", 598 | ); 599 | PRODUCT_BUNDLE_IDENTIFIER = com.akhil.ACBAVPlayerTests; 600 | PRODUCT_NAME = "$(TARGET_NAME)"; 601 | SWIFT_COMPILATION_MODE = wholemodule; 602 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 603 | SWIFT_VERSION = 5.0; 604 | TARGETED_DEVICE_FAMILY = "1,2"; 605 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ACBAVPlayerExtension.app/ACBAVPlayerExtension"; 606 | }; 607 | name = Release; 608 | }; 609 | E99BE1601F3D7D09005EF6B1 /* Debug */ = { 610 | isa = XCBuildConfiguration; 611 | buildSettings = { 612 | ALWAYS_SEARCH_USER_PATHS = NO; 613 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 614 | CLANG_ANALYZER_NONNULL = YES; 615 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 616 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 617 | CLANG_CXX_LIBRARY = "libc++"; 618 | CLANG_ENABLE_MODULES = YES; 619 | CLANG_ENABLE_OBJC_ARC = YES; 620 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 621 | CLANG_WARN_BOOL_CONVERSION = YES; 622 | CLANG_WARN_COMMA = YES; 623 | CLANG_WARN_CONSTANT_CONVERSION = YES; 624 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 625 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 626 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 627 | CLANG_WARN_EMPTY_BODY = YES; 628 | CLANG_WARN_ENUM_CONVERSION = YES; 629 | CLANG_WARN_INFINITE_RECURSION = YES; 630 | CLANG_WARN_INT_CONVERSION = YES; 631 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 632 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 633 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 634 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 635 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 636 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 637 | CLANG_WARN_STRICT_PROTOTYPES = YES; 638 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 639 | CLANG_WARN_UNREACHABLE_CODE = YES; 640 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 641 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 642 | COPY_PHASE_STRIP = NO; 643 | DEBUG_INFORMATION_FORMAT = dwarf; 644 | ENABLE_STRICT_OBJC_MSGSEND = YES; 645 | ENABLE_TESTABILITY = YES; 646 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 647 | GCC_C_LANGUAGE_STANDARD = gnu99; 648 | GCC_DYNAMIC_NO_PIC = NO; 649 | GCC_NO_COMMON_BLOCKS = YES; 650 | GCC_OPTIMIZATION_LEVEL = 0; 651 | GCC_PREPROCESSOR_DEFINITIONS = ( 652 | "DEBUG=1", 653 | "$(inherited)", 654 | ); 655 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 656 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 657 | GCC_WARN_UNDECLARED_SELECTOR = YES; 658 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 659 | GCC_WARN_UNUSED_FUNCTION = YES; 660 | GCC_WARN_UNUSED_VARIABLE = YES; 661 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 662 | MTL_ENABLE_DEBUG_INFO = YES; 663 | ONLY_ACTIVE_ARCH = YES; 664 | SDKROOT = iphoneos; 665 | TARGETED_DEVICE_FAMILY = "1,2"; 666 | }; 667 | name = Debug; 668 | }; 669 | E99BE1611F3D7D09005EF6B1 /* Release */ = { 670 | isa = XCBuildConfiguration; 671 | buildSettings = { 672 | ALWAYS_SEARCH_USER_PATHS = NO; 673 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 674 | CLANG_ANALYZER_NONNULL = YES; 675 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 676 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 677 | CLANG_CXX_LIBRARY = "libc++"; 678 | CLANG_ENABLE_MODULES = YES; 679 | CLANG_ENABLE_OBJC_ARC = YES; 680 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 681 | CLANG_WARN_BOOL_CONVERSION = YES; 682 | CLANG_WARN_COMMA = YES; 683 | CLANG_WARN_CONSTANT_CONVERSION = YES; 684 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 685 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 686 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 687 | CLANG_WARN_EMPTY_BODY = YES; 688 | CLANG_WARN_ENUM_CONVERSION = YES; 689 | CLANG_WARN_INFINITE_RECURSION = YES; 690 | CLANG_WARN_INT_CONVERSION = YES; 691 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 692 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 693 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 694 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 695 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 696 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 697 | CLANG_WARN_STRICT_PROTOTYPES = YES; 698 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 699 | CLANG_WARN_UNREACHABLE_CODE = YES; 700 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 701 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 702 | COPY_PHASE_STRIP = NO; 703 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 704 | ENABLE_NS_ASSERTIONS = NO; 705 | ENABLE_STRICT_OBJC_MSGSEND = YES; 706 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 707 | GCC_C_LANGUAGE_STANDARD = gnu99; 708 | GCC_NO_COMMON_BLOCKS = YES; 709 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 710 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 711 | GCC_WARN_UNDECLARED_SELECTOR = YES; 712 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 713 | GCC_WARN_UNUSED_FUNCTION = YES; 714 | GCC_WARN_UNUSED_VARIABLE = YES; 715 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 716 | MTL_ENABLE_DEBUG_INFO = NO; 717 | SDKROOT = iphoneos; 718 | SWIFT_COMPILATION_MODE = wholemodule; 719 | TARGETED_DEVICE_FAMILY = "1,2"; 720 | VALIDATE_PRODUCT = YES; 721 | }; 722 | name = Release; 723 | }; 724 | E99BE1631F3D7D09005EF6B1 /* Debug */ = { 725 | isa = XCBuildConfiguration; 726 | buildSettings = { 727 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 728 | CODE_SIGN_IDENTITY = "iPhone Developer"; 729 | DEVELOPMENT_TEAM = ""; 730 | INFOPLIST_FILE = ACBAVPlayerExtension/Info.plist; 731 | LD_RUNPATH_SEARCH_PATHS = ( 732 | "$(inherited)", 733 | "@executable_path/Frameworks", 734 | ); 735 | PRODUCT_BUNDLE_IDENTIFIER = com.akhil.ACBAVPlayerExtension; 736 | PRODUCT_NAME = "$(TARGET_NAME)"; 737 | }; 738 | name = Debug; 739 | }; 740 | E99BE1641F3D7D09005EF6B1 /* Release */ = { 741 | isa = XCBuildConfiguration; 742 | buildSettings = { 743 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 744 | CODE_SIGN_IDENTITY = "iPhone Developer"; 745 | DEVELOPMENT_TEAM = ""; 746 | INFOPLIST_FILE = ACBAVPlayerExtension/Info.plist; 747 | LD_RUNPATH_SEARCH_PATHS = ( 748 | "$(inherited)", 749 | "@executable_path/Frameworks", 750 | ); 751 | PRODUCT_BUNDLE_IDENTIFIER = com.akhil.ACBAVPlayerExtension; 752 | PRODUCT_NAME = "$(TARGET_NAME)"; 753 | }; 754 | name = Release; 755 | }; 756 | /* End XCBuildConfiguration section */ 757 | 758 | /* Begin XCConfigurationList section */ 759 | E950DDCF200211B3002F56AE /* Build configuration list for PBXNativeTarget "ACBAVPlayer" */ = { 760 | isa = XCConfigurationList; 761 | buildConfigurations = ( 762 | E950DDCB200211B3002F56AE /* Debug */, 763 | E950DDCC200211B3002F56AE /* Release */, 764 | ); 765 | defaultConfigurationIsVisible = 0; 766 | defaultConfigurationName = Release; 767 | }; 768 | E950DDD0200211B3002F56AE /* Build configuration list for PBXNativeTarget "ACBAVPlayerTests" */ = { 769 | isa = XCConfigurationList; 770 | buildConfigurations = ( 771 | E950DDCD200211B3002F56AE /* Debug */, 772 | E950DDCE200211B3002F56AE /* Release */, 773 | ); 774 | defaultConfigurationIsVisible = 0; 775 | defaultConfigurationName = Release; 776 | }; 777 | E99BE1461F3D7D09005EF6B1 /* Build configuration list for PBXProject "ACBAVPlayerExtension" */ = { 778 | isa = XCConfigurationList; 779 | buildConfigurations = ( 780 | E99BE1601F3D7D09005EF6B1 /* Debug */, 781 | E99BE1611F3D7D09005EF6B1 /* Release */, 782 | ); 783 | defaultConfigurationIsVisible = 0; 784 | defaultConfigurationName = Release; 785 | }; 786 | E99BE1621F3D7D09005EF6B1 /* Build configuration list for PBXNativeTarget "ACBAVPlayerExtension" */ = { 787 | isa = XCConfigurationList; 788 | buildConfigurations = ( 789 | E99BE1631F3D7D09005EF6B1 /* Debug */, 790 | E99BE1641F3D7D09005EF6B1 /* Release */, 791 | ); 792 | defaultConfigurationIsVisible = 0; 793 | defaultConfigurationName = Release; 794 | }; 795 | /* End XCConfigurationList section */ 796 | }; 797 | rootObject = E99BE1431F3D7D09005EF6B1 /* Project object */; 798 | } 799 | --------------------------------------------------------------------------------