Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c CoreAudio AudioObjectRemovePropertyListener未在Swift中工作_Objective C_Swift_Closures_Core Audio - Fatal编程技术网

Objective c CoreAudio AudioObjectRemovePropertyListener未在Swift中工作

Objective c CoreAudio AudioObjectRemovePropertyListener未在Swift中工作,objective-c,swift,closures,core-audio,Objective C,Swift,Closures,Core Audio,我正在swift中使用CoreAudio,需要查找用户何时更改系统音量 我可以正确地获取卷,甚至可以添加一个属性侦听器,以便在用户更改卷时查找。但是我需要在某个时刻停止侦听(如果用户更改了默认输出设备),但我无法删除属性侦听器 我已经为Playerd创建了一个基本测试,并在命令行obj-c项目中进行了相同的测试。该测试在obj-c中运行良好,但在swift中不起作用 代码只是添加侦听器,然后将其删除,因此在运行代码后更改卷应该不会打印任何内容,但在swift中它会继续打印 swift代码: im

我正在swift中使用CoreAudio,需要查找用户何时更改系统音量

我可以正确地获取卷,甚至可以添加一个属性侦听器,以便在用户更改卷时查找。但是我需要在某个时刻停止侦听(如果用户更改了默认输出设备),但我无法删除属性侦听器

我已经为Playerd创建了一个基本测试,并在命令行obj-c项目中进行了相同的测试。该测试在obj-c中运行良好,但在swift中不起作用

代码只是添加侦听器,然后将其删除,因此在运行代码后更改卷应该不会打印任何内容,但在swift中它会继续打印

swift代码:

import CoreAudio

//first get default output device
var outputDeviceAOPA:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
    mSelector: kAudioHardwarePropertyDefaultOutputDevice,
    mScope: kAudioObjectPropertyScopeGlobal,
    mElement: kAudioObjectPropertyElementMaster)

var outputDeviceID = kAudioObjectUnknown
var propertySize = UInt32(sizeof(AudioDeviceID))
AudioObjectGetPropertyData(UInt32(kAudioObjectSystemObject), &outputDeviceAOPA,
    0, nil, &propertySize, &outputDeviceID)

// get volume from device
var volumeAOPA:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
    mSelector: kAudioDevicePropertyVolumeScalar,
    mScope: kAudioObjectPropertyScopeOutput,
    mElement: kAudioObjectPropertyElementMaster
)
var volume:Float32 = 0.5
var volSize = UInt32(sizeof(Float32))

AudioObjectGetPropertyData(outputDeviceID, &volumeAOPA, 0, nil, &volSize, &volume)
print(volume)

var queue = dispatch_queue_create("testqueue", nil)
var listener:AudioObjectPropertyListenerBlock = {
    _, _ in
    AudioObjectGetPropertyData(outputDeviceID, &volumeAOPA, 0, nil, &volSize, &volume)
    print(volume)
}

AudioObjectAddPropertyListenerBlock(outputDeviceID, &volumeAOPA, queue, listener)
AudioObjectRemovePropertyListenerBlock(outputDeviceID, &volumeAOPA, queue, listener)

while true{
    //keep playground running
}
这是objective-c代码:

//objective-c code working
//  main.m
//  objccatest

