truncated sound clips on IOS - ios

The essence of the problem is that on IOS only, playing
sound clips using
MediaManager.createMedia(clip, "audio/wav", null).play();
sometimes the playback is truncated. This is especially obvious
when the clip is several seconds long, but the point at which the
clip is truncated varies; occasionally the whole clip plays.
I've so far been unsuccessful creating a simple test case - in isolation
from my apps, the clip plays in full, so it seems like something in normal
background activity in the full app is interfering with audio playback.

I'm pretty sure I've found the root cause. MediaManager.createMedia creates an instance of Media, and when that object is garbage collected, it's finalize method is called, and a side effect of that causes the audio to be stopped.
A quick and dirty way to prevent this is to save a pointer to the media object.
This ought to be accomplished by internal bookkeeping in playaudio.

Related

HLS audio stream fails to resume play after time in background (AVPlayer refuses to buffer)

I have an iOS app that is designed to play HLS audio stream content.
The app supports time-shifting - you can skip backward, skip forward, scrub backward/forward, as well as pause the stream and unpause to where you left off.
The app works fine when operating in the foreground. It also works fine when actovely playing in the background (I have the background audio entitlement set correctly).
However, if the app is put into the background for more than a few moments (~30 seconds seems to do it) with the audio paused and either A) the user un-pauses the audio, or B) the user returns the app to the foreground and attempts to un-pause it from there, the audio does not play even after waiting a few moments. Note that the app process is not killed during this time.
To pause and unpause, I am using AVPlayer's pause and play methods.
While looking into it, I verified that the buffer (determined by looking at loadedTimeRanges) is filled during normal playback, but is quickly emptied shortly after the paused app is put in the background. If the app is returned to the foreground quickly enough, the buffer begins to fill again and playback can resume. Otherwise - if the user moves the app to the background for ~30 seconds - the buffer never refills at all and attempting to play again fails until the AVPlayerItem is re-configured.
I realize that there is no guarantee that the buffer will always have content (ie. it could be emptied to minimize memory footprint, which I suspect is the case here), but would expect AVPlayer to begin to start loading audio from it again as needed when playback resumes. Even if it has been in the background for a while.
Does anybody have an idea why this is occurring or how to work around it?
Note: I have created a simple sample iOS 14+ Xcode project that exhibits the problem using a known HLS stream. Tap 'Configure' to load the URL, then play/pause to exhibit the issue (I added console output showing the state of loadedTimeRanges).
https://tapestryapps.com/AudioTestbed.zip
Thank you.
If anyone is still experiencing this when working with HLS and changing the playerViewController?.player?.currentItem?.preferredPeakBitRate = 1 to safe data when backgrounding the application a workaround for this is to lower the buffer size playerViewController?.player?.currentItem?.preferredForwardBufferDuration = 10
When returning back to foreground all values can be set again to the default of 0
As an alternative you could also replace the playerViewController?.player?.currentItem but this would then result in video and audio buffering again.
The code works for me on iOS 13.5.1 and iOS 14.4, but fails on 14.0.1.
It looks like an iOS bug. You could work around this by recreating the AVPlayerItem when returning to the foreground on affected systems.

Airplay background streaming like Spotify / Amazon Music

Is it possible to do Airplay audio streaming like Spotify or Amazon Music. When i setup an Airplay stream with Audio from my App the screen (on the Apple-TV) turns black and shows only the progressbar.
Is it possible to show the small hint in the top corner with all the audio information which disappears after a few Seconds and don't block the whole Apple TV Ui?
Or is this kind of a Spotify / Amazon Music privilege?
We had this problem as well. I believe that there are some bugs here in Apple's court, but we found a decent workaround that seems to be pretty safe from side effects.
We found that setting the player's allowsExternalPlayback field to NO would sometimes correctly stream the audio without the blank video screen (along with correct display of the now playing information, correct response to volume rocker etc...). However, we found that very often it would fail to play anything at all.
Doing some runtime introspection, we found that the player would always correctly buffer from the network. But when it would hit the isPlaybackLikelyToKeepUp event, it would set the player's rate field to 1 indicating that it is playing, but more often than not, not actually play the audio. No errors were reported and so from all we could tell, the player itself thinks that it is indeed playing when it is not. We found this hangup to only occur when we had set an AirPlay device for audio output.
So we found that in certain event callbacks and other key places, if we added a simple one-liner:
if( self.avPlayer.rate == 1 ){ self.avPlayer.rate = 1; }
It would kick whatever internal hold ups were causing the player to not actually AirPlay and correctly stream the audio. If the player was already correctly playing, then no harm done.

