I am trying to stream the preview url Spotify provides from their Web API which is working well and I am getting correct links but they are not playing properly.
A sample url would be https://p.scdn.co/mp3-preview/757bc5732e5c92e36ea249d631120b381a4885e2?cid=e188f3e083e741659b2ef6cfb07cddbd.mp3 and I am attempting to the exact same code that is discussed in this question, and I can get it to work with the URL they provide in the question but it doesn't work with the Spotify samples. Any help would be much appreciated.
let url = URL(string: "https://p.scdn.co/mp3-preview/757bc5732e5c92e36ea249d631120b381a4885e2?cid=e188f3e083e741659b2ef6cfb07cddbd.mp3")
let playerItem:AVPlayerItem = AVPlayerItem(url: url!)
player = AVPlayer(playerItem: playerItem)
let playerLayer=AVPlayerLayer(player: player!)
playerLayer.frame=CGRect(x:0, y:0, width:10, height:50)
self.view.layer.addSublayer(playerLayer)
player.play()
The spotify preview url of of type only for 30 seconds. They can be played via AVPlayer,
import UIKit
import AVFoundation
class AudioVC : UIViewController {
var player = AVAudioPlayer()
override func viewDidLoad() {
let previewURL = "https://p.scdn.co/mp3-preview/757bc5732e5c92e36ea249d631120b381a4885e2?cid=e188f3e083e741659b2ef6cfb07cddbd.mp3"
downloadFileFromURL(url: URL(string: previewURL)!)
}
func downloadFileFromURL(url: URL){
var downloadTask = URLSessionDownloadTask()
downloadTask = URLSession.shared.downloadTask(with: url, completionHandler: {
customURL, response, error in
self.play(url: customURL!)
})
downloadTask.resume()
}
func play(url: URL) {
do {
player = try AVAudioPlayer(contentsOf: url)
player.prepareToPlay()
player.play()
}
catch{
print(error)
}}
}
Related
I want to play a sound after each network request is successful. I have some objects that I want to send to the server using a for loop. In each iteration I'm sending a request to the server and after each request is complete, I want to play a sound.
I've tried this:
for object in objects {
sendObjectToServer(object)
}
func playSound() {
let url = Bundle.main.url(forResource: "sound", withExtension: "mp3")!
let player = try! AVAudioPlayer(url)
player.play()
}
func sendObjectToServer(object: Object) {
URLSession.shared.dataTask(with url: object.url) {(data,response,error) in
DispatchQueue.main.async {
playSound() // doesn't play sound synchronously
}
}
}
Why are you using the main thread for background-related operations. Only update your UI in the Dispatch.main.async code:
Try this on a physical device (tested and worked)
import AVFoundation
for object in objects {
DispatchQueue.global(qos: .background).async {
sendObjectToServer(object)
}
}
var player: AVAudioPlayer?
func playSound() {
guard let url = Bundle.main.url(forResource: "sound", withExtension: "mp3") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
/* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
/* iOS 10 and earlier require the following line:
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
func sendObjectToServer(object: Object) {
URLSession.shared.dataTask(with url: object.url) {(data,response,error) in
// Custom Logic
playSound()
}
}
I am trying to stream a sample mp3 from a url. It is a very small sample file. However, when I press the play button nothing happens. Well, no sound plays.
I am rather new to Swift and very much a noob so here is the full View Controller as I am unsure what you might need.
import UIKit
import AVKit
import AVFoundation
import Foundation
class ViewController: UIViewController {
#IBAction func playButton(_ sender: Any) {
print("pressed")
let urlstring = "http://cdn.mos.musicradar.com/audio/samples/80s-heat-demos/AM_Eighties08_85-01.mp3"
let url = NSURL(string: urlstring)
print("the url = \(url!)")
downloadFileFromURL(url: url!)
}
override func viewDidLoad() {
// Do any additional setup after loading the view
}
func downloadFileFromURL(url:NSURL){
weak var weakSelf = self
var downloadTask:URLSessionDownloadTask
downloadTask = URLSession.shared.downloadTask(with: url as URL, completionHandler: { (URL, response, error) -> Void in
print("URL = \(URL)")
weakSelf!.plays(url: URL! as URL)
})
downloadTask.resume()
}
func plays(url:URL) {
print("playing \(url)")
do {
var playerItem = AVPlayerItem(url: url as URL)
player = AVPlayer(url : url)
player.volume = 1.0
player.play()
} catch let error as NSError {
print(error.localizedDescription)
} catch {
print("AVAudioPlayer init failed")
}
}
}
in my console I am getting this:
pressed
the url = http://cdn.mos.musicradar.com/audio/samples/80s-heat-demos/AM_Eighties08_85-01.mp3
URL = Optional(file:///private/var/mobile/Containers/Data/Application/C255E8F4-DDBA-43BB-BC33-AF71C08BBDFD/tmp/CFNetworkDownload_tm0O8v.tmp)
playing file:///private/var/mobile/Containers/Data/Application/C255E8F4-DDBA-43BB-BC33-AF71C08BBDFD/tmp/CFNetworkDownload_tm0O8v.tmp
URL = Optional(file:///private/var/mobile/Containers/Data/Application/C255E8F4-DDBA-43BB-BC33-AF71C08BBDFD/tmp/CFNetworkDownload_J1f2LF.tmp)
playing file:///private/var/mobile/Containers/Data/Application/C255E8F4-DDBA-43BB-BC33-AF71C08BBDFD/tmp/CFNetworkDownload_J1f2LF.tmp
Can anyone help me solve this? I just want to be able to play this sound on click of the button from the server not locally.
Please try to use this code for you player function.
func plays(url:URL) {
print("playing \(url)")
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
player.play()
} catch let error as NSError {
print(error.localizedDescription)
} catch {
print("AVAudioPlayer init failed")
}
}
I am developing an audio Player in swift and I need 2 buttons ( Play and Stop ) to control it. I have used the following code:
override func viewDidLoad() {
super.viewDidLoad()
let urlstring = "http://radio.spainmedia.es/wp-content/uploads/2015/12/tailtoddle_lo4.mp3"
let url = NSURL(string: urlstring)
print("the url = \(url!)")
downloadFileFromURL(url: url!)
}
func downloadFileFromURL(url:NSURL) {
var downloadTask:URLSessionDownloadTask
downloadTask = URLSession.shared.downloadTask(with: url as URL, completionHandler: { (URL, response, error) -> Void in
self.play(url: URL! as NSURL)
})
downloadTask.resume()
}
func play(url:NSURL) {
print("playing \(url)")
do {
self.SoundPlayer = try AVAudioPlayer(contentsOf: url as URL)
SoundPlayer.prepareToPlay()
SoundPlayer.volume = 1.0
SoundPlayer.play()
} catch let error as NSError {
//self.player = nil
print(error.localizedDescription)
} catch {
print("AVAudioPlayer init failed")
}
}
#IBAction func Play(_ sender: Any) {
SoundPlayer.play()
}
#IBAction func Stop(_ sender: Any) {
SoundPlayer.stop()
}
Basically, when the user opens the app, the mp3 audio file starts automatically. Therefore I have created 2 additional buttons, Start and Stop and I want to control this Audio Player with them. Would you please advice me how to do it, because now they are not connected with the Audio Player and no action is performed when I click on them.
If your objective is to just play the file while streaming it, get the Data from the URL from and then pass it to the AVAudioPlayer.
if let theURL = URL(string: "http://radio.spainmedia.es/wp-content/uploads/2015/12/tailtoddle_lo4.mp3") {
if let data = try? Data(contentsOf: theURL){
if let audioPlayer = try? AVAudioPlayer(data: data) {
print("Done")
audioPlayer.play()
} else {
print("Noo")
}
}
}
AVAudioPlayer(contentsOf: url as URL) often fails to fetch data from remote location.
You can also check other options such as AVPlayer to play your file
how can i play remote .mp3 file in my ios application?
I'm new to SWIFT/Programming &
I couldn't find an answer on my question, that's why I'm gonna give it a try here:
HOW Do I download a video (mp4) from an URL and store it within the app**
HOW Do I display the video then in a container**
I've already found this topic:
Swift - Downloading video with downloadTaskWithURL
But in my case, I wouldn't want the video to be safed in the camera-roll. Just within the app.
Thanks for any kind of help/hint !
You can use URLSession's dataTask or downloadTask to download any file from url(if it's downloadble)
Here's the way to use dataTask for downloading:
let videoUrl = "Some video url"
let docsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let destinationUrl = docsUrl.appendingPathComponent("MyFileSaveName.mp4")
if(FileManager().fileExists(atPath: destinationUrl.path)){
print("\n\nfile already exists\n\n")
}
else{
//DispatchQueue.global(qos: .background).async {
var request = URLRequest(url: URL(string: videoUrl)!)
request.httpMethod = "GET"
_ = session.dataTask(with: request, completionHandler: { (data, response, error) in
if(error != nil){
print("\n\nsome error occured\n\n")
return
}
if let response = response as? HTTPURLResponse{
if response.statusCode == 200{
DispatchQueue.main.async {
if let data = data{
if let _ = try? data.write(to: destinationUrl, options: Data.WritingOptions.atomic){
print("\n\nurl data written\n\n")
}
else{
print("\n\nerror again\n\n")
}
}//end if let data
}//end dispatch main
}//end if let response.status
}
}).resume()
//}//end dispatch global
}//end outer else
Now to play the saved file:
class MyViewController: UIViewController {
override func viewDidLoad() {
let baseUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let assetUrl = baseUrl.appendingPathComponent("MyFileSaveName.mp4")
let url = assetUrl
print(url)
let avAssest = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: avAssest)
let player = AVPlayer(playerItem: playerItem)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true, completion: {
player.play()
})
}
}
However, most sites do not provide a direct dwonloadable link for video. You can get that link by playing the video in a UIWebView and register this following observer to get that link:
NotificationCenter.default.addObserver(self, selector: #selector(videoPlayedInWebView), name: NSNotification.Name(rawValue: "AVPlayerItemBecameCurrentNotification"), object: nil)
#objc func videoPlayedInWebView(aNotification: NSNotification) {
if let playerItem: AVPlayerItem = aNotification.object as? AVPlayerItem{
let asset: AVURLAsset = playerItem.asset as! AVURLAsset
var downloadebaleVideoUrl = asset.url
print(downloadebaleVideoUrl)
}
}
Here "downloadebaleVideoUrl" is the link that will be generated once the video plays in the webview.
If you have any questions, feel free to ask.
Note: This is will work only for sites that have mp4 files. 'HLS' streams won't be downloaded with this method. For that you can refer to this following answer:
https://stackoverflow.com/a/54493233/10758374
Edit: this works only with UIWebView and it won't work with WKWebView.
You need to create a local url, that will be a path in your app's file system and write the video's data into it.
func writeToFile(urlString: String) {
guard let videoUrl = URL(string: urlString) else {
return
}
do {
let videoData = try Data(contentsOf: videoUrl)
let fm = FileManager.default
guard let docUrl = fm.urls(for: .documentDirectory, in: .userDomainMask).first else {
print("Unable to reach the documents folder")
return false
}
let localUrl = docUrl.appendingPathComponent("test.mp4")
try videoData.write(to: localUrl)
} catch {
print("could not save data")
}
}
Keep in mind to always call this function in the background thread.
here is my code of how im playing my mp3 from a live url i just cannot find any updated information for swift to use avplayer not avaudioplayer.. thank you in advance to all comments and helpers
var playerItem:AVPlayerItem?
var player = AVPlayer()
var error : NSError?
var sucess : Bool?
do{
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback,withOptions: .DefaultToSpeaker)
_ = try AVAudioSession.sharedInstance().setActive(true)
sucess = true
} catch let NotSucessError as NSError{error = NotSucessError
sucess = false}
if !sucess! {
NSLog("Fail to set audio session. Error:\(error)")
}
let url = NSURL(string: trackURL)
playerItem = AVPlayerItem(URL: url!)
player = AVPlayer(playerItem: playerItem!)
player.play()