web-dev-qa-db-ja.com

iOSで音声の音量レベルと音量変更通知を取得する方法は?

ボタンを押すと音が鳴る非常にシンプルなアプリケーションを作成しています。デバイスが無音に設定されている場合、そのボタンはあまり意味をなさないため、デバイスの音量がゼロの場合は無効にします。 (その後、ボリュームが再びクランクアップされたときに再び有効にします。)

現在の音量設定を検出するへの有効な(およびAppStoreセーフ)方法を探しており、音量レベルが変化したときに通知/コールバックを取得します。 I音量を変更したくない設定。

これはすべて、上記のボタンが使用されるViewControllerに実装されています。 iOS 4.0.1および4.0.2を実行するiPhone 4と4.0.1を実行するiPhone 3Gでこれをテストしました。 llvm 1.5を備えたiOS SDK 4.0.2で構築。 (gccまたはllvm-gccを使用しても何も改善されません。)どちらの方法でも、ビルド中に問題はなく、エラーも警告もありません。静的アナライザーも同様に満足しています。

ここに私がこれまで試したものがありますが、すべて成功していません。

Appleのオーディオサービスドキュメントに従って、kAudioSessionProperty_CurrentHardwareOutputVolumeAudioSessionAddPropertyListenerを登録する必要があります。

// Registering for Volume Change notifications
AudioSessionInitialize(NULL, NULL, NULL, NULL);
returnvalue = AudioSessionAddPropertyListener (

kAudioSessionProperty_CurrentHardwareOutputVolume ,
      audioVolumeChangeListenerCallback,
      self
);

returnvalue0です。これは、コールバックの登録が機能したことを意味します。

悲しいことに、デバイスのボリュームボタン、ヘッドセットクリッカー、または着信音とサイレントスイッチを切り替えると、関数audioVolumeChangeListenerCallbackにコールバックが届きません。

kAudioSessionProperty_AudioRouteChange(WWDCビデオ、開発者向けドキュメント、およびインターウェブ上の多数のサイトで類似のサンプルプロジェクトとして使用)の登録にまったく同じコードを使用する場合、実際にはdoオーディオルートの変更時にコールバックを取得します(ヘッドセットのプラグイン/アウトまたはデバイスのドッキングによる)。

Doug という名前のユーザーが iPhoneのボリュームが既に最大のボリュームのイベントを変更したというタイトルのスレッド を開いたところ、この方法をうまく使用していると主張しました(既に最大に設定されています)。それでも、私にはうまくいきません。

私が試した別の方法は、NSNotificationCenterでこのように登録することです。

// sharedAVSystemController 
AudioSessionInitialize(NULL, NULL, NULL, NULL);
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
                                         selector:@selector(volumeChanged:) 
                                             name:@"AVSystemController_SystemVolumeDidChangeNotification" 
                                           object:nil];

これは、volumeChangedの変更をメソッドSystemVolumeに通知する必要がありますが、実際には通知しません。

Cocoaで何かを達成するために一生懸命働いていると、根本的に間違ったことをしていると一般的に信じられているので、ここで何かを見逃すことを期待しています。no simple waytoget現在の音量レベルがあるとは信じがたいが、まだAppleのドキュメント、サンプルコード、Google、Apple Developer Forums、またはWWDC 2010のビデオを見ると使用できます。

56
MacLemon

VolumeChanged:メソッドに対して間違った署名をした可能性はありますか?これは私のために働いて、私の代理人に捨てられました:

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(volumeChanged:)
     name:@"AVSystemController_SystemVolumeDidChangeNotification"
     object:nil];
}

- (void)volumeChanged:(NSNotification *)notification
{
    float volume =
    [[[notification userInfo]
      objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"]
     floatValue];

    // Do stuff with volume
}

私のvolumeChanged:メソッドは、ボリュームが結果として変化しない場合でも(ボタンが既に最大/最小になっているため)ボタンが押されるたびにヒットします。

67
Sandy

ここでいくつかの回答で使用されているAudioSession AP​​Iは、iOS 7で非推奨になりました。システム全体の出力ボリュームのAVAudioSessionプロパティを公開するoutputVolumeに置き換えられました。これは、ドキュメントで指摘されているように、KVOを使用してボリュームが変更されたときに通知を受信することで確認できます。

0.0から1.0の範囲の値。0.0は最小ボリュームを表し、1.0は最大ボリュームを表します。

システム全体の出力ボリュームは、ユーザーのみが直接設定できます。アプリでボリュームコントロールを提供するには、MPVolumeViewクラスを使用します。

キー値監視を使用して、このプロパティの値の変化を監視できます。

これが機能するには、アプリのオーディオセッションがアクティブであることを確認する必要があります。

let audioSession = AVAudioSession.sharedInstance()
do {
    try audioSession.setActive(true)
    startObservingVolumeChanges()
} catch {
    print(“Failed to activate audio session")
}

したがって、必要なのが現在のシステムボリュームのクエリだけである場合:

let volume = audioSession.outputVolume

または、次のような変更の通知を受けることができます。

private struct Observation {
    static let VolumeKey = "outputVolume"
    static var Context = 0

}

func startObservingVolumeChanges() {
    audioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.Initial, .New], context: &Observation.Context)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeNewKey] as? NSNumber)?.floatValue {
            // `volume` contains the new system output volume...
            print("Volume: \(volume)")
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}

