Switch button to mute (swift) - ios

What I am trying to do is have a settings page in my app and when a switch is clicked on (its original state is off) then it will mute the entire app. So far what my code can do is mute only the current view and it works great until I either segue to my main view then that music is still playing that is associated with that and when I segue back to the settings page the mute switch is returned to its original off state and the music is playing once again. I was wondering how to fix my code so that when turned on it mutes all noise. Here is my code thank you for reading and helping:
import UIKit
import AVFoundation
var songs = ""
var backgroundMusicPlayer: AVAudioPlayer!
func playBackgroundMusic(filename: String) {
let url = NSBundle.mainBundle().URLForResource(
filename, withExtension: nil)
if (url == nil) {
println("Could not find file: \(filename)")
return
}
var error: NSError? = nil
backgroundMusicPlayer =
AVAudioPlayer(contentsOfURL: url, error: &error)
if backgroundMusicPlayer == nil {
println("Could not create audio player: \(error!)")
return
}
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}
class settingsView: UIViewController {
#IBOutlet weak var mySwitch: UISwitch!
#IBAction func switchPressed(sender: AnyObject) {
playBackgroundMusic(songs)
if mySwitch.on {
backgroundMusicPlayer.pause()
} else {
backgroundMusicPlayer.play()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
songs = "settingsBackground.mp3"
switchPressed(self)
}
}

You can do it like this way:
MainViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let status = NSUserDefaults().stringForKey("playerStatus")
if status == "Off"{
if (backgroundMusicPlayer?.playing != nil){
backgroundMusicPlayer?.stop()
}
}else{
songs = "1.mp3"
playBackgroundMusic(songs)
}
}
}
settingsView.swift
import UIKit
class settingsView: UIViewController {
#IBOutlet weak var mySwitch: UISwitch!
#IBAction func switchPressed(sender: AnyObject) {
if mySwitch.on {
NSUserDefaults().setObject("on", forKey: "playerStatus")
playBackgroundMusic(songs)
} else {
NSUserDefaults().setObject("Off", forKey: "playerStatus")
backgroundMusicPlayer!.stop()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let status = NSUserDefaults().stringForKey("playerStatus")
if status == "Off" {
mySwitch.setOn(false, animated: false)
}
}
}
Here is complete working project : https://github.com/DharmeshKheni/Switch-with-AudioPlayer

Related

How to turn off Background Music using a Toggle Switch in Xcode using Swift?

I am playing background music in my app from the App delegate once the app launches. Now, In my 2nd V.C. I have set up a toggle switch to turn om/off the background music. But, whenever I am running the follwing code, my app is crashing giving me this error:-
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
Could anyone please let me know how can I implement the following task in my V.C. Would appreciate your help! Thanks:)
**App Delegate**
let vc = SecondViewController()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
vc.playMusic()
return true
}
**Second View Controller**
import UIKit
import AVFoundation
class SecondViewController: UIViewController {
#IBOutlet weak var musicToggleSwitch: UISwitch!
var music: AVAudioPlayer!
let vc_1 = ViewController()
override func viewDidLoad() {
super.viewDidLoad()
self.musicToggleSwitch.setOn(UserDefaults.standard.bool(forKey: "musicToggleState"), animated: true)
}
#IBAction func musicToggleSwitch(_ sender: UISwitch) {
if (musicToggleSwitch.isOn == true) {
if (music.isPlaying == false) {
music.play()
}
}
else {
if (music.isPlaying == true) {
music.stop()
}
}
UserDefaults.standard.set(sender.isOn, forKey: "musicToggleState")
}
func playMusic() {
if let musicURL = Bundle.main.url(forResource: "Music", withExtension: "mp3") {
if let audioPlayer = try? AVAudioPlayer(contentsOf: musicURL) {
music = audioPlayer
music.numberOfLoops = -1
music.play()
}
}
}
}
This should solve your issues.
If it still doesn't play, add some breakpoints in the creation block of the music variable to see what goes wrong.
class SecondViewController: UIViewController {
#IBOutlet weak var musicToggleSwitch: UISwitch!
var music: AVAudioPlayer? = {
guard let musicURL = Bundle.main.url(forResource: "Music", withExtension: "mp3") else {
return nil
}
let audioPlayer = try? AVAudioPlayer(contentsOf: musicURL)
audioPlayer?.numberOfLoops = -1
return audioPlayer
}()
override func viewDidLoad() {
super.viewDidLoad()
self.musicToggleSwitch.setOn(UserDefaults.standard.bool(forKey: "musicToggleState"), animated: true)
}
#IBAction func musicToggleSwitch(_ sender: UISwitch) {
guard let music = music, sender.isOn != music.isPlaying else {
return
}
if sender.isOn {
music.play()
} else {
music.stop()
}
UserDefaults.standard.set(sender.isOn, forKey: "musicToggleState")
}
func playMusic() {
music?.play()
}
}
The problem is this line:
let vc = SecondViewController()
That is not the same SecondViewController that you see in your interface. So playMusic is called on the wrong view controller, and on the view controller you can see music remains nil and you crash.

