Player for streaming local and remote audio files. Written in Swift.

Related tags

Streaming Jukebox
Overview

Jukebox: audio player in Swift

Swift3 Platform Build Status Version Carthage Compatible License

Jukebox is an iOS audio player written in Swift.

Contents

  1. Features
  2. Installation
  3. Supported OS & SDK versions
  4. Usage
  5. Handling remote events
  6. Public interface
  7. Delegation
  8. License
  9. Contact

## Features

  • Support for streaming both remote and local audio files
  • Support for streaming live audio feeds
  • Functions to play, pause, stop, replay, play next, play previous, control volume and seek to a certain second.
  • Background mode integration with MPNowPlayingInfoCenter

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects.

CocoaPods 0.36 adds supports for Swift and embedded frameworks. You can install it with the following command:

$ gem install cocoapods

To integrate Jukebox into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'Jukebox'

Then, run the following command:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate Jukebox into your Xcode project using Carthage, specify it in your Cartfile:

github "teodorpatras/Jukebox"

Run carthage update to build the framework and drag the built Jukebox.framework into your Xcode project.

Manually

If you prefer not to use either of the aforementioned dependency managers, you can integrate Jukebox into your project manually.

## Supported OS & SDK versions

  • iOS 8.0+
  • Xcode 7+

## Usage

Prerequisites

  • In order to support background mode, append the following to your Info.plist:
<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
</array>
  • If you want to stream from http:// URLs, append the following to your Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
        <true/>
</dict>

Getting started

  1. Create an instance of Jukebox:
// configure jukebox
jukebox = Jukebox(delegate: self, items: [
    JukeboxItem(URL: NSURL(string: "http://www.noiseaddicts.com/samples_1w72b820/2514.mp3")!),
    JukeboxItem(URL: NSURL(string: "http://www.noiseaddicts.com/samples_1w72b820/2958.mp3")!)
    ])
  1. Play and enjoy:
jukebox?.play()

## Handling remote events

In order to handle remote events, you should do the following:

  • First, you need to call for receiving remote events:

UIApplication.sharedApplication().beginReceivingRemoteControlEvents()

  • Secondly, override remoteControlReceivedWithEvent(event:):
override func remoteControlReceived(with event: UIEvent?) {
    if event?.type == .remoteControl {
        switch event!.subtype {
        case .remoteControlPlay :
            jukebox.play()
        case .remoteControlPause :
            jukebox.pause()
        case .remoteControlNextTrack :
            jukebox.playNext()
        case .remoteControlPreviousTrack:
            jukebox.playPrevious()
        case .remoteControlTogglePlayPause:
            if jukebox.state == .playing {
               jukebox.pause()
            } else {
                jukebox.play()
            }
        default:
            break
        }
    }
}

##Public interface

##Public methods##

/**
 Starts item playback.
*/
public func play()
    
/**
Plays the item indicated by the passed index
     
 - parameter index: index of the item to be played
*/
public func play(atIndex index: Int)
    
/**
 Pauses the playback.
*/
public func pause()
    
/**
 Stops the playback.
*/
public func stop()
    
/**
 Starts playback from the beginning of the queue.
*/
public func replay()
    
/**
 Plays the next item in the queue.
*/
public func playNext()
    
/**
 Restarts the current item or plays the previous item in the queue
*/
public func playPrevious()
    
/**
 Restarts the playback for the current item
*/
public func replayCurrentItem()
    
/**
 Seeks to a certain second within the current AVPlayerItem and starts playing
     
 - parameter second: the second to seek to
 - parameter shouldPlay: pass true if playback should be resumed after seeking
*/
public func seek(toSecond second: Int, shouldPlay: Bool = false)
    
/**
 Appends and optionally loads an item
     
 - parameter item:            the item to be appended to the play queue
 - parameter loadingAssets:   pass true to load item's assets asynchronously
*/
public func append(item: JukeboxItem, loadingAssets: Bool)

/**
 Removes an item from the play queue
    
 - parameter item: item to be removed
*/
public func remove(item: JukeboxItem)
    
/**
 Removes all items from the play queue matching the URL
     
 - parameter url: the item URL
*/
public func removeItems(withURL url : URL)

##Public properties##

Property Type Description
volume Float volume of the player
currentItem JukeboxItem object encapsulating the meta of the current player item

## Delegation

Jukebox defines a delegate protocol which you can use if you want to be announced when about custom events:

public protocol JukeboxDelegate: class {
    func jukeboxStateDidChange(_ state : Jukebox)
    func jukeboxPlaybackProgressDidChange(_ jukebox : Jukebox)
    func jukeboxDidLoadItem(_ jukebox : Jukebox, item : JukeboxItem)
    func jukeboxDidUpdateMetadata(_ jukebox : Jukebox, forItem: JukeboxItem)
}

