Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Sound ChangeEffect #11

Closed
mergesort opened this issue Oct 23, 2022 · 1 comment · Fixed by #15
Closed

Feature Request: Sound ChangeEffect #11

mergesort opened this issue Oct 23, 2022 · 1 comment · Fixed by #15
Labels
Enhancement New feature or request

Comments

@mergesort
Copy link
Collaborator

I really love the way that you've included a .haptic ChangeEffect, and was wondering if it'd be possible to do the same for playing a sound.

Right now I have my own homegrown that I expose through the environment like so

@Environment(\.sounds) private var sounds

And it's invoked by calling the playSound method like this.

sounds.playSound(effect: .plinkSound, source: self.preferences.preferredSoundSource)

I'm envisioning a solution that looks much like .changeEffect(.haptic(.success), value: someStateChanged), but instead of .haptic it would be .changeEffect(.sound(.plinkSound), value: someStateChanged).

I'm also including the complete solution if it can be of any help, or provide any more context, please let me know if there's any more information that would be helpful.

public enum SoundEffect {
    case dataAsset(NSDataAsset)
    case file(filename: String, `extension`: String)
}

public final class Sounds {

    public enum Source: String {
        case none
        case headphones
        case speakers
    }

    private var player: AVAudioPlayer?

    public init() {}

    public func playSound(effect: SoundEffect, source: Source) {
        let shouldPlaySound: Bool

#if targetEnvironment(simulator)
        shouldPlaySound = true
#else
        switch source {

        case .none:
            shouldPlaySound = false

        case .headphones:
            shouldPlaySound = AVAudioSession.sharedInstance().currentRoute.outputs.map(\.portType).contains(where: { $0 == .headphones || $0 == .bluetoothA2DP })

        case .speakers:
            shouldPlaySound = true

        }
#endif

        if shouldPlaySound {
            do {
                try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
                try AVAudioSession.sharedInstance().setActive(true)

                switch effect {

                case .dataAsset(let dataAsset):
                    self.player = try AVAudioPlayer(data: dataAsset.data)

                case .file(let filename, let fileExtension):
                    guard let url = Bundle.module.url(forResource: filename, withExtension: fileExtension) else { return }
                    self.player = try AVAudioPlayer(contentsOf: url)
                }

                self.player?.play()
            } catch let error {
                print(error.localizedDescription)
            }
        }
    }

}

private enum SoundEnvironmentKey: EnvironmentKey {
    static let defaultValue = Sounds()
}

public extension EnvironmentValues {
    var sounds: Sounds {
        get { self[SoundEnvironmentKey.self] }
        set { self[SoundEnvironmentKey.self] = newValue }
    }
}
@robb
Copy link
Contributor

robb commented Oct 25, 2022

Yeah, makes sense – we're looking into it.

@robb robb added the Enhancement New feature or request label Oct 25, 2022
@robb robb linked a pull request Dec 7, 2022 that will close this issue
@robb robb closed this as completed in #15 Jan 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants