如何监控设备的音频输出以判断声音是不是来自扬声器/耳机插孔?

Posted

技术标签:

【中文标题】如何监控设备的音频输出以判断声音是不是来自扬声器/耳机插孔?【英文标题】:How can I monitor the device's audio output to be able to tell if sound is coming out of the speakers/headphone jack?如何监控设备的音频输出以判断声音是否来自扬声器/耳机插孔? 【发布时间】:2015-11-17 08:49:03 【问题描述】:

我需要在设备开始输出音频时立即启动操作。我正在使用 AVPlayer 并正在从 Parse 流式传输音频文件。使用等待 (AVPlayer.currentTime() != nil) 和 (AVPlayer.rate > 0) 等其他方法不够准确,我需要确切知道从设备输出音频的时间。我尝试使用 AVAudioEngine,然后附加一个具有 AVAudioNodeBus 的 AVAudioNode,但我无法让它工作。任何建议或技术都会非常好,谢谢!

这是我的 AudioEngine 代码。我在实例级别实例化 AudioEngine。创建standardFormat 时,我不知道standardFormatWithSampleRate 或通道块使用什么。当我尝试 installTapOnBus 时,我不知道该块使用什么,所以我输入了 nil,但这也会触发错误。任何帮助将不胜感激,我对 ios 开发人员非常陌生,并且已多次阅读 Apple 的文档,但我无法完全理解它,也无法在网上找到任何最近的示例。

class TableViewController: UITableViewController, AVAudioPlayerDelegate 

var iDArray = [String]()
var NameArray = [String]()


var durationInSeconds = Double()

var currentSong = String()




override func viewDidLoad() 
    super.viewDidLoad()



    let ObjectIDQuery = PFQuery(className: "Songs")
    ObjectIDQuery.findObjectsInBackgroundWithBlock 
        (objectsArray: [PFObject]?, error: NSError?) -> Void in

        //objectsArray!.count != 0
        var objectIDs = objectsArray!

        for i in 0...objectIDs.count-1 
                self.iDArray.append(objectIDs[i].valueForKey("objectId") as! String)
                self.NameArray.append(objectIDs[i].valueForKey("SongName") as! String)

                self.tableView.reloadData()
            

    

    do 
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        print("AVAudioSession Category Playback OK")
        do 
            try AVAudioSession.sharedInstance().setActive(true)
            print("AVAudioSession is Active")
         catch let error as NSError 
            print(error.localizedDescription)
        
     catch let error as NSError 
        print(error.localizedDescription)
    





func grabSong () 


    let songQuery = PFQuery(className: "Songs")
    songQuery.getObjectInBackgroundWithId(iDArray[SelectedSongNumber], block: 
        (object: PFObject?, error : NSError?) -> Void in


        if let audioFile = object?["SongFile"] as? PFFile 
            let audioFileUrlString: String = audioFile.url!
            let audioFileUrl = NSURL(string: audioFileUrlString)!


            AudioPlayer = AVPlayer(URL: audioFileUrl)
            AudioPlayer.play()

    )



func audioFunction() 

    var audioPlayerNode = AVAudioNode()
    var audioBus = AVAudioNodeBus()


    var standardFormat = AVAudioFormat(standardFormatWithSampleRate: <#T##Double#>, channels: <#T##AVAudioChannelCount#>)


    AudioEngine.attachNode(audioPlayerNode)

    audioPlayerNode.outputFormatForBus(audioBus)

    audioPlayerNode.installTapOnBus(audioBus, bufferSize: 100, format: standardFormat, block: nil)

    if AudioEngine.running == true 
        print("the audio engine is running")
     else 
        print("the audio engine is NOTTT running")
    




func attachNode(audioNode : AVAudioNode) 
    AudioEngine.attachNode(audioNode)

    AudioEngine.outputNode
    print(AudioEngine.outputNode.description)

    if AudioEngine.running == true 
        print("the audio engine is running")
     else 
        print("the audio engine is NOTTT running")
    


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

    return iDArray.count



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
    cell?.textLabel!.text = NameArray[indexPath.row]

    return cell!




override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

   SelectedSongNumber = indexPath.row
    grabSong()

我应该改用 AVAudioSession 吗?还是 AVCaptureSession?

【问题讨论】:

我很想给AVPlayer 添加一个水龙头。为什么不显示您的AVAudioEngine 代码?我很好奇为什么这不起作用。 抱歉,刚刚添加了它 您实际上是如何使用AVAudioEngine 播放流式音频文件的? 我更新了更多我的代码,因为它有助于清除任何东西。我实际上并没有使用 AudioEngine 播放流式音频文件。我使用 AVPlayer 构建了应用程序,现在我意识到要获得我正在寻找的精度,我需要以某种方式监控音频输出,而我发现这样做的唯一方法(我认为)是附加一个 AVAudioNode 我真的只想知道音频何时开始从设备输出。它不必连接到我的 AVPlayer,我只是想监控硬件的某些部分何时开始使用......这甚至可能吗? 【参考方案1】:

我会在AVPlayer 上使用音频点击来了解音频何时实际播放/即将播放。基本上,您会在音频播放到扬声器/耳机插孔之前收到音频点击回调。

一些复杂情况:我不确定如何获取某些流媒体类型(pls、icecast)的 AVAsset 曲目,但远程(和本地)mp3 文件可以正常工作。

var player: AVPlayer?

func doit() 
    let url = NSURL(string: "URL TO YOUR POSSIBLY REMOTE AUDIO FILE")!
    let asset = AVURLAsset(URL:url)
    let playerItem = AVPlayerItem(asset: asset)

    let tapProcess: @convention(c) (MTAudioProcessingTap, CMItemCount, MTAudioProcessingTapFlags, UnsafeMutablePointer<AudioBufferList>, UnsafeMutablePointer<CMItemCount>, UnsafeMutablePointer<MTAudioProcessingTapFlags>) -> Void = 
        (tap, numberFrames, flags, bufferListInOut, numberFramesOut, flagsOut) -> Void in

        // Audio coming out!
        let status = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, nil, numberFramesOut)
        print("get audio: \(status)\n")
    

    var callbacks = MTAudioProcessingTapCallbacks(
        version: kMTAudioProcessingTapCallbacksVersion_0,
        clientInfo: UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()),
        `init`: nil,
        finalize: nil,
        prepare: nil,
        unprepare: nil,
        process: tapProcess)

    var tap: Unmanaged<MTAudioProcessingTap>?
    let err = MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks, kMTAudioProcessingTapCreationFlag_PostEffects, &tap)

    if err != noErr 
        // TODO: something
    

    let audioTrack = playerItem.asset.tracksWithMediaType(AVMediaTypeAudio).first!
    let inputParams = AVMutableAudioMixInputParameters(track: audioTrack)
    inputParams.audioTapProcessor = tap?.takeUnretainedValue()

    let audioMix = AVMutableAudioMix()
    audioMix.inputParameters = [inputParams]

    playerItem.audioMix = audioMix

    player = AVPlayer(playerItem: playerItem)
    player?.play()

【讨论】:

谢谢,我会试试这个并报告

以上是关于如何监控设备的音频输出以判断声音是不是来自扬声器/耳机插孔?的主要内容,如果未能解决你的问题,请参考以下文章

Windows Phone 8 录制扬声器音频

如何连接多个音频输出通道以与 PyAudio 一起使用?

来自麦克风的声音与来自扬声器的声音

QT 5.7 分析音频输出

笔记本没有声音喇叭无声怎么办

获取设备音频输出