#import <Foundation/Foundation.h>
#import <CoreAudio/CoreAudio.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        //first get default output device

        AudioObjectPropertyAddress outputDeviceAOPA;
        outputDeviceAOPA.mSelector= kAudioHardwarePropertyDefaultOutputDevice;

        outputDeviceAOPA.mScope= kAudioObjectPropertyScopeGlobal;
        outputDeviceAOPA.mElement= kAudioObjectPropertyElementMaster;

        AudioObjectID outputDeviceID = kAudioObjectUnknown;
        UInt32 propertySize = sizeof(AudioDeviceID);

        AudioObjectGetPropertyData(kAudioObjectSystemObject, &outputDeviceAOPA,
                                   0, nil, &propertySize, &outputDeviceID);

        // get volume from device
        AudioObjectPropertyAddress volumeAOPA;
        volumeAOPA.mSelector= kAudioDevicePropertyVolumeScalar;
        volumeAOPA.mScope= kAudioObjectPropertyScopeOutput;
        volumeAOPA.mElement= kAudioObjectPropertyElementMaster;

        Float32 volume = 0.5;
        UInt32 volSize = sizeof(Float32);

        AudioObjectGetPropertyData(outputDeviceID, &volumeAOPA, 0, nil, &volSize, &volume);
        NSLog(@"%f", volume);

        dispatch_queue_t queue = dispatch_queue_create("testqueue", nil);
        AudioObjectPropertyListenerBlock listener = ^(UInt32 a, const AudioObjectPropertyAddress* arst){

            AudioObjectGetPropertyData(outputDeviceID, &volumeAOPA, 0, nil, &volSize, &volume);
            NSLog(@"%f", volume);

        };

        AudioObjectAddPropertyListenerBlock(outputDeviceID, &volumeAOPA, queue, listener);
        AudioObjectRemovePropertyListenerBlock(outputDeviceID, &volumeAOPA, queue, listener);

        while (true){
            //keep app running
        }

    }
    return 0;
}
//objective-c代码工作
//main.m
//对象
#进口
#进口
int main(int argc,const char*argv[]{
@自动释放池{
//首先获取默认输出设备
AudioObjectPropertyAddressOutputDeviceAOPA;
OutputDeviceOpa.mSelector=kAudioHardwarePropertyDefaultOutputDevice;
outputDeviceAOPA.mScope=kAudioObjectPropertyScopeGlobal;
OutputDeviceOpa.mElement=kAudioObjectPropertyElementMaster;
AudioObjectID outputDeviceID=KaudioObjectInKnown;
UInt32 propertySize=sizeof(AudioDeviceID);
AudioObjectGetPropertyData(kAudioObjectSystemObject和outputDeviceAOPA,
0、nil和propertySize以及outputDeviceID);
//从设备获取卷
AudioObjectPropertyAddressVolumeAopa;
volumeAOPA.mSelector=kAudioDevicePropertyVolumeScalar;
volumeAOPA.mScope=kAudioObjectPropertyScopeOutput;
volumeAOPA.mElement=kAudioObjectPropertyElementMaster;
体积=0.5;
UInt32 volSize=sizeof(Float32);
AudioObjectGetPropertyData(outputDeviceID和volumeAOPA、0、nil和volSize和volume);
NSLog(@“%f”,卷);
调度队列=调度队列创建(“测试队列”,无);
AudioObjectPropertyListenerBlock侦听器=^(UInt32 a,常量AudioObjectPropertyAddress*arst){
AudioObjectGetPropertyData(outputDeviceID和volumeAOPA、0、nil和volSize和volume);
NSLog(@“%f”,卷);
};
AudioObjectAddPropertyListenerBlock(outputDeviceID和volumeAOPA、队列、侦听器);
AudioObjectRemovePropertyListenerBlock(outputDeviceID和volumeAOPA、队列、侦听器);
while(true){
//保持应用程序运行
}
}
返回0;
}

我认为这是核心音频API中的一个缺陷,但可能有一个变通方法,或者obj-c块的工作方式与swift闭包不同。

我也有同样的问题

向Objective-CAPI传递Swift闭包似乎是一个问题。 相同的闭包被块复制两次,每个副本有不同的地址。因此,为侦听器注册提供的块与注销期间使用的块不正确匹配


我发现的解决方法是使用Objective-C helper注册和注销侦听器,Objective-C helper还将存储用于注销的块地址

是的,实际上这可能是一个bug,因为AudioObjectRemovePropertyListenerBlock无法删除侦听器块。然而,我发现用
AudioObject
注册
AudioObjectPropertyListenerProc
可以是Swift的一种解决方法

//var queue = dispatch_queue_create("testqueue", nil)
//var listener:AudioObjectPropertyListenerBlock = {
//    _, _ in
//    AudioObjectGetPropertyData(outputDeviceID, &volumeAOPA, 0, nil, &volSize, &volume)
//    print(volume)
//}
//
//AudioObjectAddPropertyListenerBlock(outputDeviceID, &volumeAOPA, queue, listener)
//AudioObjectRemovePropertyListenerBlock(outputDeviceID, &volumeAOPA, queue, listener)
var data: UInt32 = 0
func listenerProc() -> AudioObjectPropertyListenerProc {
    return { _, _, _, _ in
        AudioObjectGetPropertyData(outputDeviceID, &volumeAOPA, 0, nil, &volSize, &volume)
        print(volume)
        return 0
    }
}
AudioObjectAddPropertyListener(outputDeviceID, &volumeAOPA, listenerProc(), &data)
AudioObjectRemovePropertyListener(outputDeviceID, &volumeAOPA, listenerProc(), &data)

您甚至可以使用第四个参数来传递您自己的用户数据,这可以是一个快速关闭。因此,您可以制作一个API,将Swift闭包毫无保留地包装起来。我会调查的。