Facebook signup uses wrong segue within if statement - Swift

So on my first screen of my iOS app I have a “Login” “SignUp” and a “SignUp With Facebook” buttons. The first two buttons link to their own view controllers just fine, and once logged in the simulator will automatically log them in with the:
if PFUser.currentUser() != nil {
self.performSegueWithIdentifier("autoSegue", sender: self)
} else {
Code that you can see at the bottom of the full block of code below. However the Facebook signup I want to transition to a separate view controller where I can show them their profile pic, capture the data on Parse, have them enter a user name, then segue to the same view controller that the SignUp and Login go to – autoSegue. I have all the code on that view controller already written out, but my problem is that when they click the signup button for Facebook, it takes them through the autoSegue and not the fbSignup segue (the one that links to where I want to capture the FB data). Both segues are linked directly from the view controller (not the buttons themselves), and I receive no build errors. I appreciate any help.
Thanks!
Full code:
import UIKit
import Parse
import MediaPlayer
import FBSDKCoreKit
class ViewController: UIViewController {
#IBOutlet var loginAlpha: UIButton!
#IBOutlet var signupAlpha: UIButton!
var avPlayer: AVPlayer!
var avPlayerLayer: AVPlayerLayer!
var paused: Bool = false
#IBAction func facebookSignup(sender: AnyObject) {
let permissions = ["public_profile"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) { (user: PFUser?, error: NSError?) -> Void in
if let error = error {
print(error)
} else {
if let user = user {
self.performSegueWithIdentifier("fbSignup", sender: self)
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// code for background video
let theURL = NSBundle.mainBundle().URLForResource("test", withExtension: "mp4")
avPlayer = AVPlayer(URL: theURL!)
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
avPlayer.volume = 0
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.None
avPlayerLayer.frame = view.layer.bounds
view.backgroundColor = UIColor.clearColor();
view.layer.insertSublayer(avPlayerLayer, atIndex: 0)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "playerItemDidReachEnd:",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: avPlayer.currentItem)
}
func playerItemDidReachEnd(notification: NSNotification) {
let p: AVPlayerItem = notification.object as! AVPlayerItem
p.seekToTime(kCMTimeZero)
}
override func viewDidAppear(animated: Bool) {
if PFUser.currentUser() != nil {
self.performSegueWithIdentifier("autoSegue", sender: self)
} else {
signupAlpha.alpha = 0
loginAlpha.alpha = 0
UIView.animateWithDuration(1.5, delay: 1.0, options: [], animations: { () -> Void in
self.signupAlpha.alpha = 1.0
self.loginAlpha.alpha = 1.0
}, completion: nil)
avPlayer.play()
paused = false
}
}
override func viewDidDisappear(animated: Bool) {
avPlayer.pause()
paused = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You are using Storyboards? You may have messed up on the storyboard and connected the segue to the wrong ViewController.
I can't see anything particularly wrong with your code.

Impossible to stop AVPlayer

I am currently testing the use of AVPlayer with audio streaming url, using Swift. There are play() and pause() methods, but the problem is that, pausing only, the stream remains cached in the device.
Here is my test code :
import UIKit
import AVFoundation
class ViewController: UIViewController {
let player = AVPlayer(URL: NSURL(string: "http://streaming.radio.rtl.fr/rtl-1-48-192")!)
#IBOutlet weak var btnPlay: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnPress(sender: AnyObject) {
if (btnPlay.titleLabel?.text == "Play") {
initPlayer()
btnPlay.setTitle("Stop", forState: UIControlState.Normal)
} else {
stopPlayer()
btnPlay.setTitle("Play", forState: UIControlState.Normal)
}
}
func initPlayer() {
player.play()
}
func stopPlayer() {
// player.currentItem = nil // Last thing I tried, but generate an error
player.pause()
}
}
Here are the issues when trying somethings :
player = nil : "Cannot assign a value of type 'NilLiteralCOnvertible' to a value of type 'AVPlayer'"
player.currentItem = nil : "Cannot assign to property: 'currentItem' is a get-only property"
I tried everything, even through AVQueuePlayer without any effective result. (obviously, since I only have one item in my case).
How to stop AVPlayer or destroy his instance ?
From this post I found the best solution to completely stop AVPlayer before you leave or start a new player:
videoPlayer.replaceCurrentItemWithPlayerItem(nil)
[Update] For SWIFT 3:
player.replaceCurrentItem(with: nil)
If you declare player as an optional variable, you can then set the player to nil to deallocate it.
Silly example but it shows what happens:
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet weak var btnPlay: UIButton!
var player:AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnPress(sender: AnyObject) {
if (btnPlay.titleLabel?.text == "Play") {
initPlayer()
btnPlay.setTitle("Stop", forState: UIControlState.Normal)
} else {
stopPlayer()
btnPlay.setTitle("Play", forState: UIControlState.Normal)
}
}
func initPlayer() {
if let play = player {
print("playing")
play.play()
} else {
print("player allocated")
player = AVPlayer(URL: NSURL(string: "http://streaming.radio.rtl.fr/rtl-1-48-192")!)
print("playing")
player!.play()
}
}
func stopPlayer() {
if let play = player {
print("stopped")
play.pause()
player = nil
print("player deallocated")
} else {
print("player was already deallocated")
}
}
}
SWIFT 3 Version:
player.replaceCurrentItem(with: nil)

How to play audio in background with Swift?

As you see I'm streaming an audio broadcast. But when I press the home button and exit the app streaming stops or I cannot hear. How can I continue streaming in background and listen it from lock screen?
ViewController.Swift
import UIKit
import AVFoundation
import MediaPlayer
import GoogleMobileAds
class ViewController: UIViewController, GADInterstitialDelegate {
#IBOutlet weak var exitMapButton: UIButton!
#IBOutlet weak var radarMap: UIWebView!
var interstitial: GADInterstitial!
func createAndLoadInterstitial() -> GADInterstitial {
var interstitial = GADInterstitial(adUnitID: "adUnitID-XXXX")
interstitial.delegate = self
interstitial.loadRequest(GADRequest())
return interstitial
}
func getAd(){
if (self.interstitial.isReady)
{
self.interstitial.presentFromRootViewController(self)
self.interstitial = self.createAndLoadInterstitial()
}
}
#IBOutlet weak var ataturkButton: UIButton!
#IBOutlet weak var sabihaButton: UIButton!
#IBOutlet weak var esenbogaButton: UIButton!
#IBOutlet weak var weatherButton: UIButton!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var playButton: UIButton!
#IBOutlet weak var webViewButton: UIButton!
var googleBannerView: GADBannerView!
override func viewDidLoad() {
super.viewDidLoad()
}
class PlayerAv {
var audioLink: String?
var player: AVPlayer
init(link: String) {
self.audioLink = link
self.player = AVPlayer(URL: NSURL(string: link))
}
}
var myPlayer = PlayerAv(link: "http://somewebsite.com/abc.pls")
var setTowerState = ""
#IBAction func sliderValueChanged(sender: UISlider) {
var currentValue = Float(sender.value)
println(currentValue)
myPlayer.player.volume = currentValue
}
#IBAction func getWeatherWindow(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "http://somewebpage.com")!)
println("Directed to weather page")
}
#IBAction func changeToAtaturk() {
myPlayer.player.pause()
myPlayer = PlayerAv(link: "http://somewebsite.com/abc.pls")
myPlayer.audioLink == ""
println("\(myPlayer.audioLink!)--a")
playButton.setTitle("Pause", forState: UIControlState.Normal)
myPlayer.player.play()
setTowerState = "ataturk"
statusLabel.text = "Status: Playing, LTBA"
}
#IBAction func changeToEsenboga() {
myPlayer.player.pause()
myPlayer = PlayerAv(link: "http://somewebsite.com/def.pls")
println("\(myPlayer.audioLink!)--a")
playButton.setTitle("Pause", forState: UIControlState.Normal)
myPlayer.player.play()
setTowerState = "esenboga"
statusLabel.text = "Status: Playing, LTAC"
}
#IBAction func changeToSabiha() {
myPlayer.player.pause()
myPlayer = PlayerAv(link: "http://somewebsite.com/efg.pls")
println("\(myPlayer.audioLink!)--a")
playButton.setTitle("Pause", forState: UIControlState.Normal)
myPlayer.player.play()
setTowerState = "sabiha"
statusLabel.text = "Status: Playing, LTFJ"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func playButtonPressed(sender: AnyObject) {
toggle()
}
func toggle() {
if playButton.titleLabel?.text == "Play" {
playRadio()
println("Playing")
statusLabel.text = "Status: Playing"
} else {
pauseRadio()
println("Paused")
statusLabel.text = "Status: Paused"
}
}
func playRadio() {
myPlayer.player.play()
playButton.setTitle("Pause", forState: UIControlState.Normal)
}
func pauseRadio() {
myPlayer.player.pause()
playButton.setTitle("Play", forState: UIControlState.Normal)
}
}
You need to set your app Capabilities Background Modes (Audio and AirPlay) and set your AVAudioSession category to AVAudioSessionCategoryPlayback and set it active
From Xcode 11.4 • Swift 5.2
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
Xcode 10.2.1 Swift 4
Please add the following code in your AppDelegate
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, mode: AVAudioSessionModeDefault, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
return true
}
Note: - Please configure options as required. E.g to stop a background audio while a video file being played add
options: [.allowAirPlay, .defaultToSpeaker]
And don't forget to enable audio and airplay in Background mode
Only paste on the viewDidload
let path = Bundle.main.path(forResource:"Bismallah", ofType: "mp3")
do{
try playerr = AVAudioPlayer(contentsOf: URL(fileURLWithPath: path!))
} catch {
print("File is not Loaded")
}
let session = AVAudioSession.sharedInstance()
do{
try session.setCategory(AVAudioSessionCategoryPlayback)
}
catch{
}
player.play()
Swift 5 Xcode 11.2.1
Add this code where you have initialized the AudioPlayer.
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
let audioSession = AVAudioSession.sharedInstance()
do{
try audioSession.setCategory(AVAudioSession.Category.playback)
}
catch{
fatalError("playback failed")
}

