Construire un lecteur MP3 avec AV Foundation

Ce que vous allez créer

Fondation AV est un framework pour travailler avec les médias audio et visuels sur iOS et OSX. Grâce à AV Foundation, vous pouvez lire, capturer et encoder des données multimédia. Il s’agit d’un cadre assez complet et dans le cadre de ce tutoriel, nous nous concentrerons sur la partie audio. Plus précisément, nous utiliserons le AVAudioPlayer classe pour lire des fichiers MP3.

Projet de démarrage

J'ai fourni un projet de démarrage dans lequel toutes les actions et les prises sont déjà configurées, avec les méthodes appropriées stubées. Les classes utilisées par le projet sont déjà écrites afin que nous puissions plonger dans le code. Vous pouvez télécharger le projet de démarrage depuis GitHub.

1. Lier le cadre AV Foundation

Avant de pouvoir utiliser AV Foundation, vous devez lier le projet à la structure. dans le Navigateur de projet, assurez-vous que votre projet est sélectionné. Sous le Général onglet, allez à Cadres et bibliothèques liés et à partir de là vous choisissez AVFoundation.framework.

2. FileReader Classe

Dans le projet de démarrage, vous trouverez un fichier nommé FileReader.swift. Ouvrez ce fichier pour voir son contenu.

importer la classe UIKit FileReader: NSObject 

Il s'agit d'un simple module de la classe que nous utiliserons pour lire les fichiers à partir du disque. Il hérite de NSObject. Nous allons implémenter une méthode, readFiles, qui sera une méthode type. Les méthodes de type vous permettent d'appeler une méthode sur la classe elle-même, le type, par opposition à une instance de la classe. Ci-dessous, la mise en œuvre de la readFiles méthode.

class func readFiles () -> [String] return NSBundle.mainBundle (). pathForResourcesOfType ("mp3", inDirectory: nil) en tant que! [Chaîne] 

Le paquet principal contient le code et les ressources pour votre projet, et c’est ici que nous allons trouver les MP3. Nous utilisons la méthode pathForResourcesOfType (_: inDirectory :) méthode, qui retourne un tableau contenant les noms de chemins pour le type de ressource spécifié. Dans ce cas, nous recherchons le type "mp3". Parce que nous ne sommes pas intéressés par un répertoire spécifique, nous passons néant.

Cette classe sera utilisée par le Lecteur mp3 classe, sur laquelle nous travaillerons ensuite.

3. Lecteur mp3 Classe

Ensuite, ouvrez MP3Player.swift et voir son contenu.

import UIKit import Classe AVFoundation MP3Player: NSObject, AVAudioPlayerDelegate 

Notez que nous adoptons le AVAudioPlayerDelegate protocole. Ce protocole déclare un certain nombre de méthodes utiles, dont l’une est audioPlayerDidFinishPlaying (_: avec succès :). En mettant en œuvre le audioPlayerDidFinishPlaying (_: avec succès :) méthode, nous serons avertis lorsque la lecture du fichier audio sera terminée.

Étape 1: Propriétés

Ajouter ce qui suit à MP3Player.swift.

class MP3Player: NSObject, AVAudioPlayerDelegate var player: AVAudioPlayer? var currentTrackIndex = 0 pistes de var: [String] = [String] ()

le joueur la propriété sera une instance de la AVAudioPlayer classe, que nous utiliserons pour lire, mettre en pause et arrêter les MP3. le currentTrackIndex variable garde la trace du MP3 en cours de lecture. Finalement, le des pistes variable sera un tableau des chemins d'accès à la liste des fichiers MP3 inclus dans l'offre de l'application.

Étape 2: init

remplacer init () pistes = FileReader.readFiles () super.init () queueTrack (); 

Lors de l’initialisation, nous invoquons le FileReaderde readFiles méthode pour récupérer les chemins des fichiers MP3 et stocker cette liste dans le des pistes tableau. Comme il s’agit d’un initialiseur désigné, nous devons appeler le init méthode de la superclasse. Enfin, nous appelons queueTrack, que nous écrirons ensuite.

Étape 3: queueTrack

