39091


Firebase上にあるデータをメモリ上に展開した後、AVAudioPlayer上で再生したいと思い、以下のようなViewController.swiftを書きました。

[code]

    import UIKit
    import FirebaseStorage
    import AVFoundation
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // StorageReferenceを作成
            let storage = Storage.storage()
            let storageRef = storage.reference(forURL: "<path>")
            let audioRef = storageRef.child("bird_sound.mp3")
    
            // メモリ上に音声をダウンロードして再生
            audioRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
                if let error = error {
                    print("DEBUG_PRINT: \(error)")
                } else {
                    let audioPlayer: AVAudioPlayer = try! AVAudioPlayer(data: data!)
                    audioPlayer.play()
                }
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }
    
[/code]

シミュレータで実行したところ、音は出ないのですが、何かしようとしているようで、

2017-10-28 10:25:46.273445+0900 audiotest[38079:27055100] [aqme] 254:
AQDefaultDevice (1): skipping input stream 0 0 0x0

というようなメッセージが繰り返し出ます。どのように書くのが正しいのでしょうか？


CC BY-SA 3.0
2017-10-28T01:54:17.020
39089
2017-10-28T02:46:41.207
25953
question
swift ios firebase
AVAudioPlayerでメモリ上のデータを再生したい


まず、「AQDefaultDevice (1): skipping input stream 0 0
0x0」のメッセージですが、無視して構いません。メッセージまるごとで検索をかければ、簡単にこのようなメッセージを出なくするための設定の仕方等も見つかると思います。

* * *

「音は出ない」の対処方法ですが、`AVAudioPlayer`のインスタンスは、再生中ずっと強参照でどこかに保持されていないといけないので、少なくともその部分は修正する必要があります。今のあなたのコードではせっかく作成して再生を始めた`AVAudioPlayer`が完了ハンドラー終了とともに解放されてしまい、そこで再生が止まってしまいます。

[code]

    class ViewController: UIViewController {
        var audioPlayer: AVAudioPlayer? //<- `audioPlayer`をインスタンス変数にする
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // StorageReferenceを作成
            let storage = Storage.storage()
            let storageRef = storage.reference(forURL: "<path>")
            let audioRef = storageRef.child("bird_sound.mp3")
    
            // メモリ上に音声をダウンロードして再生
            audioRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
                if let error = error {
                    print("DEBUG_PRINT: \(error)")
                } else {
                    do { //<- `try!`を使うとエラーが起こった時に原因がわからないままクラッシュする
                        //↓作成した`AVAudioPlayer`はインスタンス変数に保持する
                        self.audioPlayer = try AVAudioPlayer(data: data!)
                        self.audioPlayer?.play()
                    } catch {
                        print(error)
                    }
                }
            }
        }
    
        //...    
    }
    
[/code]

ついでに`try!`を使っているところを`do`-`try`-`catch`に変更してあります。動的に取得したデータから`AVAudioPlayer`を作成すると言う処理は「100%絶対にエラーにならない」とは言えないので、`try!`の使用はオススメできません。

* * *

あなたのFirebaseからデータを取ってくる部分は、こちらでは再現できないためまだ他に修正の必要があるかもしれません。お試しの上、何かあればコメント等でお知らせください。


CC BY-SA 3.0
2017-10-28T02:46:41.207
39091
2017-10-28T02:46:41.207
13972
39089
answer