MPVolumeViewで強制的にミュートにする
はじめに
youtube_ios_player_helperでインライン再生を行う時に音が出てしまいなんとかならないか調べている過程で、MPVolumeViewというものがありこれで強制的にミュートにさせることができそうだったので試してみました。
XCDYouTubeKitを使えばそんなこと考えなくて良いんですがYoutubeが認めてくれないので使えず…
Appleのガイドラインをみると音量に関して以下の記載があったので使い方によってはリジェクトされるかもしれません。
2.5.9 音量を上げる/下げる、サウンドオン/オフといった標準スイッチの機能、および他のネイティブユーザーインターフェイスの要素やその挙動を変更または無効にするAppは却下されます。たとえば、ユーザーがその動作を想定できる別のAppや機能に対するリンクをブロックすることはできません。リンクの適切な取り扱いについて詳しくは、こちらをご確認ください。
https://developer.apple.com/jp/app-store/review/guidelines/
コード
MPVolumeViewを使うにはMediaPlayerをimportする必要があります。
追加自体は他のViewと同じくこんな感じに追加することができます。
let volumeView = MPVolumeView(frame: CGRect.zero)
volumeView.layer.position = CGPoint(x: 0, y: view.frame.height/2)
volumeView.frame.size = CGSize(width: self.view.frame.width, height: 100)
self.view.addSubview(volumeView)
強制的にミュートにする
MPVolumeViewの保持しているUISliderを取得してvalueを0に設定してあげることで強制的にミュートになります。
guard let slider = volumeView.subviews.compactMap({ $0 as? UISlider }).first else {
return
}
slider.value = 0
コード一覧
検証ように作ったタップ開始で音量を0にして音を再生し、タップ終了で音量を元の状態に戻すサンプルコード
import UIKit
import MediaPlayer
import AVFoundation
class ViewController: UIViewController {
var audioPlayer: AVAudioPlayer!
let volumeView = MPVolumeView(frame: CGRect.zero)
var prevBolume:Float = 0
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .orange
//音の初期化
let path = Bundle.main.path(forResource: "sample", ofType: "mp3")
let url = URL(fileURLWithPath: path!)
try! audioPlayer = AVAudioPlayer(contentsOf: url)
audioPlayer.prepareToPlay()
//画面に表示させないようにする
volumeView.isUserInteractionEnabled = false
volumeView.alpha = 0.0001
self.view.addSubview(volumeView)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
guard let slider = volumeView.subviews.compactMap({ $0 as? UISlider }).first else {
return
}
prevBolume = slider.value
slider.value = 0
if audioPlayer.isPlaying {
audioPlayer.stop()
audioPlayer.currentTime = 0
}
audioPlayer.play()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
guard let slider = volumeView.subviews.compactMap({ $0 as? UISlider }).first else {
return
}
slider.value = prevBolume
}
}