Ajouter l'implémentation suivante pour le queueTrack méthode à la Lecteur mp3 classe.

func queueTrack () if (player! = nil) player = nil erreur var: NSError? let url = NSURL.fileURLWithPath (pistes [currentTrackIndex] en tant que chaîne) player = AVAudioPlayer (contentsOfURL: url, erreur: & erreur) si let hasError = erreur // SHOW ALERT OR SOMETHING else player? .delegate = self player ?. prepareToPlay ()

Parce que nous allons instancier une nouvelle AVAudioPlayer Par exemple, chaque fois que cette méthode est appelée, nous effectuons un petit entretien en définissant joueur à néant.

Nous déclarons une option NSError et une constante url. Nous invoquons fileURLWithPath (_ :) chercher le chemin du MP3 actuel et stocker la valeur dans url. Nous passons le des pistes tableau en tant que paramètre utilisant currentTrackIndex comme indice. N'oubliez pas que le tableau de pistes contient les chemins d'accès aux fichiers MP3 et non une référence aux fichiers MP3 eux-mêmes..

Instancier le joueur, nous passons le url constante et Erreur variable dans le AVAudioPlayerest l'initialiseur. En cas d'échec de l'initialisation, le Erreur la variable est remplie avec une description de l'erreur.

Si nous ne rencontrons pas d'erreur, le délégué du joueur est défini sur soi et invoquer le prepareToPlay méthode sur le joueur. le prepareToPlay La méthode précharge les tampons et acquiert le matériel audio, ce qui minimise les retards lors de l'appel du jouer méthode.

Étape 4: jouer

le jouer La méthode vérifie d’abord si le son joue déjà ou non en vérifiant le nom approprié en jouant propriété. Si le son ne joue pas, il appelle la jouer méthode du joueur propriété.

 func play () si joueur? .playing == faux joueur? .play ()

Étape 5: Arrêtez

le Arrêtez La méthode vérifie d’abord si le lecteur audio est déjà en cours de lecture. Si c'est le cas, il invoque le Arrêtez méthode et définit le heure actuelle propriété à 0. Lorsque vous invoquez le Arrêtez méthode, il arrête simplement l'audio. Cela ne réinitialise pas l'audio au début, c'est pourquoi nous devons le faire manuellement.

func stop () si joueur? .playing == vrai joueur? .stop () joueur? .currentTime = 0

Étape 6: pause

Comme le Arrêtez méthode, nous vérifions d’abord si le lecteur audio est en train de jouer. Si c'est le cas, nous invoquons le pause méthode.

 func pause () si joueur? .playing == vrai joueur? .pause ()

Étape 7: prochaine chanson

le nextSong (_: Bool) met en file d'attente la chanson suivante et, si le lecteur est en train de jouer, la reproduit. Nous ne voulons pas que la prochaine chanson soit lue si le joueur est en pause. Cependant, cette méthode est également appelée à la fin du morceau. Dans ce cas, nous voulons jouer la chanson suivante, qui correspond au paramètre songFinishedPlaying est pour.

func nextSong (songFinishedPlaying: Bool) var playerWasPlaying = false si player? .playing == true player? .stop () playerWasPlaying = true currentTrackIndex ++ si currentTrackIndex> = tracks.count currentTrackIndex = 0 queueTrack) | songFinishedPlaying player? .play ()

le playerWasPlaying La variable est utilisée pour indiquer si le joueur jouait ou non lorsque cette méthode a été invoquée. Si la chanson jouait, nous invoquons le Arrêtez méthode sur le joueur Et mettre playerWasPlaying à vrai.

Ensuite, nous incrémentons le currentTrackIndex et vérifier pour voir s'il est supérieur ou égal à pistes.count. le compter La propriété d'un tableau nous donne le nombre total d'éléments dans le tableau. Nous devons nous assurer que nous n'essayons pas d'accéder à un élément qui n'existe pas dans le des pistes tableau. Pour éviter cela, nous avons défini currentTrackIndex retour au premier élément du tableau si c'est le cas.

