Coder Social home page Coder Social logo

fethica / fradioplayer Goto Github PK

View Code? Open in Web Editor NEW
276.0 23.0 57.0 815 KB

A simple radio player framework for iOS, macOS, tvOS.

Home Page: https://fethica.github.io/FRadioPlayer/

License: MIT License

Swift 96.97% Ruby 3.03%
player radio swift music avplayer album-artwork cocoapods itunes-api radio-url audio-player

fradioplayer's Introduction

FRadioPlayer

FRadioPlayer

CI Status CI Status Version License Platform

FRadioPlayer is a wrapper around AVPlayer to handle internet radio playback.

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

FRadioPlayer

Features

  • Support internet radio URL playback
  • Update and parse track metadata
  • Update and show album artwork (via iTunes API)
  • Automatic handling of interruptions
  • Automatic handling of route changes
  • Support bluetooth playback
  • Swift 5
  • Full documentation
  • Network interruptions handling
  • Support for Carthage
  • Support for macOS
  • Support for tvOS
  • Support for Swift Package Manager SPM
  • Support for Audio Taps
  • Support for Audio Recording

Requirements

  • macOS 10.12+
  • iOS 10.0+
  • tvOS 10.0+
  • Xcode 10.2+
  • Swift 5

Installation

CocoaPods

FRadioPlayer is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'FRadioPlayer'

Carthage

FRadioPlayer is available through Carthage. To install it, simply add the following line to your Cartfile:

github "fethica/FRadioPlayer" ~> 0.1.10

Swift Package Manager

FRadioPlayer is available through SPM. To install it, simply add the following dependency to your Package.swift file:

.package(url: "https://github.com/fethica/FRadioPlayer.git", from: "0.1.18")

Manual

Drag the Source folder into your project.

Usage

Basics

  1. Import FRadioPlayer (if you are using Cocoapods)
import FRadioPlayer
  1. Get the singleton FRadioPlayer instance
let player = FRadioPlayer.shared
  1. Set the delegate for the player
player.delegate = self
  1. Set the radio URL
player.radioURL = URL(string: "http://example.com/station.mp3")

Properties

  • isAutoPlay: Bool The player starts playing when the radioURL property gets set. (default == true)

  • enableArtwork: Bool Enable fetching albums artwork from the iTunes API. (default == true)

  • artworkSize: Int Artwork image size. (default == 100 | 100x100).

  • rate: Float? Read only property to get the current AVPlayer rate.

  • isPlaying: Bool Read only property to check if the player is playing.

  • state: FRadioPlayerState Player current state of type FRadioPlayerState.

  • playbackState: FRadioPlaybackState Playing state of type FRadioPlaybackState.

Playback controls

  • Play
player.play()
  • Pause
player.pause()
  • Stop
player.stop()
  • Toggle playing state
player.togglePlaying()

Delegate methods

Called when player changes state

func radioPlayer(_ player: FRadioPlayer, playerStateDidChange state: FRadioPlayerState)

Called when the playback changes state

func radioPlayer(_ player: FRadioPlayer, playbackStateDidChange state: FRadioPlaybackState)

Called when player changes the current player item

func radioPlayer(_ player: FRadioPlayer, itemDidChange url: URL?)

Called when player item changes the timed metadata value

func radioPlayer(_ player: FRadioPlayer, metadataDidChange artistName: String?, trackName: String?)

Called when player item changes the timed metadata value

func radioPlayer(_ player: FRadioPlayer, metadataDidChange rawValue: String?)

Called when the player gets the artwork for the playing song

func radioPlayer(_ player: FRadioPlayer, artworkDidChange artworkURL: URL?)

Swift Radio App

For more complete app features, check out Swift Radio App based on FRadioPlayer

Swift Radio

Hacking

The Xcode project is generated automatically from project.yml using XcodeGen. It's only checked in because Carthage needs it, do not edit it manually.

$ mint run yonaskolb/xcodegen
💾  Saved project to FRadioPlayer.xcodeproj

Author

Fethi El Hassasna

License

