Play video in reverse using AVPlayer and Swift on IOS 9 - ios

I have a recorded video clip that I want to play in reverse.
Playing forward is fine but as soon as I seek to the end of the video file and set the rate of playback to -1.0 the video clip seeks to the end of the clip (I see this in the timeline bar above the video) but does not play in reverse.
After I present the player view controller I check if it is ready to use:
print("readyForDisplay = \(playerViewController.readyForDisplay)")
This tells me that all is ready to prepare to play.
I check if reverse play is possible:
let reversePlay = playerViewController.player!.currentItem?.canPlayReverse
print("reversePlay = \(reversePlay)")
This returns TRUE
I then seek to the end of the clip and set the play back rate to -1.0 for reverse play.
playerViewController.player!.seekToTime(playerViewController.player!.currentItem!.asset.duration)
playerViewController.player!.rate = -1.0
I believe having got this far it is ready to play because if I add the following:
let status : AVPlayerItemStatus? = playerViewController.player!.currentItem?.status
if status == AVPlayerItemStatus.ReadyToPlay {
print("Ready to play")
}
It shows me that the clip is ready to play, so I am assuming that seeking to the end of clip (which is only 2 seconds long) has completed.
I then play the clip:
playerViewController.player!.play()
It plays fine if I don't seek to the end and attempt to change the rate to set it to reverse play.
What am I missing here?

I decided to add some logging after launching the video and found that the rate was -1 before launching and 1 immediately after so it seems that the rate is reset to 1.
Could this be a bug?
Anyway setting the rate immediately after the request to play the video has the desire effect.

Related

Check if Speaker is working programmatically in iOS

I want to check if my speaker is working sound or not programmatically.
Currently I was playing audio and recording that and checking if sound is recorded using peakPower.
recorder?.updateMeters()
let peakRecordedValue: Float = recorder?.peakPower(forChannel: 1) ?? 0.0
if peakRecordedValue <= 0 && peakRecordedValue >= -30 {
// Speaker is working
}
It was working fine for me. But there is a problem. If mic is not working or we have some issue in recording then it will not receive sound and I can't check if this problem is with mic or speaker.
Is there any other way to check if sound is coming from speakers without using other resources like mic.
PS: AVAudioSessionPortBuiltInSpeaker is the current port.

AVPlayer is in the ReadyToPlay status but unable to start a playback

Here is my code to start the video:
let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let playerAV = AVPlayer(url: videoURL! as URL)
let playerLayerAV = AVPlayerLayer(player: playerAV)
playerLayerAV.frame = ...
self.view.layer.addSublayer(playerLayerAV)
playerAV.play()
I can see the video preview, I can also see it's being loaded, I can even move the slider and see that preview is changing to the time I'm choosing. But if I hit play - nothing happens. I tried to press "play" button manually, I tried to call .play programmatically, the state of the "Play" button changes to "||" but then switches back to ">" right away.
I'm also tracking debug info related to the player state and I notice the following. Right when I created a player the status is below:
Status: ReadyToPlay
TimeControl: WaitingToPlayAtSpecifiedRate
ReasonToWait: AVPlayerWaitingToMinimizeStallsReason
Time: {0/1 = 0.000}
Rate: 1
Loaded Time Ranges: [Location=0,Length=0]
And it almost instantly changes its TimeControl: Paused and Rate: 0:
Status: ReadyToPlay
TimeControl: Paused
ReasonToWait:
Time: {0/1 = 0.000}
Rate: 0
Loaded Time Ranges: [Location=0,Length=0]
In both cases, it shows that playerItem.LoadedTimeRanges has one element but length and locations are 0 when the UI shows that the video has been completely loaded and ready to play.
Turned out that there is no issue with the video, views or controllers setup. The video is loaded and ready to play and paused right away because of a mode of the share audioSession. It was previously set to .record to process another app use-case.
The solution is to restore an original audioSession mode which includes playback and the video will play without any issues.

AudioKit and AVAssetWriter conflict ? No Audio on first record only

