You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在macOS Sonoma之前版本中从AudioObjectID获取PID

在macOS Sonoma之前版本获取音频进程PID的方案

在macOS 14.0之前,系统并未提供kAudioProcessPropertyPID这类直接获取音频进程PID的公开API,你可以通过以下两种兼容方案实现相同功能:

方法一:通过Bundle Identifier匹配PID(公开API,稳定可靠)

先获取音频进程的Bundle Identifier,再遍历系统运行中的进程匹配对应PID,对GUI应用和大部分后台进程都适用:

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AppKit/AppKit.h>
#import <sys/sysctl.h>

pid_t getAudioProcessPIDPreSonoma(AudioObjectID process) {
    CFStringRef bundleID = NULL;
    UInt32 dataSize = sizeof(CFStringRef);
    
    // 读取音频进程的Bundle Identifier
    AudioObjectPropertyAddress prop = {
        kAudioProcessPropertyBundleIdentifier,
        kAudioObjectPropertyScopeGlobal,
        kAudioObjectPropertyElementMain
    };
    
    OSStatus error = AudioObjectGetPropertyData(process, &prop, 0, NULL, &dataSize, &bundleID);
    if (error != noErr || !bundleID) {
        return -1;
    }
    
    NSString *bundleIDStr = (__bridge NSString *)bundleID;
    CFRelease(bundleID);
    
    // 优先匹配GUI应用
    NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
    for (NSRunningApplication *app in [workspace runningApplications]) {
        if ([app.bundleIdentifier isEqualToString:bundleIDStr]) {
            return app.processIdentifier;
        }
    }
    
    // 匹配无UI的后台进程,通过进程名关联Bundle Identifier
    NSString *processName = [bundleIDStr componentsSeparatedByString:@"."].lastObject;
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t size;
    sysctl(mib, 4, NULL, &size, NULL, 0);
    struct kinfo_proc *procs = malloc(size);
    sysctl(mib, 4, procs, &size, NULL, 0);
    int count = size / sizeof(struct kinfo_proc);
    
    pid_t pid = -1;
    for (int i = 0; i < count; i++) {
        struct kinfo_proc *proc = &procs[i];
        char name[256];
        strncpy(name, proc->kp_proc.p_comm, sizeof(name));
        name[sizeof(name)-1] = '\0';
        if ([processName isEqualToString:[NSString stringWithUTF8String:name]]) {
            pid = proc->kp_proc.p_pid;
            break;
        }
    }
    free(procs);
    
    return pid;
}

方法二:使用私有属性(仅限非上架应用)

macOS 10.15到13.x版本中,AudioToolbox存在未公开的属性可以直接读取PID,但该方式属于私有API,可能随系统更新失效,且无法通过App Store审核:

pid_t getAudioProcessPIDPreSonomaPrivate(AudioObjectID process) {
    pid_t pid = -1;
    UInt32 dataSize = sizeof(pid);
    
    // 私有属性标识,在旧版系统中对应PID属性
    AudioObjectPropertyAddress prop = {
        0x100,
        kAudioObjectPropertyScopeGlobal,
        kAudioObjectPropertyElementMain
    };
    
    OSStatus error = AudioObjectGetPropertyData(process, &prop, 0, NULL, &dataSize, &pid);
    return error == noErr ? pid : -1;
}

整合到原有代码

将前置版本的实现整合到你的函数中,完整兼容代码如下:

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AppKit/AppKit.h>
#import <sys/sysctl.h>

int getAudioProcessPID(AudioObjectID process)
{
    pid_t pid;
    if (@available(macOS 14.0, *)) {
        constexpr AudioObjectPropertyAddress prop {
            kAudioProcessPropertyPID,
            kAudioObjectPropertyScopeGlobal,
            kAudioObjectPropertyElementMain
        };
        UInt32 dataSize = sizeof(pid);
        OSStatus error = AudioObjectGetPropertyData(process, &prop, 0, nullptr, &dataSize, &pid);
        if (error != noErr) {
            return -1;
        }
    } else {
        pid = getAudioProcessPIDPreSonoma(process);
    }
    return pid;
}

// 前置版本实现函数
pid_t getAudioProcessPIDPreSonoma(AudioObjectID process) {
    CFStringRef bundleID = NULL;
    UInt32 dataSize = sizeof(CFStringRef);
    
    AudioObjectPropertyAddress prop = {
        kAudioProcessPropertyBundleIdentifier,
        kAudioObjectPropertyScopeGlobal,
        kAudioObjectPropertyElementMain
    };
    
    OSStatus error = AudioObjectGetPropertyData(process, &prop, 0, NULL, &dataSize, &bundleID);
    if (error != noErr || !bundleID) {
        return -1;
    }
    
    NSString *bundleIDStr = (__bridge NSString *)bundleID;
    CFRelease(bundleID);
    
    NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
    for (NSRunningApplication *app in [workspace runningApplications]) {
        if ([app.bundleIdentifier isEqualToString:bundleIDStr]) {
            return app.processIdentifier;
        }
    }
    
    NSString *processName = [bundleIDStr componentsSeparatedByString:@"."].lastObject;
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t size;
    sysctl(mib, 4, NULL, &size, NULL, 0);
    struct kinfo_proc *procs = malloc(size);
    sysctl(mib, 4, procs, &size, NULL, 0);
    int count = size / sizeof(struct kinfo_proc);
    
    pid_t pid = -1;
    for (int i = 0; i < count; i++) {
        struct kinfo_proc *proc = &procs[i];
        char name[256];
        strncpy(name, proc->kp_proc.p_comm, sizeof(name));
        name[sizeof(name)-1] = '\0';
        if ([processName isEqualToString:[NSString stringWithUTF8String:name]]) {
            pid = proc->kp_proc.p_pid;
            break;
        }
    }
    free(procs);
    
    return pid;
}

内容的提问来源于stack exchange,提问作者RuLoViC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 10:43:12