📷

カメラ画面でHaptic Feedbackを使いたい #iOS #Swift

2023/12/18に公開

カメラ機能をカスタムしようとすると AVFoundationAVCaptureSession を中心に利用することになると思います。(ARKitなどは除く)
そこでたとえばシャッターを押したときや、ズームの倍率を変更した際に Haptic Feedback(触覚フィードバック)機能 を使ってユーザーにリアクションを伝えたいという場面があります。
ただ、愚直に設定してもHaptic Feedbackは動作しないのでどうしたらいいんだろうと頭を悩ませていました。
ちなみに try AVAudioSession.sharedInstance().setAllowHapticsAndSystemSoundsDuringRecording(true) を設定すればいいと思っていたのですが、それすら無視されているような挙動をしていました。

ただ、これは設定の順番が誤っていたようで、

    let session = AVCaptureSession()
    let audioDevice = AVCaptureDevice.default(for: .audio)
    var audioDeviceInput: AVCaptureDeviceInput?
    var videoDeviceInput: AVCaptureDeviceInput?

    let backVideoDeviceDiscoverySession = AVCaptureDevice.DiscoverySession(
        deviceTypes: [.builtInDualCamera, .builtInWideAngleCamera],
        mediaType: .video,
        position: .back
    )

    let fileOutput = AVCaptureMovieFileOutput()

    func configureSettings() throws {
        // before
	try AVAudioSession.sharedInstance().setAllowHapticsAndSystemSoundsDuringRecording(true)
        session.beginConfiguration()
        if let audioDevice {
            let audioInput = try AVCaptureDeviceInput(device: audioDevice)
            if session.canAddInput(audioInput) {
                session.addInput(audioInput)
            }
            else {
                throw VideoRecorderErrors.audioInputAddFailed
            }
            audioDeviceInput = audioInput
        }
        if let device = backVideoDeviceDiscoverySession.devices.first {
            let videoInput = try AVCaptureDeviceInput(device: device)
            if session.canAddInput(videoInput) {
                session.addInput(videoInput)
            }
            else {
                throw VideoRecorderErrors.videoInputAddFailed
            }
            videoDeviceInput = videoInput
        }
        fileOutput.maxRecordedDuration = maxTimeDuration
        session.addOutput(fileOutput)

        session.commitConfiguration()
    }

元々はこんな感じで AVCaptureSession の設定をする前に AVAudioSession の設定をしていたのですが、

        session.commitConfiguration()
	// after
	try AVAudioSession.sharedInstance().setAllowHapticsAndSystemSoundsDuringRecording(true)
    }

こんな感じで AVCaptureSession の設定が完了後に AVAudioSession の設定を更新すればうまく動きました。

どうも AVCaptureSessionAVCaptureDeviceInput(device: audioDevice) を追加するタイミングで AVAudioSession の設定が初期化されるらしく、他にも動画再生と音楽再生を同時にしようとすると、カメラ画面を起動した前後で挙動が変わるといった問題も起きていました。
これは動画再生前に

try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: .mixWithOthers)

を実行すれば回避できました。

まとめ

なんとなくOSの気持ちになれば理解できるのですが、不具合が起きてる時は焦るので冷静に考えられませんでした。
なんとか直ってよかったです。

Discussion