Context:
I am using AudioKit and GPUImage2 in my app.
I have a first screen (Record) to get a preview and record the camera.
I have a second screen (Play) to play the recorded movie and to process the audio (with AudioKit)
on Record screen, GPUImage2 uses a simple AVAssetWriter to capture video and audio. The audio is recorded with this trivial code:
guard (assetWriterAudioInput.isReadyForMoreMediaDatav) else {
return
}
if (!assetWriterAudioInput.append(sampleBuffer)) {
print("Trouble appending audio sample buffer")
} else {
}
This code is called as it should and assetWriterAudioInput is not nil.
On Play screen, I launch two players, a muted AVPlayer for video and a AKAudioPlayer for audio (to be processed) with the same file as source.
Two notes which if removed do not affect my issue.
During record, I play a music on top of the user voice, with AKAudioPlayer.
During the play, I put the music on a mixer with recorded voice (so 2 AKAudioPlayer into 1 output AKMixer)
During record, I play a music on top of the user voice, with AKAudioPlayer.
NB: during the play, I put the music on a mixer with recorded voice (so 2 AKAudioPlayer into 1 output AKMixer)
My issue is:
When I record the first time, I get only the video on Play screen, no audio has been recorded. The mixer is working good as I hear the music I add in it.
When I start again (back action to Record screen), I record normally and on Play screen, everything is functional -> video plays, voice+music is played.
Can someone help me to resolve this?
If it can help, the AudioSessionCategory I use is PlaybackCategory, it never changes during the app lifecycle, so same on first and next records. It only changes from Ambient to Playback at app launch because I let the speakers play with physical mute button active.

AVPlayerItem doesn't play video even its status is `readyToPlay` and `isPlaybackLikelyToKeepUp` is true

I'm playing live video with AVPlayer and AVPlayerItem. I'm observing AVPlayerItem's status, isPlaybackLikelyToKeepUp, and AVPlayerItemPlaybackStalled. I'm also observing AVPlayer's rate.
While I'm testing I found really weird thing happened.
While AVPlayer plays video normally(AVPlayerItem.status == readyToPlay and AVPlayerItem.isPlaybackLikelyToKeepUp == true), if I press home button, the AVPlayer.rate becomes 0.0. It means player stopped playing.
When app got back to foreground and I press play button, it is still AVPlayerItem.status == readyToPlay and AVPlayerItem.isPlaybackLikelyToKeepUp == true but paused and after a while it starts to play.
What I want is to know the player is paused or playing. In this case, even player is not playing video, the status indicates it is playing. (AVPlayerItem.status == readyToPlay, AVPlayerItem.isPlaybackLikelyToKeepUp == true, AVPlayer.rate == 1.0)
I checked AVPlayerItem's loadedTimeRanges and item.loadedTimeRanges.first is not nil(loadedTimeRanges has only one item) and its start and duration are not 0.
What should I check?
I'm adding little more.
This symptom only happens with streaming(m3u8) not with vod(mp4).
So I guess it is a problem of buffered data. While player is playing, buffer has data to play and the data is still valid. After app goes background and back to foreground, player's buffer still has data so isPlaybackLikelyToKeepUp == true, AVPlayerItem.status == readyToPlay. However when I try to play, AVPlayer flushes buffer because it is old.
It looks like the only way so far is create new AVPlayerItem and set when app is back to foreground.
What is the exact problem I'm encountering and want to know how to avoid it.
This is the repo I'm working on.
https://github.com/trick14/SLPlayer
The upper one is live and bottom one is VOD. After loading is done, play and go background and foreground couple times. And if you try to play, all status looks normal but player is stalled.
I have a similar experience long time ago.
At that time, I've stored the status of playing and the playback location when user press home button.
When return to the foreground, I used the stored information to restore or play the location.
I hope you were helpful.

Audio Start Delay For The First Time - ios Swift

I am creating an application with five buttons. When I click on each button each audio will play. It is working. Now my problem is when I click first button audio play with 1 second delay(App stuck for 1 second) and play. Next time clicks a button audio play without any delay. What could be the issue here?
I am using the following code to play an audio
var currentAudio = try? AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("sample_audio", ofType: "mp3")!));
currentAudio!.stop()
currentAudio!.currentTime = 0
currentAudio!.play();
Please someone help me to finds this issue.
You could use AVAudioPlayer's .prepareToPlay() method to preload the player's buffers, it will increase AVAudioPlayer's performance (faster start).
The idea is to prepare the player some time before actually playing it:
currentAudio?.prepareToPlay()
then later, in your play function, it will start immediately:
currentAudio?.play()

Resources