Enfin, nous invoquons queueTrack pour obtenir la prochaine chanson prête et jouer cette chanson si soit playerWasPlaying ou songFinishedPlaying est vrai.

Étape 8: précédentSong

le précédentSong méthode fonctionne très similaire à prochaine chanson. La seule différence est que nous décrémentons la currentTrackIndex et vérifier si elle est égale à 0. Si c'est le cas, on le met à l'index du dernier élément du tableau.

func previousSong () var playerWasPlaying = false si player? .playing == true player? .stop () playerWasPlaying = true currentTrackIndex-- si currentTrackIndex < 0  currentTrackIndex = tracks.count - 1  queueTrack() if playerWasPlaying  player?.play()   

En utilisant à la fois le prochaine chanson et précédentSong méthodes, nous pouvons parcourir tous les fichiers MP3 et recommencer lorsque nous arrivons au début ou à la fin de la liste.

Étape 9: getCurrentTrackName

le getCurrentTrackName méthode obtient le nom du MP3 sans l'extension.

func getCurrentTrackName () -> String let TrackName = pistes [currentTrackIndex] .lastPathComponent.stringByDeletingPathExtension return trackName

Nous obtenons une référence à tout ce que le MP3 actuel est en utilisant pistes [currentTrackIndex]. Rappelez-vous cependant que ce sont les chemins d'accès aux fichiers MP3 et non les fichiers eux-mêmes. Les chemins sont assez longs, car c’est le chemin complet des fichiers MP3.

Sur ma machine, par exemple, le premier élément de la des pistes tableau est égal à "/Users/jamestyner/Library/Developer/CoreSimulator/Devices/80C8CD34-22AE-4F00-862E-FD41E2D8D6BA". Ce chemin serait différent sur un appareil réel bien sûr.

Nous avons une grande chaîne contenant le chemin d'accès au fichier MP3, mais nous souhaitons simplement connaître le nom du fichier MP3 lui-même. le NSString La classe définit deux propriétés qui peuvent nous aider. Comme son nom l'indique, le lastPathComponent propriété retourne le dernier composant d'un chemin. Comme vous l'avez peut-être deviné, le stringByDeletingPathExtension propriété supprime l'extension.

Étape 10: getCurrentTimeAsString

le getCurrentTimeAsString méthode utilise le heure actuelle propriété du joueur exemple et le renvoie sous forme de chaîne lisible par l’homme (par exemple,., 1:02).

 func getCurrentTimeAsString () -> Chaîne var secondes = 0 var minutes = 0 si le temps = player? .currentTime secondes = Int (heure)% 60 minutes = (Int (heure) / 60)% 60 retourne Chaîne (format : "% 0.2d:% 0.2d", minutes, secondes)

le heure actuelle propriété est de type NSTimeInterval, qui est juste un typealias pour un Double. Nous utilisons des mathématiques pour obtenir le secondes et minutes, en nous assurant de convertir temps à un Int puisque nous devons travailler avec des nombres entiers. Si vous ne connaissez pas l'opérateur représentant le reste (%), il trouve le reste après la division d'un nombre par un autre. Si la temps variable était égale à 65, puis secondes serait égal à 5 parce que nous utilisons 60.

Étape 11: getProgress

le getProgress méthode est utilisée par le UIProgressView exemple pour donner une indication de la quantité de MP3 jouée. Ce progrès est représenté par une valeur de 0.0 à 1,0 comme un Flotte.

 func getProgress () -> Float var theCurrentTime = 0.0 var theCurrentDuration = 0.0 si currentTime = player? .currentTime, duration = player? .duration theCurrentTime = currentTime theCurrentDuration = duration renvoie Float (theCurrentTime / theCurrentDuration).

Pour obtenir cette valeur, nous divisons le joueurde heure actuelle propriété par le joueurde durée propriété, nous stockons ces valeurs dans les variables l'heure actuelle et la durée actuelle. Comme heure actuelle, la durée propriété est de type NSTimeInterval et il représente la durée de la chanson en secondes.

Étape 12: setVolume

le setVolume (_: Float) méthode invoque le setVolume méthode du joueur exemple.

func setVolume (volume: Float) player? .volume = volume 

