I am currently working on one Podcast app, in which we are using MPCommandCenter to enhance user experience to initialise MPCommandCenter I am using following code
let remoteCommands = MPRemoteCommandCenter.shared()
remoteCommands.playCommand.addTarget { event in
// Perform play action
return .success
}
remoteCommands.pauseCommand.addTarget { event in
// Perform pause action
return .success
}
After using this code MPCommandCenter properly display remote controls. But we have functionality that allow users to Close currently playing podcast. And I am not able to figure out the way to unregister commandcenter manually. Can anyone help me to figure this one out.
remoteCommands.playCommand.removeTarget(self)
remoteCommands.pauseCommand.removeTarget(self)
MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
try? AVAudioSession.sharedInstance().setActive(false)
Related
The approved KVO approach for responding to device volume level changes stops detecting volume button presses after min/max outputVolume is reached. I'd like to continue to receive those button press events after min/max, so I assume I need to try this solution, even if it's not supported by Apple. However, I'm very much an amateur iOS programmer so I could use a hint. Here's what I've been doing (using RxSwift):
NotificationCenter.default.rx.notification(Notification.Name(rawValue: "AVSystemController_AudioVolumeNotificationParameter"))
.subscribe(onNext: { [weak self] notification in
guard let my = self else { return }
my.volumeNotification.accept(notification.userInfo!["AVSystemController_AudioVolumeNotificationParameter"] as! Double)
})
.disposed(by: disposeBag)
Should I instead be subscribing to a Notification named "MPVolumeControllerDataSource_SystemVolumeDidChange"?
Thanks in advance!
Three cheers for open source, specifically: JPSVolumeButtonHandler. This component works like a champ, and uses the Apple-approved KVO technique. Be aware that this component sets AVAudioSession options to .mixWithOthers which prevents MPRemoteCommandCenter from receiving/handing any BlueTooth commands. So if you need BT (Swift 5):
let volumeButtonHandler = JPSVolumeButtonHandler(up: {
// handle up press
}, downBlock: {
// handle down press
})
volumeButtonHandler.sessionOptions = [] // allow remote BT
I also found that programmatically setting the device volume to 0.5 before initializing the button handler avoided occasional min/max barriers. If the device initial volume was close to the min or max, the handler would stop after a few button presses:
try AVAudioSession.sharedInstance().setActive(true, options: [])
MPVolumeView(frame: .zero).volumeSlider.value = 0.5
I’m using Twilio’s Programmable Voice in one of the projects. My primary requirement is to place VoIP class between mobile devices. I am able to place calls from one device to another,but when i accept the call at that time calling screen is dismiss automatically and call continue in background. In this case user do not have an option for disconnect call or any other action related to call because screen is dismissed.
Here is the screen that i have created for call when app is in foreground.
Calling placed success fully but on receiver accept it will dismiss the custom screen.So that user do not have any option to disconnect call or any other action related to call.
If any issue in code or any thing related to call kit setting i need to configure or any other issue ? Please help.
As per my knowledge this is default behaviour of call kit framework. On accept button click it will dismiss the screen when app is in foreground. If you wants to achieve same like whats app then you need to create a custom screen for that.Below code I did to resolve this issue:
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction)
{
NSLog("provider:performAnswerCallAction:")
// TwilioVoice.configureAudioSession()
let vc = loadVC(strStoryboardId: SB_CHAT, strVCId: idVoiceCallVC) as! VoiceCallVC
vc.callername = name
vc.userPhoto = userphoto
APP_DELEGATE.appNavigation?.pushViewController(vc, animated: true)
assert(action.callUUID == self.callInvite?.uuid)
TwilioVoice.isAudioEnabled = false
self.performAnswerVoiceCall(uuid: action.callUUID)
{ (success) in
if (success)
{
action.fulfill()
}
else
{
action.fail()
}
}
action.fulfill()
}
You just need to add your custom screen display code in this delegate method of call kit framework.
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {}
Thanks.
I am creating an music player iOS app and getting data from firebase. I can able to control play, pause, next and previous in simulator or iPhone. While headset is connect to device play, next and previous functionalities are not working properly.
Here is the code which i've used;
func setupRemoteCommandCenter() {
// Get the shared MPRemoteCommandCenter
let commandCenter = MPRemoteCommandCenter.shared()
// Add handler for Play Command
commandCenter.playCommand.addTarget { event in
player?.play()
print("headset play")
return .success
}
// Add handler for Pause Command
commandCenter.pauseCommand.addTarget { event in
player?.pause()
print("headset pause")
return .success
}
// Add handler for Next Command
commandCenter.nextTrackCommand.addTarget { event in
return .success
}
// Add handler for Previous Command
commandCenter.previousTrackCommand.addTarget { event in
return .success
}
}
And calling setupRemoteCommandCenter function in viewdidload
This document says that to receive player event notifications you need to
begin playing audio
be the "Now playing app"
The definition of "Now playing app" is hard to pin down, but it seems to be any app that has an active, non-mixable audio session and is playing audio (or has very recently played audio, there seems to be a brief grace period here) . One possible non-mixable audio session is:
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
try session.setActive(true)
} catch let err as NSError {
print("Error setting up non mixable audio session \(err)")
}
p.s. if you want the headset controls to work while the screen is locked (or if you want the lockscreen controls to work for that matter), you will need to add audio to Background Modes, because technically, if the screen is locked then your app has been backgrounded:
I have an app with different button press sounds. I'm trying to use two functions to set the next button press sound and then play it. The idea is to load the audio file for when the next button is pressed, and then finally play it through a different function when a button is pressed. Using prepareToPlay(), this should make playback faster.
The problem is that when I press a button, I hear 'silence'. I say 'silence' because my speakers actually receive some signal, but its too week to be heard.
Here's my code:
func loadNextButtonPressSound() {
let randomSoundIndex = Int(arc4random_uniform(UInt32(pressSounds.count)))
pressSoundPlayer = try! AVAudioPlayer(contentsOfURL: pressSounds[randomSoundIndex])
pressSoundPlayer.prepareToPlay()
pressSoundPlayer.delegate = self
}
func playButtonPressSound() { // called when a button is pressed
if(StoredSettings.instance.getEnableSoundsSetting()) {
pressSoundPlayer.play()
loadNextButtonPressSound()
}
}
If I instead merge the codes to form this:
internal func playButterPressSound() {
if(StoredSettings.instance.getEnableSoundsSetting()) {
let randomSoundIndex = Int(arc4random_uniform(UInt32(pressSounds.count)))
pressSoundPlayer = try! AVAudioPlayer(contentsOfURL: pressSounds[randomSoundIndex])
pressSoundPlayer.play()
}
}
It starts working (i.e. I hear button presses), but it defeats the purpose of using prepareToPlay() to preload the next sound.
Any suggestions on how to make the first code above work ?
Edited to explain why its not a duplicate:
I am trying to use MPMusicPlayerController.systemMusicPlayer() to control music playback from my app, but I want to disable the Command Center previous track button. I also want to override the default Command Center play and next track functions. The code should be simple:
This code is in ViewController.swift - viewDidLoad
let commandCenter = MPRemoteCommandCenter.sharedCommandCenter()
commandCenter.previousTrackCommand.enabled = false
commandCenter.previousTrackCommand.addTargetWithHandler({ (commandEvent: MPRemoteCommandEvent!) -> MPRemoteCommandHandlerStatus in
self.empty()
return MPRemoteCommandHandlerStatus.Success
})
//MPRemoteCommandCenter.sharedCommandCenter().previousTrackCommand.addTarget(self, action: "empty")
commandCenter.nextTrackCommand.enabled = true
commandCenter.nextTrackCommand.addTargetWithHandler { (commandEvent: MPRemoteCommandEvent!) -> MPRemoteCommandHandlerStatus in
self.gameOver()
return MPRemoteCommandHandlerStatus.Success
}
commandCenter.playCommand.enabled = true
commandCenter.playCommand.addTargetWithHandler { (commandEvent: MPRemoteCommandEvent!) -> MPRemoteCommandHandlerStatus in
self.playing()
return MPRemoteCommandHandlerStatus.Success
}
Also, in AppDelegate.swift - application
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
And in the iOS simulator (both iPad and iPhone), it works correctly, as can be seen in the first screenshot (of the simulator).
However, when deploying the app to my iPad, none of the MPRemoteCommandCenter commands work at all, as can be seen in the second screenshot (of an actual device).
This is different from the "dupliate" question (How Do I Get Audio Controls on Lock Screen/Control Center from AVAudioPlayer in Swift) in the following ways:
I am not using AVAudioSession, I am using MPMusicPlayerController.systemMusicPlayer()
I have already called beginReceivingRemoteControlEvents, so that cant be the issue (unless I have somehow called it incorrectly, in which case, I would love an answer explaining how else it should be called).
Thank you.
,