Audio Information of Current Track iOS Swift
Here is example function to get audio Info:
import MediaPlayer
var url:NSURL!
let audioInfo = MPNowPlayingInfoCenter.defaultCenter()
var nowPlayingInfo:[NSObject:AnyObject] = [:]
func fetchMP3Info() {
let playerItem = AVPlayerItem(URL: url) //this will be your audio source
println(url.path!)
let metadataList = playerItem.asset.metadata as! [AVMetadataItem]
for item in metadataList {
if item.commonKey != nil && item.value != nil {
if item.commonKey == "title" {
println(item.stringValue)
nowPlayingInfo[MPMediaItemPropertyTitle] = item.stringValue
}
if item.commonKey == "type" {
println(item.stringValue)
nowPlayingInfo[MPMediaItemPropertyGenre] = item.stringValue
}
if item.commonKey == "albumName" {
println(item.stringValue)
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = item.stringValue
}
if item.commonKey == "artist" {
println(item.stringValue)
nowPlayingInfo[MPMediaItemPropertyArtist] = item.stringValue
}
if item.commonKey == "artwork" {
if let image = UIImage(data: item.value as! NSData) {
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(image: image)
println(image.description)
}
}
}
}
audioInfo.nowPlayingInfo = nowPlayingInfo
}
Hope this will help.
Detecting which audio track is playing on device in iOS Swift
The short answer is no.
You may be able to retrieve song information from the iTunes library (if it's not a shared song using Home Sharing). Read about MPMusicPlayerController for more information. Specially the nowPlayingItem
is probably what you're looking for.
However, most third-party applications such as Spotify, Deezer or Pandora will most likely have implemented their own player, which does not integrate with the iPod music player. This blog post also covers some of the details.
Get audio metadata from current playing audio in iTunes on OS X
Here's a simple example how to get the properties from the current track:
Tested on (El Capitan v10.11.5
, iTunes 12.4 and Xcode 7.3).
import Cocoa
import ScriptingBridge
@objc protocol iTunesApplication {
optional func currentTrack()-> AnyObject
optional var properties: NSDictionary {get}
//if you need another object or method from the iTunes.h, you must add it here
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) {
let iTunesApp: AnyObject = SBApplication(bundleIdentifier: "com.apple.iTunes")!
let trackDict = iTunesApp.currentTrack!().properties as Dictionary
if (trackDict["name"] != nil) {// if nil then no current track
print(trackDict["name"]!) // print the title
print(trackDict["artist"]!)
print(trackDict["album"]!)
print(trackDict["playedCount"]!)
// print(trackDict) // print the dictionary
}
}
}
How to get another app's currently playing audio
This isn't currently possible in iOS. Just changing your AVAudioSession
category options to .MixWithOthers
, what will be an option to get info Song Info from other apps, causes your nowPlayingInfo
to be ignored.
iOS only considers non-mixing apps for inclusion in MPNowPlayingInfoCenter
, because there is uncertainty as to which app would show up in (e.g.) Control Center if there are multiple mixing apps playing at the same time.
Proposal: An option would be to use a music fingerprinting algorithm to recognize what is being played by recording it from your App.
Some interesting projects in this direction:
Gracenote https://developer.gracenote.com/ Gracenote (which is owned by Sony) has opened up it's SDKs and APIs and has a proper dev portal.
EchoNest & Spotify API http://developer.echonest.com/ Fusioned with Spotify since March 2016
ACRCloud https://www.acrcloud.com/ offers ACR solutions for custom files such as TV commercials, music tec
Using Swift to display title of currently playing .MP3
you need to add the import statement for Media player and set the
General Media Item Property Keys
for nowPlayingInfo property. For the MPMediaItemPropertyArtwork you need to take a look at this MPMediaItemArtwork
import MediaPlayer
let audioInfo = MPNowPlayingInfoCenter.defaultCenter()
let audioName = audioPath.lastPathComponent!.stringByDeletingPathExtension
audioInfo.nowPlayingInfo = [ MPMediaItemPropertyTitle: audioName, MPMediaItemPropertyArtist:"artistName"]
To extract the metadata from your mp3 you need to create an AVPlayerItem and access its asset commonMetadata property
let playerItem = AVPlayerItem(URL: audioPath)
let metadataList = playerItem.asset.commonMetadata as! [AVMetadataItem]
for item in metadataList {
if item.commonKey == "title" {
println("Title = " + item.stringValue)
}
if item.commonKey == "artist" {
println("Artist = " + item.stringValue)
}
}
Note: You will have to invoke beginReceivingRemoteControlEvents() otherwise it will not work on the actual device.
override func viewDidLoad() {
super.viewDidLoad()
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
}
How to get Track Id from m4a audio file in swift 5.3
You've already got the track number in trackItems
. However it should be a dataValue
, not a stringValue
.
For one of my tracks I see 8 bytes of what looks like 4 16bit big endian integers:
0x00000008000e0000
Mine is track 8 of 14, so I guess you want the 2nd integer.
Here's more anecdotal evidence of the above:
https://lists.apple.com/archives/cocoa-dev/2009/Oct/msg00952.html
You could do what you want using this (note the symbols for the keySpace/key
s):
if let trackItem = AVMetadataItem.metadataItems(from: metadata, filteredByIdentifier: .iTunesMetadataTrackNumber).first,
let data = trackItem.dataValue,
data.count == 8 {
let bytes = [UInt8](data)
let trackNumber = ((Int)(bytes[2]) << 8) | (Int)(bytes[3])
let totalTracks = ((Int)(bytes[4]) << 8) | (Int)(bytes[5])
print("trackNumber: \(trackNumber)/\(totalTracks)")
}
N.B.: it's different for mp3/ID3 in which case you'll want id3/TRCK
& it's a stringValue
containing an integer.
Swift iOS, Play tracks sequentially from array using AVAudioPlayer, with some function in between each track?
The approach using audioPlayerDidFinishPlaying(_:,successfully:)
is correct. In your code when you call playScript(c:)
you will iterate through all audio files from conditions
array and call startRecord
method really quickly, while first audio is playing. All sounds will be placed in a queue and play one by one. I don't know contents of startRecord
method, but I don't think that it was supposed to be called like that.
In order to avoid those problems you need to call playScript(c:)
and then wait for method startRecord()
to finish, and then call playScript(c:)
again. So you can try something like this:
import AVFoundation
class SomeClass: NSObject, AVAudioPlayerDelegate {
var player: AVAudioPlayer?
var conditions = [String]()
var instructions: [() -> ()] = []
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("finished playing \(player.url)")
startRecord {
playNextInstruction()
}
}
func playScript(c: String)
{
let path = Bundle.main.path(forResource: c, ofType:"m4a")!
let url = URL(fileURLWithPath: path)
do {
self.player = try AVAudioPlayer(contentsOf: url)
self.player?.delegate = self
self.player?.play()
print(c)
print("playing script for " + c)
} catch {
print("couldn't load script")
}
}
func beginTest() {
instructions = conditions.shuffled().map { [unowned self] condition in
return {
self.playScript(c: condition)
}
}
playNextInstruction()
}
func playNextInstruction() {
if instructions.count != 0 {
instructions.remove(at: 0)()
} else {
exportData()
}
}
func exportData() {
}
func startRecord(completion: (() -> ())) {
}
}
If it won't work then I suggest to try searching problem somewhere else in your code.
How to track when song is finished AVAudioPlayer
I solved my problem with help of Leo Dabus.
I changed my edited code. I moved player?.delegate = self
to playSound
func. Finally, it is working.
playSound & audioPlayerDidFinishPlaying function:
func playSound(name: String ) {
guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else {
print("url not found")
return
}
do {
/// this codes for making this app ready to takeover the device audio
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
/// change fileTypeHint according to the type of your audio file (you can omit this)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
player?.delegate = self
// no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
player!.play()
} catch let error as NSError {
print("error: \(error.localizedDescription)")
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("finished")//It is working now! printed "finished"!
}
Do not forget to add AVAudioPlayerDelegate
to ViewController!
class ViewController: UIViewController,AVAudioPlayerDelegate {
How to automatically go to the next track when the one is currently playing ends?
You should use AVAudioPlayer
delegate method audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool)
which is called when the audio player finishes playing a sound.
Make your
PlayerViewController
confirm toAVAudioPlayerDelegate
protocol like this:class PlayerViewController: UIViewController, AVAudioPlayerDelegate {
Make sure to set
self
as the delegate of the audioPlayer you create, to do that in yourviewDidLoad
,previousAction
andnextTrack
method you need to addaudioPlayer.delegate = self
after this line:
audioPlayer = try AVAudioPlayer(contentsOfURL: mp3URL)
Now you can use the delegate method to know when the audio is finished playing and go to the next track, just add this inside your class:
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
if flag {
self.nextTrack()
} else {
// did not finish successfully
}
}
Related Topics
Is There Really No Way to Style Sklabelnode
Uibezierpath Subclass Initializer
How to Work with Udp Sockets in iOS, Swift
Screen Recording When My iOS App Is in Background with Replaykit
Delete Image from Photo Gallery
Extending a Delegate from a Base Class
How to Update iOS 14 Widget Background Color from the App
iOS App Crashes on Phone But Works Fine on Simulator
How to Add Followed Text to Uitextfield
Iad Interstitials Not Showing Consistently? and Not at All on the Simulator
Swiftui Animation and Subsequent Reverse Animation to Original State
Swift 3 - Passing Data Between a View Controller and After That to Another 2
Outline Uilabel Text in Uilabel Subclass
iOS Uiimagepickercontroller: Any Way of Getting the Date of the Chosen Picture
Swift 3 - Loading Multiple Viewcontrollers at Launch
Swiftui - Scrollviewreader's Scrollto Does Not Scroll
Swift Computed Properties Cannot Be Used in Init
How to Send Request from iOS (Swift) to Dialogflow V2 API Without Cloud Functions