Étape 13: audioPlayerDidFinishPlaying (_: avec succès :)

le audioPlayerDidFinishPlaying (_: avec succès :) méthode est une méthode de la AVAudioPlayerDelegate protocole. Cette méthode prend comme paramètres la AVAudioPlayer exemple et un booléen. Le booléen est réglé sur vrai si le lecteur audio a fini de jouer la chanson en cours.

func audioPlayerDidFinishPlaying (lecteur: AVAudioPlayer, indicateur réussi: Bool) si indicateur == true nextSong (true)

Si la chanson a fini de jouer, nous appelons le prochaine chanson méthode, passage vrai depuis que la chanson a fini de jouer tout seul.

Ceci termine la Lecteur mp3 classe. Nous y reviendrons un peu plus tard, après la mise en œuvre des actions du ViewController classe.

4. ViewController Classe

Ouvrir ViewController.swift et voir son contenu.

Import de UIKit mport Classe AVFoundation ViewController: UIViewController var mp3Player: MP3Player? var timer: NSTimer? @IBOutlet faible var trackName: UILabel! @IBOutlet faible var trackTime: UILabel! @IBOutlet faible var progressBar: UIProgressView! remplacez func viewDidLoad () super.viewDidLoad () @IBAction func playSong (expéditeur: AnyObject)  @IBAction func stopSong (expéditeur: AnyObject)  @IBAction func pauseSong (expéditeur: AnyObject)  @IBAction func playNext ( expéditeur: AnyObject)  @IBAction func setVolume (expéditeur: UISlider)  @IBAction func playPreviousSong (expéditeur: AnyObject)  écrasé func didReceiveMemoryWarning () super.didReceiveMemoryWarning () 

le lecteur mp3 variable est une instance du Lecteur mp3 classe que nous avons mis en place plus tôt. le minuteur variable sera utilisée pour mettre à jour le trackTime et barre de progression vues chaque seconde.

Dans les prochaines étapes, nous mettrons en œuvre les actions du ViewController classe. Mais d’abord, nous devrions instancier le Lecteur mp3 exemple. Mettre à jour la mise en œuvre de la viewDidLoad méthode comme indiqué ci-dessous.

remplacer la fonction viewDidLoad () super.viewDidLoad () mp3Player = MP3Player () 

Étape 1: playSong (_: AnyObject)

Entrez ce qui suit dans le playSong (_: AnyObject) méthode.

@IBAction func playSong (expéditeur: AnyObject) mp3Player? .Play ()

Dans cette méthode, nous appelons le jouer méthode sur le lecteur mp3 objet. Nous sommes à un point où nous pouvons commencer à tester l'application maintenant. Exécutez l'application et appuyez sur le bouton de lecture. La chanson devrait commencer à jouer.

Étape 2: stopSong (_: AnyObject)

le stopSong (_: AnyObject) méthode appelle la méthode stop sur le lecteur mp3 objet.

 @IBAction func stopSong (expéditeur: AnyObject) mp3Player? .Stop ()

Exécutez l'application à nouveau et appuyez sur le bouton de lecture. Vous devriez maintenant pouvoir arrêter la chanson en appuyant sur le bouton d'arrêt.

Étape 3: pauseSong (_: AnyObject)

Comme vous l'avez peut-être deviné, le pauseSong (_: AnyObject) méthode invoque le pause méthode sur le lecteur mp3 objet.

@IBAction func pauseSong (expéditeur: AnyObject) mp3Player? .Pause ()

Étape 4: playNextSong (_: AnyObject)

IBAction func playNextSong (expéditeur: AnyObject) mp3Player? .NextSong (false)

Dans playNextSong (_: AnyObject), nous invoquons le prochaine chanson méthode sur le lecteur mp3 objet. Notez que nous passons faux en tant que paramètre, car la chanson n'a pas fini de jouer d'elle-même. Nous commençons manuellement la chanson suivante en appuyant sur le bouton suivant.

Étape 5: previousSong (_: AnyObject)

 @IBAction func playPreviousSong (expéditeur: AnyObject) mp3Player? .PreviousSong ()

