1

My screen cracked and my phone has no sound capabilities. I recorded a video using the camera. When I select the video url from didFinishPickingMediaWithInfo I tried to check if the video has sound or not but player.currentItem?.asset.tracks says the video does have sound (the device and recorded video definitely has no sound).

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

   // ...
   guard let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL else { return }

   // ...
   let asset = AVURLAsset(url: url)
   let playerItem = AVPlayerItem(asset: asset)
   let player = AVPlayer(playerItem: playerItem)

   if let tracks = player.currentItem?.asset.tracks {
                
       switch tracks.count {
       case 0:
           print("tracks -0: audio only")
                    
       case 1:
           print("tracks -1: video only ")

       case 2:
           print("tracks -2: audio and video") // this prints when the video does have sound (recorded before the screen cracked)
                    
       default:
           print("tracks -default: audio and video") // *** this always prints when the video doesn't have sound (recorded after the screen cracked) ***       
       }   
   }
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256

1 Answers1

3

This is the way to do it:

let asset = AVURLAsset(url: url)
// if using a mixComposition it's: let asset = mixComposition (an AVMutableComposition itself is an asset)

let audioTrack = asset.tracks(withMediaType: .audio)
if audioTrack.isEmpty {

    print("this video has no sound")

} else {

    print("this video has sound")
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • This detects if it has an audio track. What if it has an audio track and no sound? How do you check if it has an audio track and no sound? – stefanosn Jan 15 '22 at 16:36
  • 1
    Are you detecting tracks that come from some where else or do you provide it? For example with my broken device I could record video but no sound. What I would do is supply a silent audio track to substitute. When I save I have a `noSound` property set to true. Later when what is saved is read from somewhere else within my app I would just look for that property to check for sound. Of course this is within the context of saving/reading from within my own app. There’s no way to pull in recording from anywhere else in my app without saving from my app to begin with. Does that help you? – Lance Samaria Jan 15 '22 at 17:50
  • 1
    Try this for a silent audio track https://bigsoundbank.com/detail-0917-one-minute-of-silence.html – Lance Samaria Jan 15 '22 at 17:53
  • Thanks for responding. Yes it is possible in our app to download a video from internet save it in photos and upload it through our app. So as i understand there is no way to find if an audio track has sound or not via the AVAsset right? – stefanosn Jan 15 '22 at 18:14
  • 1
    I just added a comment to your question. This is what you're looking for https://stackoverflow.com/a/52280271/4833705. Check if the noise level is anything less than -80dB and if it is it will be considered as silence. – Lance Samaria Jan 15 '22 at 18:16
  • 1
    You can also check this WWDC video https://developer.apple.com/videos/play/wwdc2015/508/ – Lance Samaria Jan 15 '22 at 18:18
  • Thanks again although i do not understand the code in the question you mentioned i will try to find a way to find the noise level. One question please. I have to use AVplayer to play the video and after it starts playing i have to use AVfoundation to find noise level? I am not that experienced that is why i am asking. Any help appreciated. – stefanosn Jan 15 '22 at 18:40
  • 1
    Gimme a few, I'll help you out. I'm not an Audio expert but I'll try to get you in the right direction with the code form that answer. – Lance Samaria Jan 15 '22 at 19:03
  • 1
    1- create a new project. 2- create a class named `AudioContext` and add the code in that answer from step (A). 3- In the separate ViewController class (use the one from the project), add all of the code from steps (B), (C), (D), (E), and (F). 4- Drag 2 video or audio files into the project. One with loud sound and one with silent sound. 5- After you drag in the files, in the ViewController class in `viewDidLoad` add the code from step (G) but obviously use your video file's name instead. – Lance Samaria Jan 15 '22 at 19:33
  • 1
    6- He doesn's say at what point to check the `noiseFloor` but it seems in step (G) you might have to check if the `outputArray` is less than `-80`. The last part I'm not sure about but if you play with it enough you'll figure it out. Once you get the basic setup going (it's easy because you can c+p his code) you can then message him to ask him how to check the `noiseFloor` in step (G). The thing is you have to get it working on a basic level before you message him. Make sure you use the code from the Swift 5 part of his answer – Lance Samaria Jan 15 '22 at 19:35
  • 1
    As far as your question. The way I would do it is I would first get the url, second check for sound using the code from his answer, then third I would play the video last. – Lance Samaria Jan 15 '22 at 20:01
  • 1
    Thanks for your help i will try it out and let you know! – stefanosn Jan 15 '22 at 21:42
  • 1
    Hey, one more thing, about what I said earlier. I'm not how you go about playing your videoUrls. I save my videoUrls to the Temp Dir and play from there. Either way, let's assume this sound check takes some time. Maybe 1) fetch url 2) play vid 3) while the vid is playing check for the sound db. If it's not there then show a message "this video has no sound" or whatever you intend on doing. The reason I added this is it might take some time to process and immediately playing the video with or without sound is more important then having the user wait for the vid to load while looking for sound. – Lance Samaria Jan 15 '22 at 22:03