FRadioPlayer is available under the MIT license. See the LICENSE file for more info.

fradioplayer's People

Contributors

bubudrc avatar cbarriga avatar fethica avatar linusu avatar misteral avatar nicolassrod avatar sbrighiu avatar topdsgn avatar urayoanm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fradioplayer's Issues

Radio not playing ???

`import UIKit
import AVFoundation
import FRadioPlayer

class RadioViewController: UIViewController {
let player = FRadioPlayer.shared

var audioPlayer: AVAudioPlayer?

override func viewDidLoad() {
    super.viewDidLoad()
    player.delegate = self

}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destination.
    // Pass the selected object to the new view controller.
}
*/

@IBAction func playSongButtonPressed(_ sender: Any) {
    
    player.radioURL = URL(string: "http://rfcmedia.streamguys1.com/Newport.mp3")

    player.play()
}

}

extension RadioViewController: FRadioPlayerDelegate {

func radioPlayer(_ player: FRadioPlayer, playerStateDidChange state: FRadioPlayerState)
{
    print("radioPlayer");
}
func radioPlayer(_ player: FRadioPlayer, playbackStateDidChange state: FRadioPlaybackState)
{
    print("FRadioPlaybackState");
    
}
func radioPlayer(_ player: FRadioPlayer, itemDidChange url: URL?)
{
    print("itemDidChange");
    
}

func radioPlayer(_ player: FRadioPlayer, metadataDidChange artistName: String?, trackName: String?)
{
    print("metadataDidChange artistName");
    
}

func radioPlayer(_ player: FRadioPlayer, metadataDidChange rawValue: String?)
{
    print("metadataDidChange");
    
}

func radioPlayer(_ player: FRadioPlayer, artworkDidChange artworkURL: URL?)
{
    print("artworkDidChange");
    
}

// func radioPlayer(_ player: FRadioPlayer, artworkDidChange artworkURL: URL?) {
//
// // Please note that the following example is for demonstration purposes only, consider using asynchronous network calls to set the image from a URL.
// guard let artworkURL = artworkURL, let data = try? Data(contentsOf: artworkURL) else {
// artworkImageView.image = stations[selectedIndex].image
// return
// }
// track?.image = UIImage(data: data)
// artworkImageView.image = track?.image
// updateNowPlaying(with: track)
// }
}` please help me AVplayers showing nil values

How could i know when state of audio is still playing?

How could i know when state of audio is still playing?

I tried with two function, but both doesnt work

func radioPlayer(_ player: FRadioPlayer, playerStateDidChange state: FRadioPlayerState) {
if state == .loadingFinished && !player.isPlaying{
print("ansdfhkdhf")
}
}

func radioPlayer(_ player: FRadioPlayer, playbackStateDidChange state: FRadioPlaybackState) {
    if state == .playing && !player.isPlaying{
        print("ansdfhkdhf")
    }
}

playerDidFinishPlaying method not called when song is changed

Hi,
I need to call playerDidFinishPlaying method once each song playing finish.
I have a couple of songs comes from my server, need to get closure or some delegate method that can be called when a new song started playing or finished playing.

And also once the song is playing finished it will automatically start playing the next song in sequence when new songs is in queue or playlist.

is it possible?

Additional Metadata

I am attempting to get the duration of a track and using the " - " however it only returns track name and artist. I have tried putting it in the function for additional meta data and doesn't seem to work. I am fairly new to swift so I know I am missing something! (I learnt wayyyyyyyy back on Pascal and C...with no plus.)

While poking around in the API the search (specifically the struct Key.results) is useful in other places of my app as I want to incorporate a "buy" screen. It feels silly to implement a new method/function to duplicate so what would be best practice to send this information to my MainVC?

Thank-you,

Ryan

PS This app has been a lifesaver and great teaching tool so far.

After call interrupted stream metadata = nil

After that incoming call has interrupted stream, call ended, then first
func radioPlayer(_ player: FRadioPlayer, metadataDidChange artistName: String?, trackName: String?) returns empty data, new data arrived few minutes later.

See log:

