Added the ability to dynamically remove or add EQ unit to save battery when EQ unit is not needed
This commit is contained in:
parent
dee6322751
commit
60d48a0682
|
|
@ -418,6 +418,7 @@
|
|||
ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch";
|
||||
INFOPLIST_FILE = "ExampleApp/ExampleApp-Info.plist";
|
||||
|
|
|
|||
|
|
@ -27,19 +27,21 @@
|
|||
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
|
||||
[[AVAudioSession sharedInstance] setActive:YES error:&error];
|
||||
|
||||
|
||||
Float32 bufferLength = 0.1;
|
||||
AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(bufferLength), &bufferLength);
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = YES, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} }];
|
||||
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .flushQueueOnSeek = YES, .enableVolumeMixer = NO, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} }];
|
||||
audioPlayer.meteringEnabled = YES;
|
||||
audioPlayer.volume = 1;
|
||||
|
||||
AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds];
|
||||
AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds andAudioPlayer:audioPlayer];
|
||||
|
||||
audioPlayerView.delegate = self;
|
||||
audioPlayerView.audioPlayer = audioPlayer;
|
||||
|
||||
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
|
||||
[self becomeFirstResponder];
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
UILabel* label;
|
||||
UILabel* statusLabel;
|
||||
UISlider* slider;
|
||||
UISwitch* enableEqSwitch;
|
||||
UISwitch* repeatSwitch;
|
||||
UIButton* muteButton;
|
||||
UIButton* playButton;
|
||||
|
|
@ -65,4 +66,6 @@
|
|||
@property (readwrite, retain) STKAudioPlayer* audioPlayer;
|
||||
@property (readwrite, unsafe_unretained) id<AudioPlayerViewDelegate> delegate;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame andAudioPlayer:(STKAudioPlayer*)audioPlayer;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -47,12 +47,14 @@
|
|||
@implementation AudioPlayerView
|
||||
@synthesize audioPlayer, delegate;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
- (id)initWithFrame:(CGRect)frame andAudioPlayer:(STKAudioPlayer*)audioPlayerIn
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
self.audioPlayer = audioPlayerIn;
|
||||
|
||||
CGSize size = CGSizeMake(220, 50);
|
||||
|
||||
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
|
|
@ -97,7 +99,12 @@
|
|||
|
||||
size = CGSizeMake(80, 50);
|
||||
|
||||
repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake((320 - size.width) / 2, frame.size.height * 0.15 + 180, size.width, size.height)];
|
||||
repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(30, frame.size.height * 0.15 + 180, size.width, size.height)];
|
||||
|
||||
enableEqSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(320 - size.width - 30, frame.size.height * 0.15 + 180, size.width, size.height)];
|
||||
enableEqSwitch.on = audioPlayer.equalizerEnabled;
|
||||
|
||||
[enableEqSwitch addTarget:self action:@selector(onEnableEqSwitch) forControlEvents:UIControlEventAllTouchEvents];
|
||||
|
||||
label = [[UILabel alloc] initWithFrame:CGRectMake(0, slider.frame.origin.y + slider.frame.size.height + 10, frame.size.width, 25)];
|
||||
|
||||
|
|
@ -123,6 +130,7 @@
|
|||
[self addSubview:stopButton];
|
||||
[self addSubview:meter];
|
||||
[self addSubview:muteButton];
|
||||
[self addSubview:enableEqSwitch];
|
||||
|
||||
[self setupTimer];
|
||||
[self updateControls];
|
||||
|
|
@ -131,6 +139,11 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
-(void) onEnableEqSwitch
|
||||
{
|
||||
audioPlayer.equalizerEnabled = self->enableEqSwitch.on;
|
||||
}
|
||||
|
||||
-(void) sliderChanged
|
||||
{
|
||||
if (!audioPlayer)
|
||||
|
|
|
|||
|
|
@ -40,14 +40,22 @@
|
|||
[[self.window contentView] addSubview:playFromHTTPButton];
|
||||
[[self.window contentView] addSubview:meter];
|
||||
|
||||
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .enableVolumeMixer = NO, .equalizerBandFrequencies = {0, 50, 100, 200, 400, 800, 1600, 2600, 16000} } ];
|
||||
audioPlayer = [[STKAudioPlayer alloc] initWithOptions:(STKAudioPlayerOptions){ .enableVolumeMixer = NO, .equalizerBandFrequencies = {50, 100, 200, 400, 800, 1600, 2600, 16000} } ];
|
||||
audioPlayer.delegate = self;
|
||||
audioPlayer.meteringEnabled = YES;
|
||||
audioPlayer.volume = 0.1;
|
||||
|
||||
[self performSelector:@selector(test) withObject:nil afterDelay:4];
|
||||
[self performSelector:@selector(test) withObject:nil afterDelay:8];
|
||||
|
||||
[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(tick:) userInfo:nil repeats:YES];
|
||||
}
|
||||
|
||||
-(void) test
|
||||
{
|
||||
audioPlayer.equalizerEnabled = !audioPlayer.equalizerEnabled;
|
||||
}
|
||||
|
||||
-(void) playFromHTTP
|
||||
{
|
||||
[audioPlayer play:@"http://fs.bloom.fm/oss/audiosamples/sample.mp3"];
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
|
|||
@property (readonly) double progress;
|
||||
/// Enables or disables peak and average decibel meteting
|
||||
@property (readwrite) BOOL meteringEnabled;
|
||||
/// Enables or disables the EQ
|
||||
@property (readwrite) BOOL equalizerEnabled;
|
||||
/// Returns an array of STKFrameFilterEntry objects representing the filters currently in use
|
||||
@property (readonly) NSArray* frameFilters;
|
||||
/// Returns the items pending to be played (includes buffering and upcoming items but does not include the current item)
|
||||
|
|
|
|||
|
|
@ -171,8 +171,12 @@ static AudioStreamBasicDescription canonicalAudioStreamBasicDescription;
|
|||
Float32 averagePowerDb[2];
|
||||
|
||||
BOOL meteringEnabled;
|
||||
BOOL equalizerOn;
|
||||
BOOL equalizerEnabled;
|
||||
STKAudioPlayerOptions options;
|
||||
|
||||
NSMutableArray* converterNodes;
|
||||
|
||||
AUGraph audioGraph;
|
||||
AUNode eqNode;
|
||||
AUNode mixerNode;
|
||||
|
|
@ -446,6 +450,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
options = optionsIn;
|
||||
|
||||
self->volume = 1.0;
|
||||
self->equalizerEnabled = optionsIn.equalizerBandFrequencies[0] != 0;
|
||||
|
||||
PopulateOptionsWithDefault(&options);
|
||||
|
||||
|
|
@ -522,7 +527,11 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
AudioComponentInstanceDispose(outputUnit);
|
||||
}
|
||||
|
||||
AUGraphClose(audioGraph);
|
||||
if (audioGraph)
|
||||
{
|
||||
AUGraphUninitialize(audioGraph);
|
||||
AUGraphClose(audioGraph);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&playerMutex);
|
||||
pthread_mutex_destroy(&mainThreadSyncCallMutex);
|
||||
|
|
@ -1955,6 +1964,8 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)), 0);
|
||||
CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &desFormat, sizeof(desFormat)), 0);
|
||||
CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(maxFramesPerSlice)), 0);
|
||||
|
||||
[converterNodes addObject:@(convertNode)];
|
||||
|
||||
return convertNode;
|
||||
}
|
||||
|
|
@ -1962,24 +1973,33 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
-(void) connectNodes:(AUNode)srcNode desNode:(AUNode)desNode srcUnit:(AudioComponentInstance)srcUnit desUnit:(AudioComponentInstance)desUnit
|
||||
{
|
||||
OSStatus status;
|
||||
BOOL addConverter = NO;
|
||||
AudioStreamBasicDescription srcFormat, desFormat;
|
||||
UInt32 size = sizeof(AudioStreamBasicDescription);
|
||||
|
||||
CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(srcUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size));
|
||||
CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &desFormat, &size));
|
||||
|
||||
status = AudioUnitSetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat));
|
||||
addConverter = memcmp(&srcFormat, &desFormat, sizeof(srcFormat)) != 0;
|
||||
|
||||
if (status)
|
||||
if (addConverter)
|
||||
{
|
||||
AUNode convertNode = [self createConverterNode:srcFormat desFormat:desFormat];
|
||||
|
||||
CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, mixerNode, 0));
|
||||
status = AudioUnitSetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat));
|
||||
|
||||
addConverter = status != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (addConverter)
|
||||
{
|
||||
AUNode convertNode = [self createConverterNode:srcFormat desFormat:desFormat];
|
||||
|
||||
CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, srcNode, 0, convertNode, 0));
|
||||
CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, desNode, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, srcNode, 0, desNode, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void) setOutputCallbackForFirstNode:(AUNode)firstNode firstUnit:(AudioComponentInstance)firstUnit
|
||||
|
|
@ -2014,8 +2034,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
-(void) createAudioGraph
|
||||
{
|
||||
OSStatus status;
|
||||
NSMutableArray* nodes = [[NSMutableArray alloc] init];
|
||||
NSMutableArray* units = [[NSMutableArray alloc] init];
|
||||
converterNodes = [[NSMutableArray alloc] init];
|
||||
|
||||
CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph));
|
||||
CHECK_STATUS_AND_RETURN(AUGraphOpen(audioGraph));
|
||||
|
|
@ -2024,11 +2043,46 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
[self createMixerUnit];
|
||||
[self createOutputUnit];
|
||||
|
||||
[self connectGraph];
|
||||
|
||||
CHECK_STATUS_AND_RETURN(AUGraphInitialize(audioGraph));
|
||||
|
||||
self.volume = self->volume;
|
||||
}
|
||||
|
||||
-(void) connectGraph
|
||||
{
|
||||
OSStatus status;
|
||||
NSMutableArray* nodes = [[NSMutableArray alloc] init];
|
||||
NSMutableArray* units = [[NSMutableArray alloc] init];
|
||||
|
||||
AUGraphClearConnections(audioGraph);
|
||||
|
||||
for (NSNumber* converterNode in converterNodes)
|
||||
{
|
||||
status = AUGraphRemoveNode(audioGraph, (AUNode)converterNode.intValue);
|
||||
}
|
||||
|
||||
[converterNodes removeAllObjects];
|
||||
|
||||
if (eqNode)
|
||||
{
|
||||
[nodes addObject:@(eqNode)];
|
||||
[units addObject:[NSValue valueWithPointer:eqUnit]];
|
||||
if (self->equalizerEnabled)
|
||||
{
|
||||
[nodes addObject:@(eqNode)];
|
||||
[units addObject:[NSValue valueWithPointer:eqUnit]];
|
||||
|
||||
self->equalizerOn = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->equalizerOn = NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->equalizerOn = NO;
|
||||
}
|
||||
|
||||
if (mixerNode)
|
||||
{
|
||||
|
|
@ -2041,7 +2095,7 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
[nodes addObject:@(outputNode)];
|
||||
[units addObject:[NSValue valueWithPointer:outputUnit]];
|
||||
}
|
||||
|
||||
|
||||
[self setOutputCallbackForFirstNode:(AUNode)[[nodes objectAtIndex:0] intValue] firstUnit:(AudioComponentInstance)[[units objectAtIndex:0] pointerValue]];
|
||||
|
||||
for (int i = 0; i < nodes.count - 1; i++)
|
||||
|
|
@ -2053,10 +2107,6 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
|
||||
[self connectNodes:srcNode desNode:desNode srcUnit:srcUnit desUnit:desUnit];
|
||||
}
|
||||
|
||||
CHECK_STATUS_AND_RETURN(AUGraphInitialize(audioGraph));
|
||||
|
||||
self.volume = self->volume;
|
||||
}
|
||||
|
||||
-(BOOL) startAudioGraph
|
||||
|
|
@ -2585,6 +2635,17 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
|
|||
entry->filter(asbd.mChannelsPerFrame, asbd.mBytesPerFrame, inNumberFrames, ioData->mBuffers[0].mData);
|
||||
}
|
||||
}
|
||||
|
||||
if (audioPlayer->equalizerEnabled != audioPlayer->equalizerOn)
|
||||
{
|
||||
Boolean isUpdated;
|
||||
|
||||
[audioPlayer connectGraph];
|
||||
|
||||
AUGraphUpdate(audioPlayer->audioGraph, &isUpdated);
|
||||
|
||||
isUpdated = isUpdated;
|
||||
}
|
||||
|
||||
if (entry == nil)
|
||||
{
|
||||
|
|
@ -2966,4 +3027,15 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
|
|||
return self->volume;
|
||||
}
|
||||
|
||||
-(BOOL) equalizerEnabled
|
||||
{
|
||||
return self->equalizerEnabled;
|
||||
}
|
||||
|
||||
-(void) setEqualizerEnabled:(BOOL)value
|
||||
{
|
||||
self->equalizerEnabled = value;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
Loading…
Reference in New Issue