Comme vous pouvez le constater, la mise en œuvre de la previousSong (_: AnyObject) méthode est très similaire à celle de nextSong (_: AnyObject). Tous les boutons du lecteur MP3 devraient être opérationnels maintenant. Si vous n'avez pas encore testé l'application, ce serait le bon moment pour vous assurer que tout fonctionne comme prévu.

Étape 6: setVolume (_: UISlider)

le setVolume (_: UISlider) méthode invoque le setVolume méthode sur le lecteur mp3 objet. La propriété volume est de type Flotte. La valeur va de 0.0 à 1,0. le UISlider l'objet est mis en place avec 0.0 comme valeur minimale et 1,0 comme valeur maximale.

 @IBAction func setVolume (expéditeur: UISlider) mp3Player? .SetVolume (sender.value)

Exécutez l'application une fois de plus et jouez avec le curseur de volume pour vérifier que tout fonctionne correctement.

Étape 7: startTimer

le startTimer méthode instancie un nouveau NSTimer exemple.

 func startTimer () timer = NSTimer.scheduledTimerWithTimeInterval (1.0, cible: self, sélecteur: Selector ("updateViewsWithTimer:"), userInfo: nil, répète: true)

le scheduleTimerWithTimeInterval (_: cible: sélecteur: utilisateurInfo: répète :) initializer prend en paramètre le nombre de secondes entre le déclenchement de la minuterie, l’objet auquel appeler une méthode spécifiée par sélecteur, la méthode appelée lors du déclenchement de la minuterie, option informations utilisateur dictionnaire, et si le chronomètre se répète jusqu'à ce qu'il soit invalidé.

Nous utilisons une méthode nommée updateViewsWithTimer (_: NSTimer) en tant que sélecteur, nous allons donc créer cette prochaine.

Étape 8: updateViewsWithTimer (_: NSTimer)

le updateViewsWithTimer (_: NSTimer) la méthode appelle le updateViews méthode, que nous allons mettre en œuvre dans la prochaine étape.

func updateViewsWithTimer (theTimer: NSTimer) updateViews ()

Étape 9: updateViews

le updateViews la méthode met à jour le trackTime et barre de progression vues.

func updateViews () trackTime.text = mp3Player? .getCurrentTimeAsString () si laisse progress = mp3Player? .getProgress () progressBar.progress = progress 

le texte propriété de trackTime est mis à jour avec le heure actuelle propriété, formatée comme une chaîne en invoquant le getCurrentTimeAsString méthode. Nous déclarons une constante le progrès en utilisant le lecteur mp3de getProgress méthode et set progressBar.progress en utilisant cette constante.

Étape 10: Câblage de la minuterie

Maintenant, nous devons appeler le startTimer méthode aux endroits appropriés. Nous devons démarrer le chronomètre dans le playSong (_: AnyObject) méthode, la playNextSong (_: AnyObject) méthode et playPreviousSong (_: AnyObject) méthode.

@IBAction func playSong (expéditeur: AnyObject) mp3Player? .Play () startTimer () 
 @IBAction func playNextSong (expéditeur: AnyObject) mp3Player? .NextSong (false) startTimer () 
@IBAction func playPreviousSong (expéditeur: AnyObject) mp3Player? .PreviousSong () startTimer () 

Étape 11: arrêt de la minuterie

Nous devons également arrêter la minuteur lorsque les boutons pause et arrêt sont enfoncés. Vous pouvez arrêter le minuteur objet en invoquant le invalider méthode sur le NSTimer exemple.

@IBAction func stopSong (expéditeur: AnyObject) mp3Player? .Stop () updateViews () timer? .Invalidate () 
@IBAction func pauseSong (expéditeur: AnyObject) mp3Player? .Pause () timer? .Invalidate ()

Étape 12: setTrackName

le setTrackName méthode définit le texte propriété de trackName en invoquant getCurrentTrackName sur le lecteur mp3 objet.

func setTrackName () trackName.text = mp3Player? .getCurrentTrackName ()

Étape 13: setupNotificationCenter

