Play sound on WatchOS - swift

I'm trying to make an app for Apple Watch using Xcode. It's a very simple app that plays a sound whenever a button is played but I can't seem to find the way to play.
The audio file is in my WatchKit extension and I have tried to play it through a WKAudioFilePlayer object but I don't know if I am doing it the right way.
override func awake(withContext context: Any?) {
super.awake(withContext: context)
kickPath = Bundle.main.path(forResource:"Kick", ofType: "mp3")!
kickUrl = URL(fileURLWithPath: kickPath!)
kickAsset = WKAudioFileAsset(url: kickUrl!)
kickItem = WKAudioFilePlayerItem(asset: kickAsset!)
kick = WKAudioFilePlayer(playerItem: kickItem!)
}
#IBAction func kickButton() {
switch kick.status {
case .readyToPlay:
kick.play()
print("sound")
case .failed:
print("failed")
case .unknown:
print("unknown")
}
}
The audio doesn't play but I know it's getting on the right switch case because it prints "sound".

The thing that worked for me was using AVFoundation with an AVAudioPlayer for the sound instead of the WKAudioFilePlayer I was using. It sounds through the Watch's speaker and through headphones too if you have a bluetooth set connected.

Related

Using an AVPlayer returns a "non-Multipath connection" error

I'm using AVKit to play a youtube URL.
I have this code inside a button action:
#IBAction func trailerButtonAction(_ sender: Any) {
guard let youtubeUrl = youtubeURL else { return }
let player = AVPlayer(url: youtubeUrl)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true) {
player.play()
}
}
The URL is valid, but when I press the button, the video doesn't stop loading and I'm getting this message on Debug area:
nw_endpoint_flow_copy_multipath_subflow_counts Called on non-Multipath connection
Edit:
I found that AVPlayer doesn't support youtube URL
I would say this log isn't necessarily relevant. I was getting this error when trying to playback on the simulator but it wasn't happening on a real device.
One workaround would be to use a 12.4.x simulator as it does not exhibit this issue. Only the 13.x simulators are showing this error. It happens to repeatedly that it slows down Simulator to a craw until all requested tracks have been buffered.
To combat this while testing, I am either not turning on AVPlayer or I am only buffering a short track.
To cut down on the number of errors try initing your AVPlayer like so:
var avPlayer : AVPlayer = AVPlayer()
This may cut down the errors by 30%.

WatchKit Sound from watch speaker without displaying controls

this has probably been covered before.
I can play sound through the watch speaker (as long as no bluetooth device is connected). But it brings up the annoying controls.
I want to play sound with no controls on a button press.
Is there a way of hiding the controls?
let assetURL: NSURL = NSBundle.mainBundle().URLForResource("Sound", withExtension: "wav")!
#IBAction func buttonAction() {
self.presentMediaPlayerControllerWithURL(assetURL, options: nil, completion: { _ in })
}

How to play the same sound overlapping with AVAudioPlayer?

This code plays the sound when the button is tapped but cancels the previous if it is pressed again. I do not want this to happen I want the same sound to overlap when repeatedly pressed. I believe it might be due to using the same AVAudioPlayer as I have looked on the internet but I am new to swift and want to know how to create a new AVAudioPlayer everytime the method runs so the sounds overlap.
func playSound(sound:String){
// Set the sound file name & extension
let soundPath = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource(sound, ofType: "mp3")!)
do {
//Preperation
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch _{
}
do {
try AVAudioSession.sharedInstance().setActive(true)
}
catch _ {
}
//Play the sound
var error:NSError?
do{
audioPlayer = try AVAudioPlayer(contentsOfURL: soundPath)
}catch let error1 as NSError {
error = error1
}
audioPlayer.prepareToPlay()
audioPlayer.play()
}
To play two sounds simultaneously with AVAudioPlayer you just have to use a different player for each sound.
In my example I've declared two players, playerBoom and playerCrash, in the Viewcontroller, and I'm populating them with a sound to play via a function, then trigger the play at once:
import AVFoundation
class ViewController: UIViewController {
var playerBoom:AVAudioPlayer?
var playerCrash:AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
playerBoom = preparePlayerForSound(named: "sound1")
playerCrash = preparePlayerForSound(named: "sound2")
playerBoom?.prepareToPlay()
playerCrash?.prepareToPlay()
playerBoom?.play()
playerCrash?.play()
}
func preparePlayerForSound(named sound: String) -> AVAudioPlayer? {
do {
if let soundPath = NSBundle.mainBundle().pathForResource(sound, ofType: "mp3") {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
return try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: soundPath))
} else {
print("The file '\(sound).mp3' is not available")
}
} catch let error as NSError {
print(error)
}
return nil
}
}
It works very well but IMO is not suitable if you have many sounds to play. It's a perfectly valid solution for just a few ones, though.
This example is with two different sounds but of course the idea is exactly the same for two identic sounds.
I could not find a solution using just AVAudioPlayer.
Instead, I have found a solution to this problem with a library that is built on top of AVAudioPlayer.
The library allows same sounds to be played overlapped with each other.
https://github.com/adamcichy/SwiftySound

