George Garside Blog

A place of many ramblings about macOS and development. If you find something useful on here, it's probably an accident.

AirPods Pro can automatically enable noise cancellation when music is played and switch to transparency mode when music is paused. You can hook the media controller to change noise cancellation mode on your AirPods automatically.

  • given the application playing media
  • when the application changes the state of playing (from stop/pause to play or vice versa)
  • if the current output route is AirPods Pro
    • if media is now playing
      • set the Bluetooth listening mode to Noise Cancellation
    • else
      • set the Bluetooth listening mode to Transparency

Hook media controller

The media controller class is SBMediaController. This class contains a method which will be called when the media state changes:

-(void)_mediaRemoteNowPlayingApplicationIsPlayingDidChange:(id)arg1

A hook on this method will allow you to perform an action whenever the media’s ‘now playing’ state changes. To know whether the media has changed from playing to paused or vice versa:

  1. hook after the built-in implementation of this method is finished,
    %orig(arg1);
  2. then inspect what the current state of play is by looking at SBMediaController:
    -(BOOL)isPlaying;.

The code at this point is as follows, which includes the outline of a hook on the aforementioned method and the ability for that hook to find whether media is playing:

@interface SBMediaController : NSObject
-(BOOL)isPlaying;
@end

%hook SBMediaController
-(void)_mediaRemoteNowPlayingApplicationIsPlayingDidChange:(id)arg1 {
  %orig(arg1);
}
%end

Get access to AirPods

When media is playing on iPhone, it is routed to an output device such as the built-in speaker, connected headphones or AirPlay. Each of these routes are an instance of MPAVRoute. You can find the currently active route from the MPAVRoutingController which has the pickedRoute property.

@interface MPAVRoutingController : NSObject
@property(readonly, nonatomic) MPAVRoute *pickedRoute;
@end

To access the pickedRoute from the

Swiftvalue(forKey: "_routingController")?.pickedRoute()
Objective-C[[self valueForKey:@"_routingController"] pickedRoute]
routingController‘s pickedRoute

To make changes to the state of the AirPods, it’s necessary to get the

MPAVRoutingController provides the chosen MPAVRoute through the pickedRoute property.

Choose noise cancellation or transparency mode

We’re interested in two of the three listening modes of AirPods Pro:

Noise cancellation modeAirPods Pro Noise Cancellation mode iconAVOutputDeviceBluetooth­ListeningModeActiveNoiseCancellation
Normal modeAirPods Pro normal mode iconAVOutputDeviceBluetooth­ListeningModeNormal
Transparency modeAirPods Pro Transparency mode iconAVOutputDeviceBluetooth­ListeningModeAudioTransparency
AirPods Pro listening modes and internal representations

If music is playing, we want to choose noise cancellation mode, otherwise we want to set transparency mode.

SwiftisPlaying() ? "AVOutputDeviceBluetooth­ListeningModeActiveNoiseCancellation" : "AVOutputDeviceBluetooth­ListeningModeAudioTransparency"
Objective-C[self isPlaying] ? @"AVOutputDeviceBluetooth­ListeningModeActiveNoiseCancellation" : @"AVOutputDeviceBluetooth­ListeningModeAudioTransparency"];

The return value of the above expression is what the listening mode needs to be set to…

Set listening mode

Another class will help us with this: AVOutputDevice. This class contains a useful method:

-(void)setCurrentBluetoothListeningMode:(NSString *)arg1;

This method can be called and its returned value can be used to set the value of the property.

Jailbreak tweak

The Banana jailbreak tweak does this automatically for you:

Leave a Reply

No comments