Transitioning to background, AVPlayer Video has small audio gap

I have followed the many helpful previous questions to get my AVPlayer successfully streaming video when my app goes to the background. There are two methods described on Apple's QA1668 and they both work for my stream urls.
The problem is that there is a noticeable audio gap during the transition that is identical for both methods. On my iPhone 6 in release mode I would say the gap is less than 0.5 seconds, which may not seem terrible but if I'm playing something like a music video this is very distracting.
After more testing it looks like this gap actually occurs when I remove the AVPlayerLayer (or, if I am using the other method, when I disable the AVMediaCharacteristicVisual tracks) as I have determined it will still happen if I hook those actions up to a button rather than the backgrounding state.
My guess is that is has something to do with the audio re-syncing to the new video state of the AVPlayer but really I have no clue. Any help would be greatly appreciated!

Media pauses because of slow buffering, and then never recovers from it. How to handle this situation?

I think we all run into this as a user as well. For example, when I'm playing a Youtube video, and the connection is slow, it will not play until enough content has been buffered. But sometimes even after the content arrived it won't resume playing.
Most of the times when this happens I just click once somewhere on the player bar and it will resume.
Now, I think I've run into this situation while programming with HTML5 Audio elements and Youtube APIs. Most of the times they work well, but when the connection is spotty, it will just stop and never resume even after content has arrived. Is there a way to get around this problem? Thank you!
HTML5 Media Elements trigger a lot of useful events that might help you solve this problem. I would consider starting a timer when the waiting event fires (which indicates buffering) then periodically attempt to resume playing the track until canplay fires.
You could also call load instead of play then wait for canplaythrough fires (which indicates that media can play continuously without needing to pause for buffering).
Of course it's possible that the YouTube API prevents these events from propagating to the containing page, but it's worth a try.

MPMoviePlayerController blank frame after seeking to particular time-line

I am developing an iPhone application in which I play a video using MPMoviePlayerController. I use custom controls to play the video.
I have a slider that shows video time line. Using this user can seek the movie to any time-line of the movie.
When user continuously moves the slider:
Pause the video only for first time; [MPMoviePlayerController-obj pause]
MPMoviePlayerController-obj.currentPlaybackTime = slider.value
When slider action ends:
Play the video; [MPMoviePlayerController-obj play]
This plays the movie from the position where user had left the slider. But, it leads to blank frame when movie completes playing. This defect occurs randomly; i.e not for all the seek'd time.
What is the reason for getting the blank frame? How do I solve this?
I'm not sure if this will work, but try setting the initialPlaybackTime to either the slider.value or to currentPlaybackTime.
For being sure that your content is not flawed, hence possibly triggering that issue, you should try to replicate your faulty MPMoviePlayerController results using Apple's reference video content.
HTTP-Streaming: bipbop.m3u8
Progressive Download & Local
Playback: sample_mpeg4.mp4
I have personally observed many issues in connection with improper encoding. Weird things tend to happen when working with lossy compressed content. This is true for video (i-frames vs. p-frames) as well as audio (variable bitrate).
One being improper playback durations being reported. Such issue may result into an unexpected finished-state. I have seen cases where MPMoviePlayerController still shows a bunch of seconds to play even though the actual video has obviously finished. Those cases occur frequently once the user seeks around within the video.
Once you made sure that the issue occurs using the given sample files as well, you should file a bug-report.

Resources