Quand une chanson est terminée, le nom de la chanson suivante doit s'afficher automatiquement et la lecture commence. De plus, lorsque l’utilisateur appuie sur les boutons de lecture, suivant ou précédent, le setTrackName méthode devrait être invoquée. Le lieu idéal pour cela est le queueTrack méthode du Lecteur mp3 classe.

Nous avons besoin d'un moyen d'avoir le Lecteur mp3 classe dire le ViewController classe à invoquer le setTrackName méthode. Pour ce faire, nous allons utiliser le NSNotificationCenter classe. Le centre de notification fournit un moyen de diffuser des informations tout au long d'un programme. En s'inscrivant en tant qu'observateur auprès du centre de notification, un objet peut recevoir ces émissions et effectuer une opération. Une autre façon d'accomplir cette tâche serait d'utiliser le modèle de délégation.

Ajoutez la méthode suivante à la ViewController classe.

 func setupNotificationCenter () NSNotificationCenter.defaultCenter (). addObserver (auto-sélecteur: "setTrackName", nom: "SetTrackNameText", objet: nil) 

Nous obtenons d’abord une référence au centre de notification par défaut. Nous invoquons ensuite le addObserver (_: sélecteur: nom: objet :) méthode sur le centre de notification. Cette méthode accepte quatre paramètres:

  • l'objet s'inscrivant en tant qu'observateur, soi dans ce cas
  • le message qui sera envoyé à l'observateur lors de la publication de la notification
  • le nom de la notification pour laquelle inscrire l'observateur
  • l'objet dont l'observateur veut recevoir les notifications

En passant dans néant comme dernier argument, nous écoutons toutes les notifications portant le nom SetTrackNameText.

Maintenant, nous devons appeler cette méthode dans le contrôleur de vue viewDidLoad méthode.

remplacer func viewDidLoad () super.viewDidLoad () mp3Player = MP3Player () setupNotificationCenter () 

Étape 14: Enregistrement de la notification

Pour poster la notification, nous invoquons le postNotificationName (_: objet :) méthode sur le centre de notification par défaut. Comme je l'ai mentionné plus tôt, nous le ferons dans le queueTrack méthode du Lecteur mp3 classe. Ouvrir MP3Player.swift et mettre à jour le queueTrack méthode comme indiqué ci-dessous.

 func queueTrack () if (player! = nil) player = nil erreur var: NSError? let url = NSURL.fileURLWithPath (pistes [currentTrackIndex] en tant que chaîne) player = AVAudioPlayer (contentsOfURL: url, erreur: & erreur) si let hasError = erreur // SHOW ALERT OR SOMETHING else player? .delegate = self player ?. prepareToPlay () NSNotificationCenter.defaultCenter (). postNotificationName ("SetTrackNameText", objet: nil)

Si vous testez l'application maintenant et laissez une chanson jouer en boucle, la lecture de la chanson suivante devrait commencer automatiquement. Mais vous vous demandez peut-être pourquoi le nom de la chanson n’apparaît pas lors de la première chanson. le init méthode du Lecteur mp3 la classe appelle le queueTrack méthode, mais comme elle n’a pas fini de s’initialiser, elle n’a aucun effet.

Tout ce que nous avons à faire est d’appeler manuellement le setTrackName méthode après avoir initialisé le lecteur mp3 objet. Ajoutez le code suivant au viewDidLoad méthode en ViewController.swift.

 remplacer func viewDidLoad () super.viewDidLoad () mp3Player = MP3Player () setupNotificationCenter () setTrackName () updateViews ()

Vous remarquerez que j'ai aussi appelé le updateViews méthode. De cette façon, le joueur affiche un temps de 0:00 au début. Si vous testez l'application maintenant, vous devriez avoir un lecteur MP3 entièrement fonctionnel..

Conclusion

Ce didacticiel était plutôt long, mais vous avez maintenant un lecteur MP3 fonctionnel sur lequel vous pouvez construire et développer. Une suggestion est de permettre à l’utilisateur de choisir une chanson à jouer en mettant en œuvre un UITableView en dessous du joueur. Merci d'avoir lu et j'espère que vous avez appris quelque chose d'utile.