2019-07-14 19:22:40.063156+0300 Free Radio[15846:3911976] metadataDidChange = Sting - All This Time
2019-07-14 19:25:06.641497+0300 Free Radio[15846:3911976] metadataDidChange = 
2019-07-14 19:25:06.678216+0300 Free Radio[15846:3911976] playerStateDidChange = Ready to play
2019-07-14 19:25:06.678296+0300 Free Radio[15846:3911976] playerStateDidChange = Loading finished
2019-07-14 19:27:21.571133+0300 Free Radio[15846:3911976] metadataDidChange = Sting - Brand New Day

AVPlayer not working on iOS 14

Hi,

It seems like AVPlayer not able to play HLS streams on iOS 14. This is a road blocking issue. Do you have any idea/solution for this? Please direct me if you have anything

Thank you
Regards,
Hima

Set music volume

It's possible to set the volume of the current stream? Thanks in advance!

Airplay to an Apple TV prompts a black screen instead of a now playing notification

Airplay-ing to an Apple TV device will prompt a black screen with a loader and a progress bar instead of running as a background music app -> TuneIn (which i do believe uses AVPlayer, but i cannot confirm), Soundcloud, Spotify ..

Reproduce:

  1. Open the app, setup FRadioPlayer, and call play()
  2. Wait until you hear the music, and then go into Control Center and Airplay to an Apple TV (not headphones.. it needs to be an Apple TV for this to be reproduce-able)
  3. Observe the now playing info is not visible anywhere and the screen goes fully black, with only a loader and a progress bar.

The annoying part is the fact that if you dismiss the screen, it does not continue playing the music and will most of the times corrupt the session on that Apple TV.

Audio Equalizer Implementation

Is it tricky to implement an audio equalizer like Spotify for FRadioPlayer? I'm currently coding the Swift Radio Pro to my liking and was wondering how hard it would be? I'm still learning so if you just point me in the right direction to do it myself that would be much appreciated. Thank You
img_2030

How to use with SwiftUI?

Can somebody tell me if it’s possible to use this library together with SwiftUI?

If yes, I would appreciate a brief example, thanks in advance!

I'm kinda getting stuck, when it comes to things like UIViewControllerRepresentable or to set the player it’s delegate due to the missing override function in a SwiftUI file.

Cannot start radio while Airplay-ing to an Apple TV

The Player remains stuck in .loading status and needs custom timeout logic.

Reproduce:

  1. Open the app, setup FRadioPlayer, and call play()
  2. Wait until you hear the music, and then go into Control Center and Airplay to an Apple TV (not headphones.. it needs to be an Apple TV for this to be reproduce-able)
  3. Hear the music playing on the Apple TV
  4. Close the app
  5. Start the app again and try to play() .. the app will not start now

The route will be selected as AirPlay route and this case was .. to my knowledge not treated.
I've tried to override the port to the .speaker port with no success.

Car Play crash

Hello Fethica,

We have a music audio app which we built car play using your tutorial - https://blog.fethica.com/add-carplay-support-to-swiftradio/ . The app is working fine on simulator, but when tested on a real car, it crashed right after tapping the app icon on car dashboard. We have followed the same steps mentioned in the post above by extending the App Delegate with 'MPPlayableContentDelegate'. Do you have any suggestions why the app may crash in real time? Below is the thread that is causing the failure. Also, we are using Fradio player for our music app.

Please do the needful. Thank you

crashlog.pdf

Cannot stop radio while it's loading

I seem to not be able to stop the radio from playing while it's still loading. Is there anyway to cancel loading and keep it from starting to play while it's in the loading state?

Swift 5

Good afternoon!

Upgrading to swift 5 is bringing a couple issues, of course.

In "Reachablity" there is some updates on it's github page and it fixes most of the issues.

Thought I had another...I was wrong sory. Cannot delete this for some reason....

Thanks!
Ryan

Stream Interruption when changing from wifi to cellular

Hi,
I'm facing the issue that the player interrupts the stream when changing from a wifi to a cellular connection. It doesn't reconnect, even after reconnection to the wifi network. Could be an iOS 12 specific problem, I don't have an iOS 11 device to test it.

