[Event Handling] Add context to all observers

Add context field to all observers that support it, in case it's useful.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
swiftingly
Christopher Snowhill 2022-06-15 16:47:43 -07:00
parent 5bca70d141
commit 8db2e41049
12 changed files with 157 additions and 87 deletions

View File

@ -47,6 +47,8 @@ void PrintStreamDesc(AudioStreamBasicDescription *inDesc) {
@implementation ConverterNode
static void *kConverterNodeContext = &kConverterNodeContext;
@synthesize inputFormat;
- (id)initWithController:(id)c previous:(id)p {
@ -78,7 +80,7 @@ void PrintStreamDesc(AudioStreamBasicDescription *inDesc) {
lastChunkIn = nil;
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:nil];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:kConverterNodeContext];
}
return self;
@ -900,10 +902,14 @@ tryagain:
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqualToString:@"values.volumeScaling"]) {
// User reset the volume scaling option
[self refreshVolumeScaling];
if(context == kConverterNodeContext) {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqualToString:@"values.volumeScaling"]) {
// User reset the volume scaling option
[self refreshVolumeScaling];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@ -1056,7 +1062,7 @@ static float db_to_scale(float db) {
- (void)dealloc {
DLog(@"Decoder dealloc");
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeScaling"];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeScaling" context:kConverterNodeContext];
paused = NO;
[self cleanUp];

View File

@ -250,6 +250,8 @@ static void upmix(const float *inBuffer, int inchannels, uint32_t inconfig, floa
@implementation DownmixProcessor
static void *kDownmixProcessorContext = &kDownmixProcessorContext;
- (id)initWithInputFormat:(AudioStreamBasicDescription)inf inputConfig:(uint32_t)iConfig andOutputFormat:(AudioStreamBasicDescription)outf outputConfig:(uint32_t)oConfig {
self = [super init];
@ -276,16 +278,16 @@ static void upmix(const float *inBuffer, int inchannels, uint32_t inconfig, floa
[self setupVirt];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.headphoneVirtualization" options:0 context:nil];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.hrirPath" options:0 context:nil];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.headphoneVirtualization" options:0 context:kDownmixProcessorContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.hrirPath" options:0 context:kDownmixProcessorContext];
}
return self;
}
- (void)dealloc {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.headphoneVirtualization"];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.hrirPath"];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.headphoneVirtualization" context:kDownmixProcessorContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.hrirPath" context:kDownmixProcessorContext];
}
- (void)setupVirt {
@ -328,11 +330,15 @@ static void upmix(const float *inBuffer, int inchannels, uint32_t inconfig, floa
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqualToString:@"values.headphoneVirtualization"] ||
[keyPath isEqualToString:@"values.hrirPath"]) {
// Reset the converter, without rebuffering
[self setupVirt];
if(context == kDownmixProcessorContext) {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqualToString:@"values.headphoneVirtualization"] ||
[keyPath isEqualToString:@"values.hrirPath"]) {
// Reset the converter, without rebuffering
[self setupVirt];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

View File

@ -18,6 +18,9 @@
#import "Logging.h"
@implementation InputNode
static void *kInputNodeContext = &kInputNodeContext;
@synthesize exitAtTheEndOfTheStream;
- (id)initWithController:(id)c previous:(id)p {
@ -84,47 +87,53 @@
}
- (void)registerObservers {
DLog(@"REGISTERING OBSERVERS");
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:NULL];
if(!observersAdded) {
DLog(@"REGISTERING OBSERVERS");
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:kInputNodeContext];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:NULL];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:kInputNodeContext];
observersAdded = YES;
observersAdded = YES;
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqual:@"properties"]) {
DLog(@"Input format changed");
// Converter may need resetting, it'll do that when it reaches the new chunks
NSDictionary *properties = [decoder properties];
if(context == kInputNodeContext) {
DLog(@"SOMETHING CHANGED!");
if([keyPath isEqual:@"properties"]) {
DLog(@"Input format changed");
// Converter may need resetting, it'll do that when it reaches the new chunks
NSDictionary *properties = [decoder properties];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
int channels = [[properties objectForKey:@"channels"] intValue];
bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
bytesPerFrame = ((bitsPerSample + 7) / 8) * channels;
nodeFormat = propertiesToASBD(properties);
nodeChannelConfig = [[properties valueForKey:@"channelConfig"] unsignedIntValue];
nodeLossless = [[properties valueForKey:@"encoding"] isEqualToString:@"lossless"];
} else if([keyPath isEqual:@"metadata"]) {
// Inform something of metadata change
NSDictionary *entryProperties = [decoder properties];
if(entryProperties == nil)
return;
nodeFormat = propertiesToASBD(properties);
nodeChannelConfig = [[properties valueForKey:@"channelConfig"] unsignedIntValue];
nodeLossless = [[properties valueForKey:@"encoding"] isEqualToString:@"lossless"];
} else if([keyPath isEqual:@"metadata"]) {
// Inform something of metadata change
NSDictionary *entryProperties = [decoder properties];
if(entryProperties == nil)
return;
NSDictionary *entryInfo = [NSDictionary dictionaryByMerging:entryProperties with:[decoder metadata]];
NSDictionary *entryInfo = [NSDictionary dictionaryByMerging:entryProperties with:[decoder metadata]];
[controller pushInfo:entryInfo];
[controller pushInfo:entryInfo];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@ -251,8 +260,8 @@
- (void)removeObservers {
if(observersAdded) {
[decoder removeObserver:self forKeyPath:@"properties"];
[decoder removeObserver:self forKeyPath:@"metadata"];
[decoder removeObserver:self forKeyPath:@"properties" context:kInputNodeContext];
[decoder removeObserver:self forKeyPath:@"metadata" context:kInputNodeContext];
observersAdded = NO;
}
}

View File

@ -42,6 +42,8 @@ NSArray *sortClassesByPriority(NSArray *theClasses) {
@implementation CogDecoderMulti
static void *kCogDecoderMultiContext = &kCogDecoderMultiContext;
+ (NSArray *)mimeTypes {
return nil;
}
@ -114,17 +116,17 @@ NSArray *sortClassesByPriority(NSArray *theClasses) {
[theDecoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:NULL];
context:kCogDecoderMultiContext];
[theDecoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:NULL];
context:kCogDecoderMultiContext];
}
- (void)removeObservers {
[theDecoder removeObserver:self forKeyPath:@"properties"];
[theDecoder removeObserver:self forKeyPath:@"metadata"];
[theDecoder removeObserver:self forKeyPath:@"properties" context:kCogDecoderMultiContext];
[theDecoder removeObserver:self forKeyPath:@"metadata" context:kCogDecoderMultiContext];
}
- (BOOL)setTrack:(NSURL *)track {
@ -136,8 +138,12 @@ NSArray *sortClassesByPriority(NSArray *theClasses) {
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
[self willChangeValueForKey:keyPath];
[self didChangeValueForKey:keyPath];
if(context == kCogDecoderMultiContext) {
[self willChangeValueForKey:keyPath];
[self didChangeValueForKey:keyPath];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end

View File

@ -23,6 +23,8 @@ static NSString *CogPlaybackDidBeginNotficiation = @"CogPlaybackDidBeginNotficia
@implementation OutputCoreAudio
static void *kOutputCoreAudioContext = &kOutputCoreAudioContext;
static void fillBuffers(AudioBufferList *ioData, float *inbuffer, size_t count, size_t offset) {
const size_t channels = ioData->mNumberBuffers;
for(int i = 0; i < channels; ++i) {
@ -223,6 +225,11 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kOutputCoreAudioContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.outputDevice"]) {
NSDictionary *device = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"outputDevice"];
@ -774,9 +781,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
visController = [VisualizationController sharedController];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:NULL];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:NULL];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.eqPreamp" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:NULL];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:kOutputCoreAudioContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:kOutputCoreAudioContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.eqPreamp" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kOutputCoreAudioContext];
observersapplied = YES;
return (err == nil);
@ -805,10 +812,10 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
- (void)stop {
stopInvoked = YES;
if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice" context:kOutputCoreAudioContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQenable" context:kOutputCoreAudioContext];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.eqPreamp" context:kOutputCoreAudioContext];
observersapplied = NO;
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice"];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQenable"];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.eqPreamp"];
}
if(stopNext && !paused) {
if(!started) {

View File

@ -53,6 +53,7 @@
// These are in NSObject, so as long as you are a subclass of that, you are ok.
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context;
- (BOOL)isSilence;
@end

View File

@ -13,6 +13,8 @@
#import "Logging.h"
static void *kFileTreeDataSourceContext = &kFileTreeDataSourceContext;
static NSURL *defaultMusicDirectory(void) {
return [[NSFileManager defaultManager] URLForDirectory:NSMusicDirectory
inDomain:NSUserDomainMask
@ -44,18 +46,22 @@ static NSURL *defaultMusicDirectory(void) {
forKeyPath:@"values.fileTreeRootURL"
options:NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionInitial
context:nil];
context:kFileTreeDataSourceContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
NSString *url =
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"];
DLog(@"File tree root URL: %@\n", url);
self.rootURL = [NSURL URLWithString:url];
if(context == kFileTreeDataSourceContext) {
if([keyPath isEqualToString:@"values.fileTreeRootURL"]) {
NSString *url =
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] objectForKey:@"fileTreeRootURL"];
DLog(@"File tree root URL: %@\n", url);
self.rootURL = [NSURL URLWithString:url];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

View File

@ -14,6 +14,8 @@
@implementation InfoWindowController
static void *kInfoWindowControllerContext = &kInfoWindowControllerContext;
@synthesize valueToDisplay;
+ (void)initialize {
@ -27,18 +29,22 @@
}
- (void)awakeFromNib {
[playlistSelectionController addObserver:self forKeyPath:@"selection" options:NSKeyValueObservingOptionNew context:nil];
[currentEntryController addObserver:self forKeyPath:@"content" options:NSKeyValueObservingOptionNew context:nil];
[appController addObserver:self forKeyPath:@"miniMode" options:NSKeyValueObservingOptionNew context:nil];
[playlistSelectionController addObserver:self forKeyPath:@"selection" options:NSKeyValueObservingOptionNew context:kInfoWindowControllerContext];
[currentEntryController addObserver:self forKeyPath:@"content" options:NSKeyValueObservingOptionNew context:kInfoWindowControllerContext];
[appController addObserver:self forKeyPath:@"miniMode" options:NSKeyValueObservingOptionNew context:kInfoWindowControllerContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// Avoid "selection" because it creates a proxy that's hard to reason with when we don't need to write.
PlaylistEntry *currentSelection = [[playlistSelectionController selectedObjects] firstObject];
if(currentSelection != NULL) {
[self setValueToDisplay:currentSelection];
if(context == kInfoWindowControllerContext) {
// Avoid "selection" because it creates a proxy that's hard to reason with when we don't need to write.
PlaylistEntry *currentSelection = [[playlistSelectionController selectedObjects] firstObject];
if(currentSelection != NULL) {
[self setValueToDisplay:currentSelection];
} else {
[self setValueToDisplay:[currentEntryController content]];
}
} else {
[self setValueToDisplay:[currentEntryController content]];
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

View File

@ -18,6 +18,8 @@
@implementation CueSheetDecoder
static void *kCueSheetDecoderContext = &kCueSheetDecoderContext;
+ (NSArray *)fileTypes {
return [CueSheetContainer fileTypes];
}
@ -199,24 +201,26 @@
}
- (void)registerObservers {
DLog(@"REGISTERING OBSERVERS");
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:NULL];
if(!observersAdded) {
DLog(@"REGISTERING OBSERVERS");
[decoder addObserver:self
forKeyPath:@"properties"
options:(NSKeyValueObservingOptionNew)
context:kCueSheetDecoderContext];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:NULL];
[decoder addObserver:self
forKeyPath:@"metadata"
options:(NSKeyValueObservingOptionNew)
context:kCueSheetDecoderContext];
observersAdded = YES;
observersAdded = YES;
}
}
- (void)removeObservers {
if(observersAdded) {
[decoder removeObserver:self forKeyPath:@"properties"];
[decoder removeObserver:self forKeyPath:@"metadata"];
[decoder removeObserver:self forKeyPath:@"properties" context:kCueSheetDecoderContext];
[decoder removeObserver:self forKeyPath:@"metadata" context:kCueSheetDecoderContext];
observersAdded = NO;
}
}
@ -225,8 +229,12 @@
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
[self willChangeValueForKey:keyPath];
[self didChangeValueForKey:keyPath];
if(context == kCueSheetDecoderContext) {
[self willChangeValueForKey:keyPath];
[self didChangeValueForKey:keyPath];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)close {

View File

@ -109,6 +109,8 @@ extern NSString *CogPlaybackDidStopNotficiation;
} else {
[self colorsDidChange:nil];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

View File

@ -85,6 +85,8 @@ extern NSString *CogPlaybackDidStopNotficiation;
} else {
[self updateControls];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

View File

@ -10,9 +10,12 @@
#import "CogAudio/Helper.h"
#import "PlaybackController.h"
static void *kVolumeSliderContext = &kVolumeSliderContext;
@implementation VolumeSlider {
NSTimer *currentTimer;
BOOL wasInsideSnapRange;
BOOL observersadded;
}
- (id)initWithFrame:(NSRect)frame {
@ -46,11 +49,14 @@
popover.animates = NO;
[popover setContentSize:textView.bounds.size];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeLimit" options:0 context:nil];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeLimit" options:0 context:kVolumeSliderContext];
observersadded = YES;
}
- (void)dealloc {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeLimit"];
if(observersadded) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeLimit" context:kVolumeSliderContext];
}
}
- (void)updateToolTip {
@ -116,6 +122,11 @@
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != kVolumeSliderContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if([keyPath isEqualToString:@"values.volumeLimit"]) {
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
const double new_MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;