Andrew Smith
Andrew Smith

Reputation: 13

ARKit: Stop AVPlayer Audio when not in view

I am working on an ARKit Image Tracking app that overlays an AVPlayer video on an Image Target (Swift5 and XCode 13). I currently have it set up to only track 1 image simultaneously, but there are multiple Image Targets in my AR Reference Group with unique videos.

This is all working fine, except one issue -- each video's audio continues to play even when the video is no longer being tracked and rendered by the AR Camera. The audio even keeps playing if the user navigates to a different View Controller in the app.

How can I stop the AVPlayer Audio when its Image Target is no longer being tracked?

There's a lot of code and I'm not sure what is necessary to help solve the issue (not including everything initially), please let me know if additional information would be useful.

Setting up plane with AVPlayer as a material

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {

    let node = SCNNode()


    if let imageAnchor = anchor as? ARImageAnchor {

        let size = imageAnchor.referenceImage.physicalSize


        let videoUrl = Bundle.main.url(forResource: "Nine", withExtension: "mp4")!
        let videoPlayer = AVPlayer(url: videoUrl)
        videoPlayer.play()
        let plane = SCNPlane(width: size.width, height: size.height)
        plane.firstMaterial?.diffuse.contents = videoPlayer
        let planeNode = SCNNode(geometry: plane)
        planeNode.eulerAngles.x = -.pi / 2
    }

    node.addChildNode(planeNode)
}

return node

Thank you for any help!!

Upvotes: 1

Views: 501

Answers (2)

Steve Brown
Steve Brown

Reputation: 21

There is an easier way to stop the video and audio when the anchor is no longer being tracked. You need to remove the node in didUpdate() using sceneView.session.remove(). Do it like this:

 
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {

        if node.isHidden == true {
            if let imageAnchor = anchor as? ARImageAnchor {
                sceneView.session.remove(anchor: imageAnchor)
                player.pause()
            }
        } else {
            player.play()
        }
    }

You also need to pause the player when the anchor is out of view, otherwise the audio keeps going.

Upvotes: 0

Ivan Nesterenko
Ivan Nesterenko

Reputation: 969

  1. Store the videoPlayer

    var videoPlayer: AVPlayer?    
    
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
      let node = SCNNode()
      if let imageAnchor = anchor as? ARImageAnchor {
      ...
      let videoUrl = Bundle.main.url(forResource: "Nine", withExtension: "mp4")!
      let videoPlayer = AVPlayer(url: videoUrl)
      videoPlayer.play()
      self.videoPlayer = videoPlayer 
      ...
      }
    }
    
  2. Check if the current frame has any image anchors, pause the video if it does not.

    func session(_ session: ARSession, didUpdate frame: ARFrame) {
      if frame.anchors.filter({$0 is ARImageAnchor}).count == 0 {
        videoPlayer?.pause()
      }
    }
    

Upvotes: 1

Related Questions