Player component for iOS - bugs

That's pretty much the same as what we do. The source code for the Player is available on GitHub:

1 Like

Thanks, good to know which audio formats should work then. (Especially with the compiled app/IPA).

I didn't know until today that the AI2 source code for iOS/Swift was available on github. :upside_down_face: :face_with_monocle:
(But I probably should have known.)

Yep, we released the iOS code under the same Apache 2 license as the rest of the code base back in March. See my blog post for more information.

1 Like

Unfortunately not, because seamless looping would work with the AVFoundation framework:

In addition, the sound stops in the background.
Tested with the IPA & Companion.

Unfortunately, I think I have to program it natively with Xode & Swift.
I hope that won't be necessary. :pray:

Note: PlayOnlyInForeground is not enabled, so there is a bug.
@ewpatton

This might explain it:

What about using the AVFoundation framework (instead of AVKit)?

When I asked whether the AVKit Foundation was suitable for seamless looping, I received the following answer from ChatGPT:

The AVKit framework is primarily intended for video playback and management. For seamless looping of audio files, the AVFoundation framework is more suitable. Specifically, the AVAudioPlayer or AVPlayer object from AVFoundation can be used for audio playback.

Here is a simple example using AVAudioPlayer in Swift to seamlessly loop an audio file:

import AVFoundation
class AudioLooper: NSObject, AVAudioPlayerDelegate {
    var audioPlayer: AVAudioPlayer?

    override init() {
        super.init()

        guard let audioFileURL = Bundle.main.url(forResource: "YourAudioFile", withExtension: "caf") else {
            print("Audio file not found.")
            return
        }

        do {
            audioPlayer = try AVAudioPlayer(contentsOf: audioFileURL)
            audioPlayer?.delegate = self
            audioPlayer?.numberOfLoops = -1 // -1 means infinite looping
            audioPlayer?.prepareToPlay()
        } catch {
            print("Error initializing AVAudioPlayer: \(error.localizedDescription)")
        }
    }

    func play() {
        audioPlayer?.play()
    }

    func stop() {
        audioPlayer?.stop()
    }

    // AVAudioPlayerDelegate method for seamless looping
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        if flag {
            player.play()
        }
    }
}

// Using the class
let audioLooper = AudioLooper()
audioLooper.play()

Replace "YourAudioFile" with the name of your audio file and adjust the file extension. This implementation uses AVAudioPlayer and sets numberOfLoops to -1 to enable infinite looping. The delegate is used to implement the audioPlayerDidFinishPlaying method, which triggers replay when playback finishes.

Keep in mind that this is a simple example and may not be suitable for all use cases. Depending on your application's requirements, you might also consider using AVPlayer and AVPlayerLooper for more advanced features.


And this is pretty similar to how I did it with Xcode & Swift.

Strangely, the AVFoundation framework is imported/used for the VideoPlayer component:

Why not for the Player component?
@ewpatton

Here is a suggestion on how to play a sound also in the background (idle mode) using the AVFoundation framework:

import AVFoundation

class AudioPlayer {
    var player: AVAudioPlayer?

    init() {
        // Configure the audio session for background playback
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
            try AVAudioSession.sharedInstance().setActive(true)
        } catch {
            print("Error configuring audio session: \(error.localizedDescription)")
        }
    }

    func playAudio() {
        guard let audioFileURL = Bundle.main.url(forResource: "your_audio_file", withExtension: "mp3") else {
            print("Audio file not found.")
            return
        }

        do {
            // Initialize AVAudioPlayer
            player = try AVAudioPlayer(contentsOf: audioFileURL)
            player?.numberOfLoops = -1 // -1 means infinite looping
            player?.prepareToPlay()
            player?.play()
        } catch {
            print("Error initializing AVAudioPlayer: \(error.localizedDescription)")
        }
    }
}

// Example usage
let audioPlayer = AudioPlayer()
audioPlayer.playAudio()

Do you see an opportunity to consider this in the new year? Of course, the Player component should also be able to play in the background (as is the case with Android). In addition, the problem with seamless looping could also be (easily) solved with the AVFoundation framework.

It would be nice to hear from you about this before Christmas. :pray:

1 Like

We may end up needing different logic in the companion versus not, but we will see. In particular, I would be concerned that Apple might decide that background audio support is not necessary in the companion and reject an update that includes that. If that ends up being the case, we will have to wire things up in some way that compiled apps can take the background audio capability.

1 Like

Of course it doesn't matter how it's arranged with Companion. In any case it should work with the compiled app. And where is the problem in using the AVFoundation framework also for the Player component (and not just for the VideoPlayer component)?

Nothing precludes us from switching other than the time to update and test everything. The two components were implemented by two different individuals at different times and so different frameworks ended up being used.

1 Like

Ok, I'll do the testing and I'm pretty thorough at it. :smiley:

Btw, the VideoPlayer also has some issues.
I tried to play a loopable sound (caf/IM4A format, duration 11 sec) with the VideoPlayer:

grafik

.GetDuration and .SeekTo_ms are in sec (not millis).

And unfortunately there is no loop setting (unlike the Player), because since the VideoPlayer uses AVFoundation, looping would most likely work with the VideoPlayer component.

However, as expected, the VideoPlayer does not play in the background (which usually makes sense, as long as you don't use it as an audio player).

Thanks for the report. I've fixed the issue of seconds vs milliseconds in this PR:

1 Like

The Player related issues will be fixed as part of PR 3078:

We are waiting for TestFlight review of 2.64.6, which will have both sets of changes. I will post a formal announcement once that's available.

1 Like

Thank you VERY MUCH! :+1:

1 Like

This is most likely my best Christmas present (regardless of whether I even get another one :wink:).
Merry Christmas!

1 Like