## License

Jukebox is released under the MIT license. See the LICENSE file for details.

## Contact

You can follow or drop me a line on my Twitter account. If you find any issues on the project, you can open a ticket. Pull requests are also welcome.

Comments
  • I Added a new protocol that gets title data from streaming m3u. for radio apps

    I Added a new protocol that gets title data from streaming m3u. for radio apps

    @teodorpatras Loving jukebox - found a hacky solution to getting title metadata from a http://soundradio.hk/sound-radio.m3u stream.

    I use item.addObserver inside the registerForPlayToEndNotification() to listen for "timedMetadata". Then at the bottom of the observeValueForKeyPath() I call updateInfoCenter() and add the new title to the currentItem, (had to change the properties from private to public)

    `

    private func registerForPlayToEndNotification(withItem item: AVPlayerItem) {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidPlayToEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: item)
        item.addObserver(self, forKeyPath: "timedMetadata", options: NSKeyValueObservingOptions.New, context: nil)
    }
    
    private func unregisterForPlayToEndNotification(withItem item : AVPlayerItem) {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: AVPlayerItemDidPlayToEndTimeNotification, object: item)
        item.removeObserver(self, forKeyPath: "timedMetadata", context: nil)
    }
    
    
    override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        print("keyPath: \(keyPath)")
    
        if keyPath == "timedMetadata" {
    
            let playerItem = object
    
            for metadata in playerItem!.timedMetadata {
    
                print("metadata: \(metadata)")
    
                let info = String(format: "%@", metadata.stringValue)
                let title = "\(info) ~ "
                currentItem?.title = title
                currentItem?.artwork = UIImage(named: "album-art")
                if !info.isEmpty {
                    updateInfoCenter()
                }
                print("Now Playing: \(info)")
            }
            print("object: \(object)")
            print("change: \(change)")
            print("context: \(context)")
        }
    }
    

    `

    Then at the bottom of the updateInfoCenter() (look below) I call a new protocol method self.delegate!.jukeboxMetadataDidUpdate(item) so I can update UILabels and UITextViews in any viewcontroller with the new title!

    `

    private func updateInfoCenter() {
        guard let item = self.currentItem else {return}
    
        let title = (item.title ?? item.localTitle) ?? item.URL.lastPathComponent!
        let currentTime = item.currentTime ?? 0
        let duration = item.duration ?? 0
        let trackNumber = self.playIndex
        let trackCount = self.queuedItems.count
    
        var nowPlayingInfo : [String : AnyObject] = [
            MPMediaItemPropertyPlaybackDuration : duration,
            MPMediaItemPropertyTitle : title,
            MPNowPlayingInfoPropertyElapsedPlaybackTime : currentTime,
            MPNowPlayingInfoPropertyPlaybackQueueCount :trackCount,
            MPNowPlayingInfoPropertyPlaybackQueueIndex : trackNumber,
            MPMediaItemPropertyMediaType : MPMediaType.AnyAudio.rawValue
        ]
    
        if let artist = item.artist {
            nowPlayingInfo[MPMediaItemPropertyArtist] = artist
        }
    
        if let album = item.album {
            nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = album
        }
    
        if let img = self.currentItem?.artwork {
            nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(image: img)
        }
    
        MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = nowPlayingInfo
    
        self.delegate!.jukeboxMetadataDidUpdate(item)
    }
    

    `

    Just letting you know... maybe theres a way you can integrate this into jukeBox in a less hacky fashion. Since you know jukeBox very well.

    opened by alexrmacleod 11
  • Feature: Add ability to set custom metadata on JukeboxItem.

    Feature: Add ability to set custom metadata on JukeboxItem.

    Adds JukeboxItemMetaBuilder to allow for custom metadata to be specified for a JukeboxItem. A new public customMetaBuilder property is available on JukeboxItem; simply provide this with a builder with your custom data.

    Custom metadata takes precedence over any collected from AVMetadataItem, however a combination of the two is still evaluated and used where appropriate.

    Resolves #41.

    opened by msaps 8
  • How to handle interruptions (e.g. phone calls)?

    How to handle interruptions (e.g. phone calls)?

    Jukebox is a nice player, but when a phone call comes in, the player stops playing (as it should), but when the call ends, the player does not regain audio control...

    opened by sneps85 6
  • How to play local song - part 2.

    How to play local song - part 2.

    You suggest using NSBundle's pathForResource:ofType:

    But i still not know how to use it. Can you give some more details, like how to stick NSBundle into Jukebox.

    opened by trieulieuf9 6
  • How can I use this as a singleton instance?

    How can I use this as a singleton instance?

    How can I know my music is playing as a background music in my application? For e.g, I push from page 1 to page 2 which is my details page. I popup the music player in page2 and then play a sound (sound A). When I pop back to page 1, I still want my music is playing. When I come back to page 2 from page 1 again, I click the popup button for music player, I want it showing the current sound I was playing and show the status like 50% whatever (still sound A) but not init a new music player.

    Please advise, it sounds like use this music player as a global singleton instance but I don't know how to implement it.

    Thanks,

    opened by alexliubj 5
  • [Question] in function configureAudioSession

    [Question] in function configureAudioSession

    Hello, thank you for creating this library. We are using this in one of our app.

    private func configureAudioSession() {
    do {
                try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
                try AVAudioSession.sharedInstance().setActive(true)
            } catch {
                fatalError("Could not open the audio session, hence Jukebox is unusable!")
            }
        }
    

    I received a crash report from Fabric in this method. So, I was wondering why to use fatalError? And what will happen if we simply update this code to something like this?

    private func configureAudioSession() {
            try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            try! AVAudioSession.sharedInstance().setActive(true)
        }`
    

    If you can, please explain what will happen, thanks again for your work.

    opened by AnnieNinaJoyceV 3
  • Player resumes on its own

    Player resumes on its own

    I'm Using Jukebox to stream audio from a server. Whenever the app is paused and in the background and I get a notification from another source. It starts playing on its own! What can I do to stop that?

    opened by madlyn 2
  • Swift 3 Compatibility

    Swift 3 Compatibility

    Does the current version of Jukebox work with Swift 3? I know the commits say that it does, but I keep getting the “Use Legacy Swift Language Version” (SWIFT_VERSION) error whenever I try to compile. Any ideas?

    opened by ZiadAli 2
  • Feature: Ability to seek track to specific millisecond

    Feature: Ability to seek track to specific millisecond

    For shorter audio tracks, it can be useful to give the ability to seek to milliseconds (rather than seconds) so that the user has more granular control. Seeking to seconds on a very short audio track (such as a voice-recorded chat message which lasts only for a few seconds) can cause sliders which update based on the track's playback point to appear jumpy. Seeking to milliseconds instead allows for such UI interactions to be much smoother.

    opened by diakonos 2
  • How to get noticed when player finished?

    How to get noticed when player finished?

    How can i be notified when the player did finish playing the current item? I have a UISlider to control its progress and i have to reset the slider when the item was played to 0.0

    opened by sneps85 2
  • Validate assets shouldn't throw a fatal error when the asset returns a 404

    Validate assets shouldn't throw a fatal error when the asset returns a 404

       private func validateAsset(asset : AVURLAsset) {
            var e : NSError?
            asset.statusOfValueForKey("duration", error: &e)
            if let error = e {
                var message = "\n\n***** Jukebox fatal error*****\n\n"
                if error.code == -1022 {
                    message += "It looks like you're using Xcode 7 and due to an App Transport Security issue (absence of SSL-based HTTP) the asset cannot be loaded from the specified URL: \"\(self.URL)\".\nTo fix this issue, append the following to your .plist file:\n\n<key>NSAppTransportSecurity</key>\n<dict>\n\t<key>NSAllowsArbitraryLoads</key>\n\t<true/>\n</dict>\n\n"
                    fatalError(message)
                } else {
                    fatalError("\(message)\(error.description)\n\n")
                }
            }
        }
    

    Is the error is a 404 - a fatalError, which crashes a device, shouldn't be thrown. A log message would make more sense.

    Do you agree? If so, I'll submit a PR.

    opened by samuelbeek 2
  • fix: seek method did notify delegate to early

    fix: seek method did notify delegate to early

    When seeking the jukebox didn't wait for AVPlayer to finish seeking before notifying delegate. When delegate receives this message, progress is still on state before seeking.

    AVPlayer offers a method with completionBlock, which is called when seeking is finished. Using this completionBlock to notify the delegate resolves some issues with seeking.

    opened by rabrschmidt 0
Owner
Teo
✈️ 🌏
Teo
Camera and Microphone streaming library via RTMP, HLS for iOS, macOS, tvOS.

HaishinKit Camera and Microphone streaming library via RTMP, HLS for iOS, macOS, tvOS. Issuesの言語は、日本語が分かる方は日本語でお願いします! Sponsored with ?? by Enterprise

shogo4405 2.4k Jan 2, 2023
Syntax sugar of OpenTok iOS SDK with Audio/Video communication including screen sharing

Accelerator Core iOS The Accelerator Core is a solution to integrate audio/video communication to any iOS applications via OpenTok platform. Accelerat

OpenTok 30 Nov 8, 2022
A fast and extensible gapless AudioPlayer/AudioStreamer for OSX and iOS (iPhone, iPad)

StreamingKit StreamingKit (formally Audjustable) is an audio playback and streaming library for iOS and Mac OSX. StreamingKit uses CoreAudio to decomp

Thong Nguyen 2.3k Dec 21, 2022
LaiFeng IOS Live Kit,H264 and AAC Hard coding,support GPUImage Beauty, rtmp transmission,weak network lost frame,Dynamic switching rate

LFLiveKit LFLiveKit is a opensource RTMP streaming SDK for iOS. Features Background recording Support horizontal vertical recording Support Beauty Fac

null 4.3k Jan 6, 2023
Audio player demo based on Swift and SwiftUI, which can play local or network audio.

SwiftAudioDemo Audio player demo based on Swift and SwiftUI, which can play local or network audio. In this demo, I have made a radio player to play n

Jensen Zhang 6 Mar 13, 2022
AudioPlayer is syntax and feature sugar over AVPlayer. It plays your audio files (local & remote).

AudioPlayer AudioPlayer is a wrapper around AVPlayer. It also offers cool features such as: Quality control based on number of interruption (buffering

Kevin Delannoy 676 Dec 25, 2022
An iOS and macOS audio visualization framework built upon Core Audio useful for anyone doing real-time, low-latency audio processing and visualizations.

A simple, intuitive audio framework for iOS and OSX. Deprecated EZAudio has recently been deprecated in favor of AudioKit. However, since some people

Syed Haris Ali 4.9k Jan 2, 2023
FileManager replacement for Local, iCloud and Remote (WebDAV/FTP/Dropbox/OneDrive) files -- Swift

This Swift library provide a swifty way to deal with local and remote files and directories in a unified way. This library provides implementaion of W

Amir Abbas Mousavian 890 Jan 6, 2023
AudioKit Sample Player (ROM Player) - EXS24, Sound Font, Wave Player

AudioKit ROM / Sample Player Welcome to the official AudioKit example of a sample-based music instrument written in Swift. It can be modified to play

AudioKit 500 Dec 27, 2022
A framework for streaming audio between Apple devices using AirPlay.

Airstream An iOS / macOS framework for streaming audio between Apple devices using AirPlay. You can use Airstream to start an AirPlay server in your i

Qasim Iqbal 374 Oct 26, 2022
WatchTube: a standalone WatchOS youtube player utilizing Download API for search data and video streaming

WatchTube is a standalone WatchOS youtube player utilizing Download API for sear

WatchTubeTeam 11 May 30, 2022
Swifty360Player - iOS 360-degree video player streaming from an AVPlayer.

Swifty360Player iOS 360-degree video player streaming from an AVPlayer. Demo Requirements Swifty360Player Version Minimum iOS Target Swift Version 0.2

Abdullah Selek 148 Dec 18, 2022
iOS 360-degree video player streaming from an AVPlayer.

Swifty360Player iOS 360-degree video player streaming from an AVPlayer. Demo Requirements Swifty360Player Version Minimum iOS Target Swift Version 0.2

Abdullah Selek 148 Dec 18, 2022
A swift package(SPM) with iOS UI component that loads and displays images from remote urls or local assets and displays in a slide-show form with auto scroll feature.

MDBannersView A swift package with an iOS UI component that loads and displays images from remote urls, local assets and displays in a slide-show form

Madhav Deva 2 Feb 5, 2022
Image viewer (or Lightbox) with support for local and remote videos and images

Table of Contents Features Focus Browse Rotation Zoom tvOS Setup Installation License Author Features Focus Select an image to enter into lightbox mod

Nes 534 Jan 3, 2023
A library and tool for interacting with both the local and remote asset caches.

Asset Cache Tool A library and tool for interacting with both the local and remote asset caches. This is based on research I did a few years ago on th

Kenneth Endfinger 20 Dec 23, 2022
A micro-framework for observing file changes, both local and remote. Helpful in building developer tools.

KZFileWatchers Wouldn't it be great if we could adjust feeds and configurations of our native apps without having to sit back to Xcode, change code, r

Krzysztof Zabłocki 1k Dec 19, 2022
The simplest abstraction to synchronize local data with remote source. For iOS, wirtten in swift.

Purpose The simplest abstraction to synchronize local data with remote source. For iOS, written in swift. Overview Many applications uses remote serve

Siarhei Ladzeika 7 Mar 17, 2022
The Amazing Audio Engine is a sophisticated framework for iOS audio applications, built so you don't have to.

Important Notice: The Amazing Audio Engine has been retired. See the announcement here The Amazing Audio Engine The Amazing Audio Engine is a sophisti

null 523 Nov 12, 2022
AudiosPlugin is a Godot iOS Audio Plugin that resolves the audio recording issue in iOS for Godot Engine.

This plugin solves the Godot game engine audio recording and playback issue in iOS devices. Please open the Audios Plugin XCode Project and compile the project. You can also use the libaudios_plugin.a binary in your project.

null 3 Dec 22, 2022