The player state changes a few seconds after the change to cellular to 'Loading' and stays there

Edit: It seems like that the network interruption handling doesn't work at all for me. I'll try to get my hands on an iOS 11 device.

Need help setup Tack labels updating

Hi everyone , i'm having trouble setting up Track labels updating
i have the function
func radioPlayer(_ player: FRadioPlayer, metadataDidChange artistName: String?, trackName: String?) { }

But what to i put in there ?
i tried to follow exemples but not worked
Thanks for the help :)

Local File Skimming

I tried this out with radio urls and was a great solution. Since it also works with local files, is it possible to introduce a skimming feature? For example, it plays a local file and if the user decides, they can fast forward the song to continue playing at another point? Would be great to also have the progress of the file. Meaning the user is 60% along the song so developers can create a UI element to inform users how much of the song is left and how much has been played

Radio doesn't resume after network interruption - Wifi (working for cellular)

Hello Fethica,

I have been using the FRadio library in my radio app and encountered an issue. When there is a network interruption and the network type is Wifi - the radio pauses and when the connection is back, the Radio wouldn't resume though the player state is 'Ready to play'. This is working fine with cellular data but not working with Wifi.
Please note that I have tested this on my iPhone 8 Plus device, however the same scenario is working fine in the simulator (radio resumes).
We have a release planned early next week and this is the show stopper. So, kindly get back to me ASAP.

Thank you.

Regards,
Hima

Audio not being played on iPhone 6 on real device

Audio is playing back on every device and simulator except iPhone 6 and 6+ both have iOS 11.2

Always fails with the following error when trying to playback from a URL
Credstore - performquery - error copying matching creds

Player keeps playing when remote stream ends

HI,

I'm building an app using FRRadioPlayer to play various streams from a remote icecast server which is streaming in mp3 format.

The streams are not always live. Many streams are on for 1-2 hours per day.
The app has code to check the stream is live and only shows the player when live.

The issue I'm experiencing is that when the stream ends, the player keeps playing a dead stream. The icecast server is no longer publishing the mount so the url should give a 404 error. However FRRadioPlayer thinks its still live.

FRadioPlaybackState keeps saying "Player is playing"
playerState says "Loading is finished"
isplaying shows true (playing)

I've checked all the published values and none of them appear to change. I need the player to stop playing when the stream ends.

When the stream starts again and if the url hasn't changed, the new stream doesn't play either. If the player was stopped when the stream ended and then the user started again the stream then it would be OK as it would reload the url but as the player never seems the stream stop, the UI keeps showing playing and the app never reloads the url.

ios 10 artwork raw value decoding issue

There is an issue with decoding raw value of artist name and song just on ios 10.
This workaround should work:

FRadioPlayer.swift
line 520:
case "timedMetadata": let rawValue = item.timedMetadata?.first?.value as? String timedMetadataDidChange(rawValue: rawValue)

replace with:
`case "timedMetadata":
let rawValue = item.timedMetadata?.first?.value as? String

            if #available(iOS 11.0, *) {
                timedMetadataDidChange(rawValue: rawValue)
            } else {
                guard let data = rawValue?.data(using: String.Encoding.isoLatin1),
                    let rawValue: String = String(data: data, encoding: String.Encoding.utf8) else { return }
                
                timedMetadataDidChange(rawValue: rawValue)
            }`

HLS Metadata

Hi:
There are plans to implement metadata retrieval using HLS streaming? If implemented, any lead how it works?
Thanks @ Urayoan

Getting timedMetadata

How can I get timedMetadata from FRadioPlayer?

eg 1: radioPlayer.timedMetadata.count
eg 2: radioPlayer.timedMetadata.first

Add support for tvOS

Can you add tvOS compatibility? It only needs AVAudioSession options to be set to an empty list.

Thanks in advance ;)

HLS metadata

Thanks for this great project.

I'm testing it with some HLS streams, and it seems to play fine, but I've noticed a bug with the metadata where it shows the Title for both the Artist and Title. You can see an example with this stream URL:

http://216.235.87.4:80/7302_48k.aac/playlist.m3u8

I believe the reason for this is because it's assuming that metadata comes in one field separated by " - ". That is accurate in Icecast streams, but with HLS, the Artist and Title are in separate ID3 tags.

Any chance of implementing support for ID3 metadata as well? This SO might help:
https://stackoverflow.com/questions/58099131/how-to-read-id3-tags-other-metadata-from-an-hls-stream-in-swift-avkit

Carthage framework project/files not updated to Swift 4.2

Carthage build fails because the files in the framework inside the FRadioPlayer.xcodeproj are not updated to Swift 4.2.

screen shot 2018-10-12 at 3 04 07 pm

Edit: The code is updated to Swift 4.2, but the framework target is still set to Swift 4 and will need to be updated to Swift 4.2. Deployment target is also required to be updated to at least iOS 10.0 for it to build without errors. That should be a quick fix. Thanks in advance!

Playing station and selected row mismatch.

If click quickly on "next station" or "previous station" button, selected row not always matches with the playing station. This represents almost always with array of stations containing more than 15 stations.
radioPlayer(_ player: FRadioPlayer, itemDidChange url: URL?) returns the selected station's url but player plays previous or before previous station.
How this can be fixed?

Difference between .loadingFinished and .readyToPlay

I'm having some problems figuring out the difference between .loadingFinished and .readyToPlay. From what I've observed, it seems like as soon as the stream starts playing the status first gets changed to .readyToPlay, and then directly after changes to .loadingFinished and stays there.

In the app I'm currently working on I basically only have three states: stopped, loading, playing. I'm currently using the following logic to determine what state I'm in, and it seems to be working fine, but I'm not sure if it's "correct" and will always work...

class FooBar {
    // ...

    internal func refreshState() {
        if player.playbackState == .stopped {
            self.state = .stopped
        }

        if player.state == .loading {
            self.state = .loading
        }

        if player.state == .loadingFinished && player.playbackState == .playing {
            self.state = .playing
        }
    }

    func radioPlayer(_ player: FRadioPlayer, playerStateDidChange state: FRadioPlayerState) {
        refreshState()
    }

    func radioPlayer(_ player: FRadioPlayer, playbackStateDidChange state: FRadioPlaybackState) {
        refreshState()
    }
}

Impossible to restart stream after lost connection

Hello and thank for you Librairie and SwiftRadioPro, I have a trouble, I think it's a bad integration, but I don't understand.
Everything is ok when I play and stop, and start and stop with music controller, when I receive cellular call, change with another application, when we lose network for few seconds. So it's really fine.
But when I loose connection when I drive for example or when I try with Network Link Conditionner, it's impossible to play, I need to kill app to replay.
Do you have an idea ?

I need to reset player ? Other thing ? Use delegate, other ?

And I test another thing with simple implementation
I have the same problem with simple implementation of AVPlayer

        let urlString = StreamUrl
        guard let url = URL.init(string: urlString)
            else {
                return
        }
        let playerItem = AVPlayerItem.init(url: url)
        player = AVPlayer.init(playerItem: playerItem)

And it's impossible for me to play after this warning

2021-04-27 23:12:37.786986+0200 XXX[5725:3210729] [Symptoms] {
  "transportType" : "HTTP Live Stream",
  "mediaType" : "HTTP Live Stream",
  "BundleID" : "XXX",
  "name" : "MEDIA_PLAYBACK_STALL",
  "interfaceType" : "Other"
}

Thanks in advance. Romain

Support for Audio Recording

hi thx for the effort and the quality of your application i'm asking if Support for Audio Recording will be available soon

Querying Last.fm or another API

A previous version of the SwiftRadio project had the ability to query the Last.fm API in addition to the iTunes API. Since switching the player to the fantastic FRadioPlayer, we can only query the iTunes API.

How could one implement querying the Last.fm API? Or another API for that matter? Say query a url like https://www.exampleapi.fm/meta/**channelname**/live/ for json and get and parse the results?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.