忘れないでください割り当てを解除する前に監視を停止するには:

func stopObservingVolumeChanges() {
    audioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}
49
Stuart
-(float) getVolumeLevel
{
    MPVolumeView *slide = [MPVolumeView new];
    UISlider *volumeViewSlider;

    for (UIView *view in [slide subviews]){
        if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
            volumeViewSlider = (UISlider *) view;
        }
    }

    float val = [volumeViewSlider value];
    [slide release];

    return val;
}

これで現在の音量レベルが得られます。 1は最大音量、0は音量なしです。注:これが機能するためにUI要素を表示する必要はありません。また、現在の音量レベルはヘッドフォンまたはスピーカーを基準にしていることに注意してください(つまり、2つの音量レベルは異なります。これにより、現在使用しているデバイスを取得できます。

6
Mike

audioSession SetActiveでオーディオセッションを開始しましたか

4
Karsten

Stuartの優れた答えのSwift 3バージョン:

let audioSession = AVAudioSession.sharedInstance()

do {
    try audioSession.setActive(true)
    startObservingVolumeChanges()
} 
catch {
    print("Failed to activate audio session")
}

let volume = audioSession.outputVolume

private struct Observation {
    static let VolumeKey = "outputVolume"
    static var Context = 0
}

func startObservingVolumeChanges() {
    audioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.Initial, .New], context: &Observation.Context)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeNewKey] as? NSNumber)?.floatValue {
            // `volume` contains the new system output volume...
            print("Volume: \(volume)")
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}
2

AVAudioSessionを使用して、Swift 3.のいくつかの変更を説明するStuartの答えに追加します。各コンポーネントがどこに行くかをコードが明確にすることを望みます。

override func viewWillAppear(_ animated: Bool) {
    listenVolumeButton()
}

func listenVolumeButton(){
   let audioSession = AVAudioSession.sharedInstance()
   do{
       try audioSession.setActive(true)
       let vol = audioSession.outputVolume
       print(vol.description) //gets initial volume
     }
   catch{
       print("Error info: \(error)")
   }
   audioSession.addObserver(self, forKeyPath: "outputVolume", options: 
   NSKeyValueObservingOptions.new, context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "outputVolume"{
        let volume = (change?[NSKeyValueChangeKey.newKey] as 
        NSNumber)?.floatValue
        print("volume " + volume!.description)
    }
}

 override func viewWillDisappear(_ animated: Bool) {
     audioSession.removeObserver(self, forKeyPath: "outputVolume")
 }
1
Abundance

スイフト4

func startObservingVolumeChanges() {
    avAudioSession.addObserver(self, forKeyPath: Observation.VolumeKey, options: [.initial, .new], context: &Observation.Context)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if context == &Observation.Context {
        if keyPath == Observation.VolumeKey, let volume = (change?[NSKeyValueChangeKey.newKey] as? NSNumber)?.floatValue {
            print("\(logClassName): Volume: \(volume)")
        }
    } else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

func stopObservingVolumeChanges() {
    avAudioSession.removeObserver(self, forKeyPath: Observation.VolumeKey, context: &Observation.Context)
}

そして、あなたは電話する

var avAudioSession = AVAudioSession.sharedInstance()
try? avAudioSession.setActive(true)
startObservingVolumeChanges()
1
Reimond Hill

他の実装に依存すると思います。たとえば、スライダーを使用して音量を制御する場合は、UIControlEventValueChangedで確認アクションを実行でき、0の値を取得する場合は、ボタンを非表示または無効に設定できます。

何かのようなもの:

[MusicsliderCtl addTarget:self action:@selector(checkZeroVolume:)forControlEvents:UIControlEventValueChanged];

void checkZeroVolumeは、ボリュームの変更後にトリガーされるため、実際のボリュームの比較を実行できます。

1
Vanya

設定->サウンドに移動し、「ボタンで変更」をチェックします。オフの場合、音量ボタンを押してもシステムの音量は変わりません。たぶんそれがあなたに通知されなかった理由です。

0
fantaxy