How do I change a play button to a pause button when tapped on?

I need to change my play button to a pause button and vice versa when tapped on. I am still new to this, so I don't know how to identify buttons in the .swift file or how to change icons programmatically in the .swift file.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player = AVAudioPlayer()
var toggleState = 1
#IBAction func playPauseButton(sender: AnyObject) {
if toggleState == 1 {
player.play()
toggleState = 2
} else {
player.pause()
toggleState = 1
}
}
#IBAction func stopButton(sender: AnyObject) {
player.stop()
player.currentTime = 0
}
#IBAction func sliderChanged(sender: AnyObject) {
player.volume = sliderValue.value
}
#IBOutlet weak var sliderValue: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
var audioPath = NSBundle.mainBundle().pathForResource("StarWars", ofType: "mp3")!
var error: NSError?
player = AVAudioPlayer(contentsOfURL: NSURL(string: audioPath), error: &error)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can change the image of the button depending on the state:
#IBAction func playPauseButton(sender: AnyObject) {
var playBtn = sender as UIButton
if toggleState == 1 {
player.play()
toggleState = 2
playBtn.setImage(UIImage(named:"pause.png"),forState:UIControlState.Normal)
} else {
player.pause()
toggleState = 1
playBtn.setImage(UIImage(named:"play.png"),forState:UIControlState.Normal)
}
}
The sender object passed to the playPauseButton is your UIButton which calls the method. Because it is sent as an object of type AnyObject we cast it to a UIButton. If you do not want to cast it, and are sure only a UIButton will call this method you can simply replace AnyObject with UIButton in the function parameter.

Resources