TheWidlarzGroup / react-native-video

A <Video /> component for react-native
https://docs.thewidlarzgroup.com/react-native-video/
MIT License
7.2k stars 2.9k forks source link

iOS - Ads are reproduced with sound even if muted or volume set to 0 #3068

Closed EmilianoMorghen closed 1 year ago

EmilianoMorghen commented 1 year ago

Bug

As you can see from the script, ads on iOS only, will be reproduced with audio ignoring muted or volume props. In Android this doesn't happen.

<Video
  style={StyleWebView.basic}
  source={{
    uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
  }}
  controls={true}
  muted={true}
  paused={props.pause}
  adTagUrl={
    'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator='
  }
/>

Platform

Environment info

React native info output:

System:
  OS: macOS 13.1
  CPU: (8) arm64 Apple M1 Pro
  Memory: 3.34 GB / 32.00 GB
  Shell: 5.8.1 - /bin/zsh
Binaries:
  Node: 19.4.0 - /opt/homebrew/bin/node
  Yarn: 1.22.19 - /opt/homebrew/bin/yarn
  npm: 9.2.0 - /opt/homebrew/bin/npm
  Watchman: 2023.01.16.00 - /opt/homebrew/bin/watchman
Managers:
  CocoaPods: 1.11.3 - /Users/emilianomorghen/.rvm/gems/ruby-3.1.0/bin/pod
SDKs:
  iOS SDK:
    Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1
  Android SDK: Not Found
IDEs:
  Android Studio: 2022.1 AI-221.6008.13.2211.9477386
  Xcode: 14.2/14C18 - /usr/bin/xcodebuild
Languages:
  Java: 11.0.17 - /usr/bin/javac
npmPackages:
  react: 17.0.2 => 17.0.2 
  react-native: 0.68.5 => 0.68.5 

Library version: v6.0.0-alpha.5

Expected behaviour

Audio of the ad should play muted

Reproducible sample code

<Video
  style={StyleWebView.basic}
  source={{
    uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
  }}
  controls={true}
  muted={true}
  paused={props.pause}
  adTagUrl={
    'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator='
  }
/>
francescoben commented 1 year ago

:wave: Hi there, I've spent some time examining the native code for react-native-video and also doing some research in the Google IMA SDK documentation and on the web. I've come to the conclusion that on iOS devices, ads need to be muted by setting the volume to 0 using the IMAAdsManager instance. It appears that this is due to a limitation in the way that iOS handles audio playback during ads. If I'm not wrong, the SDK uses WebViews to display ads on iOS, while on Android, the SDK uses ExoPlayer which has the ability to set the ads to mute without any issues.

I think I may have found a patch that could resolve the problem we're experiencing. I've tested it on my end and it seems to be working fine, but I'd like if you could try it out and let me know if it works for you as well.

diff --git a/ios/Video/Features/RCTIMAAdsManager.swift b/ios/Video/Features/RCTIMAAdsManager.swift
index 059ec63..2188485 100644
--- a/ios/Video/Features/RCTIMAAdsManager.swift
+++ b/ios/Video/Features/RCTIMAAdsManager.swift
@@ -76,6 +76,10 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
     // MARK: - IMAAdsManagerDelegate

     func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
+        // Mute ad if the main player is muted
+        if (_video.isMuted()) {
+            adsManager.volume = 0;
+        }
         // Play each ad once it has been loaded
         if event.type == IMAAdEventType.LOADED {
             adsManager.start()
diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift
index be1c098..cc0df2c 100644
--- a/ios/Video/RCTVideo.swift
+++ b/ios/Video/RCTVideo.swift
@@ -496,6 +496,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
         applyModifiers()
     }

+    @objc
+    func isMuted() -> Bool {
+        return _muted
+    }
+
     @objc
     func setMuted(_ muted:Bool) {
         _muted = muted

If the patch works and looks good for you, I can submit a PR to get it merged into the codebase. Let me know your thoughts.

Thanks!

freeboub commented 1 year ago

Hello, thank you for the patch. I definitely think you should open a PR with that change ! Just a thing, if you change volume/ mute state during ad playback, you should also apply the same logic ? (Change volume on adManager)

francescoben commented 1 year ago

hi @freeboub, thanks for your reply. I had thought of managing that case as well, but actually, with the current library, there is no command for volume or mute during the playback of the ad. Therefore, the user cannot activate/deactivate the audio during the playback of the ad. Am I missing something? Maybe you could give me a suggestion to solve this?