jorgenhenrichsen / swiftaudio Goto Github PK
View Code? Open in Web Editor NEWAudio player for iOS
License: MIT License
Audio player for iOS
License: MIT License
Describe the bug
After there is a problem playing a track, and the AVPlayer status changes to failed
, the player becomes unresponsive and will not play any other track. Every command after reaching this state results in an error.
To Reproduce
I found this error when I was attempting to play a track. I later discovered that there was image metadata in the track. After removing the image metadata, the track does not result in an error.
I cannot post the test file publicly, but I can provide it privately if it helps to debug.
While modifying this audio file fixes the immediate issue, there is still the underlying issue of the player becoming unresponsive after a failure.
Expected behavior
The player should be able to recover after failing to play a track and resume normal operation when attempting to play a different track.
Info:
Additional context
I am using SwiftAudio as part of react-native-track-player, which is maintained by @dcvz.
However, I have recreated this issue within the SwiftAudio example by replacing one of the example tracks with the track I have been having issues with. The default example track play fine until I try to play the problem track. After that, the example tracks will no longer play.
Suggested Solution
Apple docs say that when AVPlayer status changes to 'failed', the AVPlayer instance can no longer be used and must be replaced with a new instance.
https://developer.apple.com/documentation/avfoundation/avplayer/1388096-status
I tried this, and it seems to resolve the issue. Check out this commit on my fork.
However, I did not create a PR because I am not proficient in swift, and I don't feel I have a good enough grasp on the overall structure of this library in order to implement this fix in the best way possible.
For instance, I don't know if it would be better to do this in response to the failure, or to check before the next action and recreate the instance on demand. Also, I'm not sure if the wrapper should be re-created or just the AVPlayer.
Calling load(item:playWhenReady:)
method will not trigger play
method of the wrapper after adding item(s) to the QueuedPlayer
, that means when I add items first then play any of them, if we decide to add more items or just load a new item later, the view sometimes freezes and the item is not played.
After some investigation, it turned out to be load(from:, playWhenReady:)
method, it must not call avPlayer.replaceCurrentItem(with:)
on the main thread, rather, it must be called using asset.loadValuesAsynchronously(forKeys:)
method (as detailed in the second answer here).
Once the audio player has finished playing how can we remove the Player displaying in NotificationCenter or Lock Screen.
I am using SwiftAudio
as part of react-native-track-player
. I am trying to track down some issues related to the lock screen controls and background loading. doublesymmetry/react-native-track-player#709
So far, I don't think the issue is with SwiftAudio
. However, I was looking at differences between SwiftAudio
example and react-native-track-player
example, and noticed that SwiftAudio
has the Remote Notifications background mode enabled.
Is this really necessary?
The SwiftAudio
docs say to enable it as part of supporting remote commands.
App Settings -> Capabilites -> Background Modes -> Check 'Remote notifications'
However, all the Apple docs I can find on this setting are referring to a completely different type of notification, related to alerting the app of new content to download.
Can you explain, if you have some time? Thanks!
Describe the bug
When app goes into the background, audio stop play.
I checked Audio, AirPlay, and Picture in Picture in Background Modes
Describe the bug
Loading (buffering) state over 3G connection is not fired when the mp3 file is being loaded. Over Wifi it works OK, I guess because it loads the mp3 file faster.
To Reproduce
Just play an MP3 file over a 3G connection and you will see that the loading state is not triggered until the very end.
Edit:
This only happens the first time you load/play an MP3 file, after stopping the playback and playing it again it triggers the loading state immediately as it should.
Expected behavior
The loading state should be triggered as soon as the MP3 file starts to being loaded. This is useful for people over 3G connections to know that the MP3 is being loaded.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Could you please give an example on how to use the player with local mp3 file?
That’ll be awesome!
I cannot play the same audio file again after it ended with end reason: playedUntilEnd, is there a way to play it again ?
Is your feature request related to a problem? Please describe.
go to the last song when I am on the first one and I click on previous
Describe the solution or feature you would like
I want to add the behavior when user click on previous and he is on the first to play the last song and so on
Hello thanks for this wonderful library, do you planned to add any repeating features? either repeat one or all audios? If not I would appreciate if you could point me to the right logic to figure it out. Thank you!
How to implement Custom DefaultAudioItem with my custom Items.
I want to use more than title and album title I want to implement more than the current implementation
DefaultAudioItem(audioUrl: item.mp3Path.replaceTom3u8(), artist: item.singerName, title: item.title, albumTitle: item.singerName, sourceType: .stream, artwork: image)
How to achieve that?
how should I implement current time delegates to update view?
I've got weird crashes when trying to loading items one after one in .stream
sourceType.
I'm using AudioPlayer
and not QueuedAudioPlayer
I've checked a few things and it seems the problem is with removing observer and sometimes the AVPlayerItem
gets deallocated but the observers for .duration
and ```.loadedTimeRanges```` still registered.
Image 1:
Image 2:
NOTE
the problem occurred when I've tried to load items immediately one after one.
its ok when I let them to get .ready state
before loading another-one.
Describe the bug
I set my network link conditioner on 3g, when I play a song at music player at the middle of song music player state change to .loading or .buffering and progress bar on music player interface didn't update/moving but progress bar on MPRemoteCommandCenter still updateing the value
it's happend on AudioPlayer.currentTime too, sometime when player still buffer AudioPlayer.currentTime keep updating the value too. For this condition I reproduce it by turn on network link conditioner to very bad network at the first time song is loaded
To Reproduce
set network link conditioner to 3G
edit: try to play network link conditioner from turn off to very bad network when song is playing and buffer position still updating like the example of this video
http://www.mediafire.com/file/hsrcb07siyypbhp/VID20200310132441.mp4/file
in this video I use streaming song from
https://www.eclassical.com/custom/eclassical/files/BIS1447-002-flac_24.flac because the duration of sample song that available on the SwiftAudio example is to short
make sure change network link conditioner to very bad network when song is playing but bufferedPosition still updating their value
Expected behavior
not updating progress bar until player state change to .playing like progress bar on music player
Smartphone (please complete the following information):
How to load sources dynamically? audio URL dynamically for queued playing
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
If needed, include code examples for the problem or steps to reproduce.
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
Add any other context about the problem here.
Hi, I'm using this library to open local url but I have a problem when I try to open an url that contains whitespaces in filename.
So, for example, if I try to open a file which name is "example_file.mp3" this audio is successfully opened.
But, if I try to open a file which name is "example file.mp3" an error occurs "The requested URL was not found on this server". I've also tried to replace the name with "example%20file.mp3" but I have the same error.
Is your feature request related to a problem? Please describe.
Add a way to supply option key-values to the AVURLAsset by using init(url:options:).
Describe the solution or feature you would like
Should be able to supply these values to the AudioPlayer
, which will pass it down to the AVPlayerWrapper
that initializes the AVURLAsset
.
Describe alternatives you've considered
A protocol that AudioItem
s can conform to in order to supply relevant options.
Additional context
A result of PR #64, that was adding auth headers to the asset by supplying headers in the option dictionary with the AVURLAssetHTTPHeaderFieldsKey
key, but this is a private API. The feature described here offers a way for developers to use this at their own risk.
Player state sometimes does not change to playing
, even though audio starts and elapsedSecond
event emits. It happens randomly, but more often if your network connection is slow. I'm testing on a device using Network Link Conditioner
in Settings
-> Developer Options
to simulate a slow connection.
If you look at this log, it shouldn't be possible for player.playerState
to be paused
while emitting secondElapse
(and actually playing):
⌛ stateChange - state: paused
⌛ stateChange - state: loading
⌛ stateChange - state: paused
⌛ secondElapse - currentTime: 0.0 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ secondElapse - currentTime: 0.0 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ secondElapse - currentTime: 0.0 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 0.3657142857142857
⌛ secondElapse - currentTime: 0.02672804 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ secondElapse - currentTime: 0.026939374 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 2.36472281
⌛ updateDuration: 7.380233014
⌛ secondElapse - currentTime: 1.000674124 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 11.403090157
⌛ updateDuration: 16.941049341
⌛ secondElapse - currentTime: 2.000570967 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 20.467579953
⌛ secondElapse - currentTime: 3.001347996 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 23.994110565
⌛ updateDuration: 27.520641177
⌛ secondElapse - currentTime: 4.001117254 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 33.032477912
⌛ updateDuration: 36.559008524
⌛ secondElapse - currentTime: 5.001199992 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 42.096967708
⌛ secondElapse - currentTime: 6.000966879 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 46.616151381
⌛ updateDuration: 52.154110565
⌛ secondElapse - currentTime: 7.000541125 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 55.680641177
⌛ secondElapse - currentTime: 7.856695665 / state: Optional(SwiftAudio.AVPlayerWrapperState.paused)
⌛ updateDuration: 59.20717179
Tested on a device with iOS 13.
Hi there.
I would like to play loop audio item.
Could you guys help me how can I do it?
Thanks!
currently the player track the state every second of playback, however, I couldn't find a way to track the change every milli-second, so that the playback UI component (slider or UIProgressView for ex.) will update the visual track smoother than a 1 second threshold.
This is not an issue!
Question: How do i remove the current item (song) that is about to play?
I'm just curious.
I am using this code:
`for i in 0 ..< songInfoArray.count {
let item = songInfoArray[i]
let audio = DefaultAudioItem(audioUrl: item.url artist: item.singerName, title: item.title, albumTitle: item.thumbnail, sourceType: .stream)
sources.append(audio)
}`
try? player.add(items: sources, playWhenReady: false)
`if songInfoArray.count > 1 {
try? player.jumpToItem(atIndex: songInfoArray.count - 1)
}`
**try? player.jumpToItem(atIndex: songInfoArray.count - 1)**
is not working
the player always play the songs from the start
Wanted to bring this to your attention: https://github.com/neekeetab/CachingPlayerItem
I've done some basic test integrating into the library and it's interesting.
In a library I would expect a track should play ASAP - and caching in queued mode to automatically download the next track when the current one is fully loaded.
This doesn't provide all of that but it has some nice ideas.
Hello @jorgenhenrichsen ,
I have a table view with a list of categories. When I'm open any category, I have a list of songs.
I'm adding the list of songs to QueuedAudioPlayer like in 1 number. First time the previous and next are working correctly, but if I'm leaving the current category, going back and trying to open another one, the last played song is added to Previous Items from 0 and one of the current previous items is removed.
try player.add(items: sources, playWhenReady: playWhenReady)
try player.jumpToItem(atIndex: index)
When I call 1 again, the previous items are appended from 0 the last played items and one of previous are removed
Can you help to fix, please?
Best Regards,
Mike
Describe the bug
Cannot play an audio from a url that has a space.
To Reproduce
Add an item.
With no space:
http://website.com/songs/Hanasakam.mp3
IT WORKS
but with spaces:
http://website.com/songs/Adil Hawrami - Krmshan.mp3
As you see, Adil Hawrami - Krmshan.mp3
You get:
The operation couldn’t be completed. (SwiftAudio.APError.LoadError error 0.)
Describe the bug
iOS 13 won't play next track in Queue Automatic!
To Reproduce
just create an array with DefaultAudioItem and then playsong.
Expected behavior
after a track ends automatic play next track in queue
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
iOS
xCode 11-beta7
Smartphone (please complete the following information):
iOS13 beta 8 [Simulator and iPhone 6s real device]
How to move to the next song when I add a new song to the array while music is playing behavior like any music player :
Explanation:
The array has 1 item and I am playing that item then I click on another item and I added to the array so the array now has 2 items and I want so the second item starts playing.
It's important to set the wrapper class and all of its methods & properties access level to be 'open', so I can implement my custom wrapper on top of this wrapper, for example, I want to use a custom AVPlayerItem
inside the wrapper to manage caching, there is no way to do so without subclassing AVPlayerWrapper class.
The duration of items on iOS 12 (Possibly other versions too) simulator is not loading properly.
This works fine on physical device running iOS 12.
Calling reset() on the QueuedAudioPlayer will not properly reset the player and queue content.
Hey there.
I'm trying to work with SwiftAudio. I have downloaded a 3MB music using URLSession and i can see it in the simulator folders,
My URL looks something like this:
file:///Users/Adam/Library/Developer/CoreSimulator/Devices/D38BAB08-846E-4172-9DB1-8D3567F6E10E/data/Containers/Data/Application/DE2FF955-B927-4542-A290-4DE550B6C53D/Library/Caches/Digger/mySongByAdam.mp3
Now, using loadItem
won't work for me.
Also as mentioned in issue #43 that i SHOULDN'T include my scheme
URL, But i do not know how to remove the file:/// or get an appropriate index of the file.
Edit:
Testing it on iPhone X iOS(12.0)
With this file var/mobile/Containers/Data/Application/2BC8BB07-D24C-4625-B2F8-C444F687994D/Library/Caches/Digger/flowerAdam.mp3
Still doesn't work
Describe the bug
When you try and fetch the current time using player.currentTime AFTER having seeked a track; it returns a value that is off by < 1%.
By way of example, I played a track with duration 1700.78, seeked to close to the end of the track right away, and once the track ended it reported a progress time of 1682.39 (so off by around 1.1%)?
I've tested both having done a seek and having not done a seek; and the the currentTime appears to be off by a much greater margin when the user has seeked thru the track previously. The attached screenshots show an example of the reported current time and duration when the same track ends both with and without a seek having occurred.
Without A Seek (Off by < 0.03 of a second)
With A Seek (Off by around 12 seconds / around 1% of the total track time).
The behaviour seems to occur consistently across all the tracks I'm trying to play - which are just regular MP3 files.
To Reproduce
See above.
Expected behavior
The current time to always be reported correctly.
Screenshots
See above.
Desktop (please complete the following information):
Catalina
Smartphone (please complete the following information):
Using the latest Swift Audio (0.11.1)
Additional context
I think it might have to do with CMTimeMakeWithSeconds in the seek function and/or could be a rounding issue somewhere? Just guesses...
A quick google also brought up this: https://stackoverflow.com/questions/47158688/ios-11-avplayer-mp3-currenttime-not-accurate so might be worth adding [AVURLAssetPreferPreciseDurationAndTimingKey: true] to the AVURLAsset options just in the hope it sorts it out.
I'm using react-native-track-player
, which uses this library for iOS audio playback. I've run into an issue that I can't seem to find the root cause of - my app is crashing when trying to add tracks to it suddenly. When it crashes, I get this error:
Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
The code it's telling me that caused the crash is in NowPlayingInfoCenter.swift
:
public func set(keyValue: NowPlayingInfoKeyValue) {
_info[keyValue.getKey()] = keyValue.getValue()
self._infoCenter.nowPlayingInfo = _info
}
Looking through the trace on the right of Xcode, it looks like the call to update the now playing duration is what's causing this? Would it be possible to guard these functions from setting invalid values?
public func set(keyValue: NowPlayingInfoKeyValue) {
let key = try? keyValue.getKey()
let value = try? keyValue.getValue()
if (key != nil && value != nil) {
_info[keyValue.getKey()] = keyValue.getValue()
self._infoCenter.nowPlayingInfo = _info
}
}
I want to load the song image from my database.
instead of
DefaultAudioItem(audioUrl: <String>, artist: <String?>, title: <String?>, albumTitle: <String?>, sourceType: <SourceType>, artwork: <UIImage?>)
can I use
`DefaultAudioItem(audioUrl: , artist: <String?>, title: <String?>, albumTitle: <String?>, sourceType: , artwork: <ImageLink?>)
`
Describe the bug
Let met start by saying I don't do much with Swift; I'm using this library as a part of react-native-track-player.
Our app implements skipBackward and skipForward. Randomly, the iOS lock screen will display the standard rewind button instead of the skip backward button.
I'm led to believe this is some kind of race condition but am not comfortable enough with Swift to confirm.
To Reproduce
This must be tested on a device as iOS simulator does not show media controls.
These steps won't cause the exact scenario I mentioned above, but I believe it's the same bug.
.skipForward(preferredIntervals: [30]),
.skipBackward(preferredIntervals: [30]),
internal func enable(commands: [RemoteCommand]) {
commands.forEach { (command) in
self.enable(command: command)
}
+
+ self.enable(command: RemoteCommand.skipBackward(preferredIntervals: [60]))
+ // usleep(10000)
+ self.enable(command: RemoteCommand.skipForward(preferredIntervals: [60]))
}
The skipBackward icon should say 60 and the skipForward icon should say 30, even though it should say 60.
usleep
and test again. Both buttons should now say 60. (Obviously usleep is not a solution, it's just the only way I've been able to guarantee the expected behavior in my test.)Expected behavior
Media controls should display the skipBackward and skipForward icons.
Screenshots
Incorrect behavior:
Device 1:
Device 2:
Is it possible to get total duration of a remote audio file?
By using the event updateDuration
event the duration is continually updated (I think until everything has been downloaded/buffered?). This makes the knob on a seek bar/scrubber jump around until duration has been determined and are perceived quite buggy and hard to use by our users.
PS. Thanks for an awesome lib! :)
How to manage Play/Pause Button title in UITableView.
Hi,
I want to show song details when I'm connecting to some Bluetooth device like tv.
How can I do it?
For now, ic can see when I connect to tv just the progress bar and time.
Hello Sir. I'm a Graphics Designer. I'm happy to see an open source project, So, I want provide a logo for you. Would you mind if I propose a new logo design for your project as my Open Source Contribution?
Thanks for the attention.
Hey!
Right now AudioPlayer asks items for related remote commands or uses those provided when track changes.
I find very useful to have the ability to refresh them later (because of the how backend's API is designed) – unfortunately current API doesn't allow to do that.
Maybe a new function or remoteCommands didSet block?
public var remoteCommands: [RemoteCommand] = [] {
didSet {
if let currentItem = currentItem {
enableRemoteCommands(forItem: currentItem)
}
}
}
Describe the bug
In debug mode all works like charm, in release the app crashes trying to play audio.
To Reproduce
Install pod, add tracks and run in release mode.
Expected behavior
Always works like in debug.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
I'm developing a react-native app with the react native track player library.
This is the link at the issue.
I am looking for a way to get the audio buffering status and/or event. My audio is an URL being pulled. I have set try? controller.player.load(item: item, playWhenReady: false). I want to receive notice that the audio is ready to play. Do you know how I can achieve this?
How to add NextTrack and PreviousTrack in remote control as if I remove SeekForward and SeekPrevious , it displays the Next and Back Button but are disabled.
Enum has no case for these, So how I can implement it keeping pod attached.
Describe the bug
After I initialize my player, I set player.audioTimePitchAlgorithm = .varispeed
, but it doesn't work. (Really, I want Spectral, but varispeed should be really obvious and produce a chipmunk-like sound at 2x, so I'm just using that to try to reproduce the bug. It sounds like it's actually using lowQualityZeroLatency
.)
I also tried subclassing AudioItem but that doesn't work either.
To Reproduce
Clone and run this repo. (The main file to look at is here.)
Expected behavior
When you tap "play" and increase the speed to 2x, it should sound like a chipmunk.
Desktop (please complete the following information):
Smartphone (please complete the following information):
In case I disconnected the device from the internet, and hit play to play the track nothing happens and this is the expected behavior, but I reconnect to the internet and hit play again the audio file will not play as expected.
I can reproduce this bug in your example project.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.