Can play a sound effect on apple watch simulator now?

I want to play a sound when user press on the button on WKInterfaceController. Here is how I did in my project:
- Add a AVFoundation frame work to my watchkit app.
- Import AVFoundation on my WKInterfaceController
- Create 2 variable for audio session and player:
var audioSession:AVAudioSession!
var player:AVAudioPlayer!
- make 2 function for configure an audio session and configure Audio Player:
func configureAudioSession() {
self.audioSession = AVAudioSession.sharedInstance()
var categoryError:NSError?
var activeError:NSError?
// set category cho audio session
self.audioSession.setCategory(AVAudioSessionCategoryPlayback, error: &categoryError)
println("error: \(categoryError)")
// set active cho audio session
var success = self.audioSession.setActive(true, error: &activeError)
if !success {
println("error making audio session active :\(activeError)")
}
}
func configureAudioPlayer() {
// Lay song path
var songPath = NSBundle.mainBundle().pathForResource("Open Source - Sending My Signal", ofType: "mp3")
// Chuyen thanh URL
println("songpath: \(songPath)")
var songURL = NSURL(fileURLWithPath: songPath!)
println("songURL: \(songURL)")
//
var songError:NSError?
// Tao audioplayer
self.player = AVAudioPlayer(contentsOfURL: songURL!, error: &songError)
println("songerror:\(songError)")
self.player.numberOfLoops = 0
}
After that i finish my button press function like this:
#IBAction func startGameButtonPressed() {
self.configureAudioSession()
self.configureAudioPlayer()
self.player.play()
}
Every thing's working fine , I can saw the southPath although my button is working but I cannot hear the sound. I still use these steps on IOS app and it's working fine. May be we can't play a sound effect on Watchkit at this time? If we can, please help me to do that.
No. It is not possible to play sounds with WatchKit on the Apple Watch.
- Apple's WatchKit Evangelist
It is not currently possible to play sounds using the latest build of WatchKit.
I would suggest submitting a feature request.
YEs its possible to play a sound file in apple watch application.You need to add the sound file separately in apple watch application extension and the call the AVAudioPlayer to play the sound file.
e.g:
let path = NSBundle.mainBundle().pathForResource("coinFlip", ofType:"caf")
let fileURL = NSURL(fileURLWithPath: path!)
player = AVAudioPlayer(contentsOfURL: fileURL, error: nil)
player.prepareToPlay()
player.delegate = self
player.play()

AVFoundation playing audio in background/on lock screen in Swift

I'm trying to find a way with AVFoundation to play audio when the user is on the lock screen or if they lock the app in the middle of using my app
class ViewController: UIViewController, AVAudioPlayerDelegate {
var avPlayer: AVAudioPlayer?
var error: NSError?
... other stuff ...
func playChime(fileName: String) -> Void {
let fileURL: NSURL! = NSBundle.mainBundle().URLForResource(fileName, withExtension: "wav")
self.avPlayer = AVAudioPlayer(contentsOfURL: fileURL, error: nil)
self.avPlayer?.play()
}
... other stuff ...
}
What needs to be added to this to ensure sounds play when the user is on the lock screen as well?
To continue playing audio in the background when the device is locked or on the home screen (on Xcode 6.3):
Add to your ViewController:
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
Then in your Info.plist, add a new entry for UIBackgroundModes and set it to audio. Xcode will automatically fill it out as 'Require background modes' and 'App plays audio or streams audio/video using Airplay'