#include <CoreAudio/AudioServerPlugIn.h>
#include <CoreFoundation/CoreFoundation.h>
#include <errno.h>
#include <mach/mach_time.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define kSiriPlusDeviceObjectID 2
#define kSiriPlusStreamObjectID 3
#define kSiriPlusSampleRate 16000.0
#define kSiriPlusChannelCount 2
#define kSiriPlusSharedPCMChannelCount 1
#define kSiriPlusBufferFrameSize 320
#define kSiriPlusZeroTimeStampPeriod 16000
#define kSiriPlusMaxClientReadStates 64
// Match the writer's startup prebuffer (SiriPlusPCMStreamWriter.defaultPrebufferFrames). 300ms of read latency gives CoreAudio jitter headroom against the bursty PacketLogger text pipeline so it does not underrun into silence (the "choppy" symptom).
#define kSiriPlusReadLatencyFrames 4800
// After a mid-stream underrun, resume as soon as there is roughly one Opus frame or one CoreAudio IO cycle available.
#define kSiriPlusUnderrunRecoveryFrames 320
#define kSiriPlusSharedMemoryPath "/tmp/siriplus_remote_mic_pcm"
#define kSiriPlusSharedMemoryName "/siriplus_remote_mic_pcm"
#define kSiriPlusPCMHeaderSizeV1 32
#define kSiriPlusPCMHeaderSizeV2 64
#ifndef kAudioDevicePropertyStreamConfiguration
#define kAudioDevicePropertyStreamConfiguration ((AudioObjectPropertySelector)0x736C6179)
#endif
#ifndef kAudioDevicePropertyZeroTimeStampPeriod
#define kAudioDevicePropertyZeroTimeStampPeriod ((AudioObjectPropertySelector)0x72696E67)
#endif
#ifndef kAudioDevicePropertyBufferFrameSize
#define kAudioDevicePropertyBufferFrameSize ((AudioObjectPropertySelector)0x6673697A)
#endif
#ifndef kAudioDevicePropertyBufferFrameSizeRange
#define kAudioDevicePropertyBufferFrameSizeRange ((AudioObjectPropertySelector)0x66737A23)
#endif
#ifndef kAudioDevicePropertyUsesVariableBufferFrameSizes
#define kAudioDevicePropertyUsesVariableBufferFrameSizes ((AudioObjectPropertySelector)0x7666737A)
#endif
#ifndef SIRIPLUS_HAL_TRACE
#define SIRIPLUS_HAL_TRACE 0
#endif

#if SIRIPLUS_HAL_TRACE
#include <os/log.h>
#include <stdarg.h>
#endif

typedef struct {
    char magic[4];
    uint32_t version;
    uint32_t sampleRate;
    uint32_t channels;
    uint32_t bytesPerFrame;
    uint32_t capacityFrames;
    uint64_t writeFrame;
    uint64_t generation;
    uint32_t writerPID;
    uint32_t flags;
    uint64_t lastWriteHostTime;
    uint32_t headerBytes;
    uint32_t readerUnderrunCount;
} SiriPlusPCMHeader;

typedef struct {
    UInt32 clientID;
    uint64_t readFrame;
    uint64_t pcmGeneration;
    bool pcmUnderrun;
    bool active;
} SiriPlusClientReadState;

typedef struct SiriPlusPCMMapSnapshot {
    int fd;
    void *map;
    size_t mapSize;
    bool writable;
    atomic_uint refCount;
    atomic_bool retired;
    uint64_t retireEpoch;
    struct SiriPlusPCMMapSnapshot *nextRetired;
} SiriPlusPCMMapSnapshot;

static AudioServerPlugInHostRef gHost = NULL;
static pthread_mutex_t gStateMutex = PTHREAD_MUTEX_INITIALIZER;
static UInt32 gReferenceCount = 1;
static UInt32 gRunningClientCount = 0;
static UInt64 gIOSeed = 1;
static UInt64 gAnchorHostTime = 0;
static double gHostTicksPerFrame = 0;
static _Atomic(SiriPlusPCMMapSnapshot *) gPCMMapSnapshot = NULL;
static SiriPlusPCMMapSnapshot *gRetiredPCMMapSnapshots = NULL;
// Monotonic reclamation clock, advanced (under gStateMutex) once per reap
// trigger. A retired snapshot is only reaped in a strictly later epoch than the
// one it was retired in, giving any IO thread that already loaded the pointer a
// full refresh cycle to complete its refCount bump before the snapshot can be
// freed. See reapRetiredPCMMapSnapshotsLocked.
static uint64_t gReclaimEpoch = 0;
static bool gPCMRefreshThreadRunning = false;
static bool gPCMRefreshThreadStopRequested = false;
static SiriPlusClientReadState gClientReadStates[kSiriPlusMaxClientReadStates];
static SiriPlusClientReadState gFallbackReadState = {0, 0, 0, true, true};

static HRESULT STDMETHODCALLTYPE QueryInterface(void *inDriver, REFIID inUUID, LPVOID *outInterface);
static ULONG STDMETHODCALLTYPE AddRef(void *inDriver);
static ULONG STDMETHODCALLTYPE Release(void *inDriver);
static OSStatus STDMETHODCALLTYPE Initialize(AudioServerPlugInDriverRef inDriver, AudioServerPlugInHostRef inHost);
static OSStatus STDMETHODCALLTYPE CreateDevice(AudioServerPlugInDriverRef inDriver, CFDictionaryRef inDescription, const AudioServerPlugInClientInfo *inClientInfo, AudioObjectID *outDeviceObjectID);
static OSStatus STDMETHODCALLTYPE DestroyDevice(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID);
static OSStatus STDMETHODCALLTYPE AddDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo *inClientInfo);
static OSStatus STDMETHODCALLTYPE RemoveDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo *inClientInfo);
static OSStatus STDMETHODCALLTYPE PerformDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void *inChangeInfo);
static OSStatus STDMETHODCALLTYPE AbortDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void *inChangeInfo);
static Boolean STDMETHODCALLTYPE HasProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress);
static OSStatus STDMETHODCALLTYPE IsPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, Boolean *outIsSettable);
static OSStatus STDMETHODCALLTYPE GetPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 *outDataSize);
static OSStatus STDMETHODCALLTYPE GetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 inDataSize, UInt32 *outDataSize, void *outData);
static OSStatus STDMETHODCALLTYPE SetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 inDataSize, const void *inData);
static OSStatus STDMETHODCALLTYPE StartIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID);
static OSStatus STDMETHODCALLTYPE StopIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID);
static OSStatus STDMETHODCALLTYPE GetZeroTimeStamp(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, Float64 *outSampleTime, UInt64 *outHostTime, UInt64 *outSeed);
static OSStatus STDMETHODCALLTYPE WillDoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, Boolean *outWillDo, Boolean *outWillDoInPlace);
static OSStatus STDMETHODCALLTYPE BeginIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo *inIOCycleInfo);
static OSStatus STDMETHODCALLTYPE DoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo *inIOCycleInfo, void *ioMainBuffer, void *ioSecondaryBuffer);
static OSStatus STDMETHODCALLTYPE EndIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo *inIOCycleInfo);

static AudioServerPlugInDriverInterface gDriverInterface = {
    NULL,
    QueryInterface,
    AddRef,
    Release,
    Initialize,
    CreateDevice,
    DestroyDevice,
    AddDeviceClient,
    RemoveDeviceClient,
    PerformDeviceConfigurationChange,
    AbortDeviceConfigurationChange,
    HasProperty,
    IsPropertySettable,
    GetPropertyDataSize,
    GetPropertyData,
    SetPropertyData,
    StartIO,
    StopIO,
    GetZeroTimeStamp,
    WillDoIOOperation,
    BeginIOOperation,
    DoIOOperation,
    EndIOOperation
};

static AudioServerPlugInDriverInterface *gDriverInterfacePointer = &gDriverInterface;
static AudioServerPlugInDriverRef gDriverRef = &gDriverInterfacePointer;

#if SIRIPLUS_HAL_TRACE
static void traceLine(const char *format, ...) {
    int fd = open("/tmp/siriplus_hal_trace.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (fd < 0) {
        return;
    }
    va_list arguments;
    va_start(arguments, format);
    vdprintf(fd, format, arguments);
    va_end(arguments);
    dprintf(fd, "\n");
    close(fd);
}

static void traceProperty(const char *operation, AudioObjectID objectID, const AudioObjectPropertyAddress *address, OSStatus status, UInt32 dataSize) {
    if (address == NULL) {
        traceLine("SiriPlusRemoteMic: %s obj=%u NULL address status=%d size=%u", operation, objectID, (int)status, dataSize);
        os_log_error(OS_LOG_DEFAULT, "SiriPlusRemoteMic: %{public}s obj=%u NULL address status=%d size=%u", operation, objectID, (int)status, dataSize);
        return;
    }
    traceLine("SiriPlusRemoteMic: %s obj=%u sel=0x%08x scope=0x%08x elem=%u status=%d size=%u",
              operation,
              objectID,
              address->mSelector,
              address->mScope,
              address->mElement,
              (int)status,
              dataSize);
    os_log_error(OS_LOG_DEFAULT,
                 "SiriPlusRemoteMic: %{public}s obj=%u sel=0x%08x scope=0x%08x elem=%u status=%d size=%u",
                 operation, objectID, address->mSelector, address->mScope, address->mElement, (int)status, dataSize);
}
#else
#define traceLine(...) do {} while (0)
#define traceProperty(...) do {} while (0)
#endif

void *SiriPlusRemoteMicAudioDriverFactory(CFAllocatorRef allocator, CFUUIDRef requestedTypeUUID) {
    (void)allocator;
    traceLine("SiriPlusRemoteMic: Factory called");
    if (CFEqual(requestedTypeUUID, kAudioServerPlugInTypeUUID) ||
        CFEqual(requestedTypeUUID, kAudioServerPlugInDriverInterfaceUUID)) {
        AddRef(gDriverRef);
        traceLine("SiriPlusRemoteMic: Factory returning driver ref %p", gDriverRef);
        return gDriverRef;
    }
    traceLine("SiriPlusRemoteMic: Factory wrong UUID requested");
    return NULL;
}

static AudioStreamBasicDescription siriPlusFormat(void) {
    AudioStreamBasicDescription format;
    memset(&format, 0, sizeof(format));
    format.mSampleRate = kSiriPlusSampleRate;
    format.mFormatID = kAudioFormatLinearPCM;
    format.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian;
    format.mBytesPerPacket = sizeof(Float32) * kSiriPlusChannelCount;
    format.mFramesPerPacket = 1;
    format.mBytesPerFrame = sizeof(Float32) * kSiriPlusChannelCount;
    format.mChannelsPerFrame = kSiriPlusChannelCount;
    format.mBitsPerChannel = 32;
    return format;
}

static AudioStreamRangedDescription siriPlusRangedFormat(void) {
    AudioStreamRangedDescription ranged;
    ranged.mFormat = siriPlusFormat();
    ranged.mSampleRateRange.mMinimum = kSiriPlusSampleRate;
    ranged.mSampleRateRange.mMaximum = kSiriPlusSampleRate;
    return ranged;
}

static AudioValueRange siriPlusSampleRateRange(void) {
    AudioValueRange range;
    range.mMinimum = kSiriPlusSampleRate;
    range.mMaximum = kSiriPlusSampleRate;
    return range;
}

static size_t audioBufferListSize(UInt32 bufferCount) {
    if (bufferCount == 0) {
        return offsetof(AudioBufferList, mBuffers);
    }
    return offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * bufferCount);
}

static bool scopeIncludesInput(AudioObjectPropertyScope scope) {
    return scope == kAudioObjectPropertyScopeGlobal || scope == kAudioObjectPropertyScopeInput;
}

static bool scopeIsInput(AudioObjectPropertyScope scope) {
    return scope == kAudioObjectPropertyScopeInput;
}

static bool scopeIsOutput(AudioObjectPropertyScope scope) {
    return scope == kAudioObjectPropertyScopeOutput;
}

static OSStatus copyValue(UInt32 inDataSize, UInt32 *outDataSize, void *outData, const void *source, UInt32 sourceSize) {
    if (inDataSize < sourceSize) {
        return kAudioHardwareBadPropertySizeError;
    }
    memcpy(outData, source, sourceSize);
    *outDataSize = sourceSize;
    return noErr;
}

static OSStatus copyCFString(UInt32 inDataSize, UInt32 *outDataSize, void *outData, CFStringRef source) {
    if (inDataSize < sizeof(CFStringRef)) {
        return kAudioHardwareBadPropertySizeError;
    }
    CFStringRef value = CFStringCreateCopy(kCFAllocatorDefault, source);
    memcpy(outData, &value, sizeof(value));
    *outDataSize = sizeof(value);
    return noErr;
}

static bool isKnownObject(AudioObjectID objectID) {
    return objectID == kAudioObjectPlugInObject || objectID == kSiriPlusDeviceObjectID || objectID == kSiriPlusStreamObjectID;
}

static UInt32 objectDataSize(AudioObjectID objectID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize) {
    (void)qualifierDataSize;
    switch (address->mSelector) {
        case kAudioObjectPropertyBaseClass:
        case kAudioObjectPropertyClass:
        case kAudioObjectPropertyOwner:
        case kAudioObjectPropertyIdentify:
            return sizeof(UInt32);
        case kAudioObjectPropertyName:
        case kAudioObjectPropertyManufacturer:
        case kAudioObjectPropertyModelName:
        case kAudioObjectPropertySerialNumber:
        case kAudioObjectPropertyFirmwareVersion:
            return sizeof(CFStringRef);
        case kAudioObjectPropertyOwnedObjects:
            if (objectID == kAudioObjectPlugInObject) {
                return sizeof(AudioObjectID);
            }
            if (objectID == kSiriPlusDeviceObjectID) {
                return sizeof(AudioObjectID);
            }
            return 0;
        default:
            return 0;
    }
}

static UInt32 plugInDataSize(const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize) {
    switch (address->mSelector) {
        case kAudioPlugInPropertyBundleID:
            return sizeof(CFStringRef);
        case kAudioPlugInPropertyDeviceList:
            return sizeof(AudioObjectID);
        case kAudioPlugInPropertyTranslateUIDToDevice:
            return sizeof(AudioObjectID);
        default:
            return objectDataSize(kAudioObjectPlugInObject, address, qualifierDataSize);
    }
}

static UInt32 deviceDataSize(const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize) {
    switch (address->mSelector) {
        case kAudioDevicePropertyDeviceUID:
        case kAudioDevicePropertyModelUID:
            return sizeof(CFStringRef);
        case kAudioDevicePropertyTransportType:
        case kAudioDevicePropertyClockDomain:
        case kAudioDevicePropertyDeviceIsAlive:
        case kAudioDevicePropertyDeviceIsRunning:
        case kAudioDevicePropertyIsHidden:
        case kAudioDevicePropertyBufferFrameSize:
        case kAudioDevicePropertyUsesVariableBufferFrameSizes:
        case kAudioDevicePropertyZeroTimeStampPeriod:
            return sizeof(UInt32);
        case kAudioDevicePropertyDeviceCanBeDefaultDevice:
            return (scopeIsInput(address->mScope) || scopeIsOutput(address->mScope)) ? sizeof(UInt32) : 0;
        case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice:
            return scopeIsOutput(address->mScope) ? sizeof(UInt32) : 0;
        case kAudioDevicePropertyLatency:
        case kAudioDevicePropertySafetyOffset:
            return (scopeIsInput(address->mScope) || scopeIsOutput(address->mScope)) ? sizeof(UInt32) : 0;
        case kAudioDevicePropertyNominalSampleRate:
            return sizeof(Float64);
        case kAudioDevicePropertyAvailableNominalSampleRates:
        case kAudioDevicePropertyBufferFrameSizeRange:
            return sizeof(AudioValueRange);
        case kAudioDevicePropertyPreferredChannelLayout:
            return scopeIsInput(address->mScope) ? sizeof(AudioChannelLayout) : 0;
        case kAudioDevicePropertyRelatedDevices:
            return sizeof(AudioObjectID);
        case kAudioDevicePropertyStreams:
            return scopeIncludesInput(address->mScope) ? sizeof(AudioObjectID) : 0;
        case kAudioDevicePropertyStreamConfiguration:
            if (scopeIsInput(address->mScope)) {
                return (UInt32)audioBufferListSize(1);
            }
            if (scopeIsOutput(address->mScope)) {
                return (UInt32)audioBufferListSize(0);
            }
            return 0;
        default:
            return objectDataSize(kSiriPlusDeviceObjectID, address, qualifierDataSize);
    }
}

static UInt32 streamDataSize(const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize) {
    switch (address->mSelector) {
        case kAudioStreamPropertyIsActive:
        case kAudioStreamPropertyDirection:
        case kAudioStreamPropertyTerminalType:
        case kAudioStreamPropertyStartingChannel:
        case kAudioStreamPropertyLatency:
            return sizeof(UInt32);
        case kAudioStreamPropertyVirtualFormat:
        case kAudioStreamPropertyPhysicalFormat:
            return sizeof(AudioStreamBasicDescription);
        case kAudioStreamPropertyAvailableVirtualFormats:
        case kAudioStreamPropertyAvailablePhysicalFormats:
            return sizeof(AudioStreamRangedDescription);
        default:
            return objectDataSize(kSiriPlusStreamObjectID, address, qualifierDataSize);
    }
}

static UInt32 propertyDataSize(AudioObjectID objectID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize) {
    if (!isKnownObject(objectID)) {
        return 0;
    }
    if (objectID == kAudioObjectPlugInObject) {
        return plugInDataSize(address, qualifierDataSize);
    }
    if (objectID == kSiriPlusDeviceObjectID) {
        return deviceDataSize(address, qualifierDataSize);
    }
    return streamDataSize(address, qualifierDataSize);
}

static bool hasZeroLengthDeviceProperty(const AudioObjectPropertyAddress *address) {
    if (address == NULL) {
        return false;
    }
    switch (address->mSelector) {
        case kAudioObjectPropertyControlList:
        case kAudioDevicePropertyStreams:
            return address->mSelector == kAudioObjectPropertyControlList || scopeIsOutput(address->mScope);
        default:
            return false;
    }
}

static OSStatus copyObjectProperty(AudioObjectID objectID, const AudioObjectPropertyAddress *address, UInt32 inDataSize, UInt32 *outDataSize, void *outData) {
    AudioClassID baseClassID = kAudioObjectClassID;
    AudioClassID classID = kAudioObjectClassID;
    AudioObjectID owner = kAudioObjectUnknown;
    CFStringRef name = CFSTR("SiriPlus");

    if (objectID == kAudioObjectPlugInObject) {
        classID = kAudioPlugInClassID;
        name = CFSTR("SiriPlus Remote Mic Plug-In");
    } else if (objectID == kSiriPlusDeviceObjectID) {
        classID = kAudioDeviceClassID;
        owner = kAudioObjectPlugInObject;
        name = CFSTR("SiriPlus Remote Mic");
    } else if (objectID == kSiriPlusStreamObjectID) {
        classID = kAudioStreamClassID;
        owner = kSiriPlusDeviceObjectID;
        name = CFSTR("SiriPlus Remote Mic Input");
    } else {
        return kAudioHardwareBadObjectError;
    }

    switch (address->mSelector) {
        case kAudioObjectPropertyClass:
            return copyValue(inDataSize, outDataSize, outData, &classID, sizeof(classID));
        case kAudioObjectPropertyBaseClass:
            return copyValue(inDataSize, outDataSize, outData, &baseClassID, sizeof(baseClassID));
        case kAudioObjectPropertyOwner:
            return copyValue(inDataSize, outDataSize, outData, &owner, sizeof(owner));
        case kAudioObjectPropertyName:
        case kAudioObjectPropertyModelName:
            return copyCFString(inDataSize, outDataSize, outData, name);
        case kAudioObjectPropertyManufacturer:
            return copyCFString(inDataSize, outDataSize, outData, CFSTR("SiriPlus"));
        case kAudioObjectPropertySerialNumber:
            return copyCFString(inDataSize, outDataSize, outData, CFSTR("SPRM-0001"));
        case kAudioObjectPropertyFirmwareVersion:
            return copyCFString(inDataSize, outDataSize, outData, CFSTR("1.0"));
        case kAudioObjectPropertyOwnedObjects: {
            if (objectID == kAudioObjectPlugInObject) {
                AudioObjectID device = kSiriPlusDeviceObjectID;
                return copyValue(inDataSize, outDataSize, outData, &device, sizeof(device));
            }
            if (objectID == kSiriPlusDeviceObjectID) {
                AudioObjectID stream = kSiriPlusStreamObjectID;
                return copyValue(inDataSize, outDataSize, outData, &stream, sizeof(stream));
            }
            *outDataSize = 0;
            return noErr;
        }
        case kAudioObjectPropertyIdentify: {
            UInt32 value = 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        default:
            return kAudioHardwareUnknownPropertyError;
    }
}

static OSStatus copyPlugInProperty(const AudioObjectPropertyAddress *address, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 inDataSize, UInt32 *outDataSize, void *outData) {
    switch (address->mSelector) {
        case kAudioPlugInPropertyBundleID:
            return copyCFString(inDataSize, outDataSize, outData, CFSTR("com.siriplus.remote-mic"));
        case kAudioPlugInPropertyDeviceList: {
            AudioObjectID device = kSiriPlusDeviceObjectID;
            return copyValue(inDataSize, outDataSize, outData, &device, sizeof(device));
        }
        case kAudioPlugInPropertyTranslateUIDToDevice: {
            AudioObjectID device = kAudioObjectUnknown;
            if (inQualifierDataSize == sizeof(CFStringRef) && inQualifierData != NULL) {
                CFStringRef uid = *(const CFStringRef *)inQualifierData;
                if (uid != NULL && CFEqual(uid, CFSTR("com.siriplus.remote-mic.device"))) {
                    device = kSiriPlusDeviceObjectID;
                }
            }
            return copyValue(inDataSize, outDataSize, outData, &device, sizeof(device));
        }
        default:
            return copyObjectProperty(kAudioObjectPlugInObject, address, inDataSize, outDataSize, outData);
    }
}

static OSStatus copyDeviceProperty(const AudioObjectPropertyAddress *address, UInt32 inDataSize, UInt32 *outDataSize, void *outData) {
    switch (address->mSelector) {
        case kAudioDevicePropertyDeviceUID:
            return copyCFString(inDataSize, outDataSize, outData, CFSTR("com.siriplus.remote-mic.device"));
        case kAudioDevicePropertyModelUID:
            return copyCFString(inDataSize, outDataSize, outData, CFSTR("com.siriplus.remote-mic.model"));
        case kAudioDevicePropertyTransportType: {
            UInt32 value = kAudioDeviceTransportTypeVirtual;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyClockDomain: {
            UInt32 value = 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyDeviceIsAlive: {
            UInt32 value = 1;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyDeviceCanBeDefaultDevice: {
            UInt32 value = (scopeIsInput(address->mScope) || scopeIsOutput(address->mScope)) ? 1 : 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyDeviceCanBeDefaultSystemDevice: {
            UInt32 value = scopeIsOutput(address->mScope) ? 1 : 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyLatency:
        case kAudioDevicePropertySafetyOffset:
        case kAudioDevicePropertyIsHidden: {
            UInt32 value = 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyDeviceIsRunning: {
            pthread_mutex_lock(&gStateMutex);
            UInt32 value = gRunningClientCount > 0 ? 1 : 0;
            pthread_mutex_unlock(&gStateMutex);
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyRelatedDevices: {
            AudioObjectID device = kSiriPlusDeviceObjectID;
            return copyValue(inDataSize, outDataSize, outData, &device, sizeof(device));
        }
        case kAudioObjectPropertyControlList:
            *outDataSize = 0;
            return noErr;
        case kAudioDevicePropertyStreams: {
            if (!scopeIncludesInput(address->mScope)) {
                *outDataSize = 0;
                return noErr;
            }
            AudioObjectID stream = kSiriPlusStreamObjectID;
            return copyValue(inDataSize, outDataSize, outData, &stream, sizeof(stream));
        }
        case kAudioDevicePropertyStreamConfiguration: {
            UInt32 bufferCount = scopeIsInput(address->mScope) ? 1 : 0;
            UInt32 size = (UInt32)audioBufferListSize(bufferCount);
            if (inDataSize < size) {
                return kAudioHardwareBadPropertySizeError;
            }
            AudioBufferList *list = (AudioBufferList *)outData;
            list->mNumberBuffers = bufferCount;
            if (bufferCount == 1) {
                list->mBuffers[0].mNumberChannels = kSiriPlusChannelCount;
                list->mBuffers[0].mDataByteSize = 0;
                list->mBuffers[0].mData = NULL;
            }
            *outDataSize = size;
            return noErr;
        }
        case kAudioDevicePropertyNominalSampleRate: {
            Float64 value = kSiriPlusSampleRate;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyAvailableNominalSampleRates: {
            AudioValueRange value = siriPlusSampleRateRange();
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyZeroTimeStampPeriod: {
            UInt32 value = kSiriPlusZeroTimeStampPeriod;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyBufferFrameSize: {
            UInt32 value = kSiriPlusBufferFrameSize;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyBufferFrameSizeRange: {
            AudioValueRange value;
            value.mMinimum = kSiriPlusBufferFrameSize;
            value.mMaximum = kSiriPlusBufferFrameSize;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyUsesVariableBufferFrameSizes: {
            UInt32 value = 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioDevicePropertyPreferredChannelLayout: {
            AudioChannelLayout layout;
            memset(&layout, 0, sizeof(layout));
            layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
            return copyValue(inDataSize, outDataSize, outData, &layout, sizeof(layout));
        }
        default:
            return copyObjectProperty(kSiriPlusDeviceObjectID, address, inDataSize, outDataSize, outData);
    }
}

static OSStatus copyStreamProperty(const AudioObjectPropertyAddress *address, UInt32 inDataSize, UInt32 *outDataSize, void *outData) {
    switch (address->mSelector) {
        case kAudioStreamPropertyIsActive:
        case kAudioStreamPropertyDirection: {
            UInt32 value = 1;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioStreamPropertyTerminalType: {
            UInt32 value = kAudioStreamTerminalTypeMicrophone;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioStreamPropertyStartingChannel: {
            UInt32 value = 1;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioStreamPropertyLatency: {
            UInt32 value = 0;
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioStreamPropertyVirtualFormat:
        case kAudioStreamPropertyPhysicalFormat: {
            AudioStreamBasicDescription value = siriPlusFormat();
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        case kAudioStreamPropertyAvailableVirtualFormats:
        case kAudioStreamPropertyAvailablePhysicalFormats: {
            AudioStreamRangedDescription value = siriPlusRangedFormat();
            return copyValue(inDataSize, outDataSize, outData, &value, sizeof(value));
        }
        default:
            return copyObjectProperty(kSiriPlusStreamObjectID, address, inDataSize, outDataSize, outData);
    }
}

static double hostTicksPerFrame(void) {
    if (gHostTicksPerFrame > 0) {
        return gHostTicksPerFrame;
    }
    mach_timebase_info_data_t timebase;
    mach_timebase_info(&timebase);
    double nanosecondsPerTick = (double)timebase.numer / (double)timebase.denom;
    gHostTicksPerFrame = (1000000000.0 / kSiriPlusSampleRate) / nanosecondsPerTick;
    return gHostTicksPerFrame;
}

static void resetAllClientReadStates(void);
static bool validatePCMHeader(const SiriPlusPCMHeader *header, size_t mapSize);
static bool isStalePCMHeader(const SiriPlusPCMHeader *header);
static void resetClientReadState(SiriPlusClientReadState *state);
static bool ensurePCMMapLocked(void);
static void *pcmRefreshWorker(void *context);

static void destroyPCMMapSnapshot(SiriPlusPCMMapSnapshot *snapshot) {
    if (snapshot == NULL) {
        return;
    }
    if (snapshot->map != MAP_FAILED && snapshot->map != NULL) {
        munmap(snapshot->map, snapshot->mapSize);
    }
    if (snapshot->fd >= 0) {
        close(snapshot->fd);
    }
    free(snapshot);
}

static void releasePCMMapSnapshot(SiriPlusPCMMapSnapshot *snapshot) {
    if (snapshot == NULL) {
        return;
    }
    if (atomic_fetch_sub_explicit(&snapshot->refCount, 1, memory_order_acq_rel) == 1) {
        destroyPCMMapSnapshot(snapshot);
    }
}

// Always called under gStateMutex (via publishPCMMapSnapshot from
// ensurePCMMapLocked / closePCMMap / Release), so the retired list and epoch
// stamp need no additional guarding.
static void retirePCMMapSnapshot(SiriPlusPCMMapSnapshot *snapshot) {
    if (snapshot == NULL) {
        return;
    }
    atomic_store_explicit(&snapshot->retired, true, memory_order_release);
    snapshot->retireEpoch = gReclaimEpoch;
    snapshot->nextRetired = gRetiredPCMMapSnapshots;
    gRetiredPCMMapSnapshots = snapshot;
}

static SiriPlusPCMMapSnapshot *retainPCMMapSnapshot(void) {
    for (;;) {
        SiriPlusPCMMapSnapshot *snapshot = atomic_load_explicit(&gPCMMapSnapshot, memory_order_acquire);
        if (snapshot == NULL) {
            return NULL;
        }
        atomic_fetch_add_explicit(&snapshot->refCount, 1, memory_order_acquire);
        if (atomic_load_explicit(&gPCMMapSnapshot, memory_order_acquire) == snapshot &&
            !atomic_load_explicit(&snapshot->retired, memory_order_acquire)) {
            return snapshot;
        }
        releasePCMMapSnapshot(snapshot);
    }
}

static void publishPCMMapSnapshot(SiriPlusPCMMapSnapshot *snapshot) {
    SiriPlusPCMMapSnapshot *old = atomic_exchange_explicit(&gPCMMapSnapshot, snapshot, memory_order_acq_rel);
    retirePCMMapSnapshot(old);
}

// Bounded reaping of retired PCM map snapshots. Must be called under
// gStateMutex.
//
// Before this existed, retired snapshots (one per helper restart / PCM remap —
// the pcmRefreshWorker republishes whenever the writer PID changes) were freed
// only when coreaudiod released the driver, so a long-lived coreaudiod leaked an
// fd + mmap per remap. This reaps them incrementally.
//
// Safety against a concurrent IO callback (fillFromSharedPCM's lock-free
// retain): a snapshot is freed only when BOTH
//   (a) its refCount has fallen to 1 — the retain that publishPCMMapSnapshot
//       never released — meaning no IO callback currently holds it; and
//   (b) it was retired in a strictly earlier reclaim epoch (gReclaimEpoch is
//       advanced once per reap trigger, i.e. once per 250 ms refresh cycle and
//       on every Start/StopIO), giving any IO thread that loaded the pointer
//       before the retire a full cycle to complete its refCount bump + retired
//       recheck (which then releases) before the object can disappear.
// Entries that are still IO-referenced (refCount > 1) or too fresh are kept and
// retried on the next call, so the list stays bounded by (in-flight readers +
// the last epoch's retirements). `force` (driver teardown) frees everything
// regardless, matching the previous release-time behavior.
//
// Residual: condition (b) shrinks — but does not provably eliminate — the
// load-then-fetch_add window on the realtime IO thread; closing it fully would
// require hazard pointers / RCU in the retain path, which is out of scope for a
// minimal, obviously-reviewable change. The IO thread is high priority and
// completes that window in a handful of instructions, far inside one refresh
// cycle, so the practical risk is negligible.
static void reapRetiredPCMMapSnapshotsLocked(bool force) {
    SiriPlusPCMMapSnapshot **link = &gRetiredPCMMapSnapshots;
    while (*link != NULL) {
        SiriPlusPCMMapSnapshot *snapshot = *link;
        bool graced = snapshot->retireEpoch < gReclaimEpoch;
        bool unreferenced = atomic_load_explicit(&snapshot->refCount, memory_order_acquire) <= 1;
        if (force || (graced && unreferenced)) {
            *link = snapshot->nextRetired;
            snapshot->nextRetired = NULL;
            destroyPCMMapSnapshot(snapshot);
        } else {
            link = &snapshot->nextRetired;
        }
    }
}

static void closePCMMap(void) {
    publishPCMMapSnapshot(NULL);
    resetAllClientReadStates();
}

static SiriPlusClientReadState *clientReadState(UInt32 clientID, bool create) {
    for (UInt32 index = 0; index < kSiriPlusMaxClientReadStates; index++) {
        SiriPlusClientReadState *state = &gClientReadStates[index];
        if (state->active && state->clientID == clientID) {
            return state;
        }
    }

    if (!create) {
        return &gFallbackReadState;
    }

    for (UInt32 index = 0; index < kSiriPlusMaxClientReadStates; index++) {
        SiriPlusClientReadState *state = &gClientReadStates[index];
        if (!state->active) {
            state->clientID = clientID;
            state->active = true;
            resetClientReadState(state);
            return state;
        }
    }

    return &gFallbackReadState;
}

static void resetClientReadState(SiriPlusClientReadState *state) {
    state->readFrame = 0;
    state->pcmGeneration = 0;
    state->pcmUnderrun = true;
}

static void removeClientReadState(UInt32 clientID) {
    for (UInt32 index = 0; index < kSiriPlusMaxClientReadStates; index++) {
        SiriPlusClientReadState *state = &gClientReadStates[index];
        if (state->active && state->clientID == clientID) {
            state->active = false;
            resetClientReadState(state);
            return;
        }
    }
}

static void resetAllClientReadStates(void) {
    for (UInt32 index = 0; index < kSiriPlusMaxClientReadStates; index++) {
        if (gClientReadStates[index].active) {
            resetClientReadState(&gClientReadStates[index]);
        }
    }
    resetClientReadState(&gFallbackReadState);
}

static SiriPlusPCMMapSnapshot *adoptPCMFileDescriptor(int fd, bool writable) {
    struct stat statBuffer;
    if (fstat(fd, &statBuffer) != 0 || statBuffer.st_size < (off_t)sizeof(SiriPlusPCMHeader)) {
        close(fd);
        return NULL;
    }

    int protection = PROT_READ | (writable ? PROT_WRITE : 0);
    void *map = mmap(NULL, (size_t)statBuffer.st_size, protection, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED) {
        close(fd);
        return NULL;
    }

    const SiriPlusPCMHeader *header = (const SiriPlusPCMHeader *)map;
    if (!validatePCMHeader(header, (size_t)statBuffer.st_size) || isStalePCMHeader(header)) {
        munmap(map, (size_t)statBuffer.st_size);
        close(fd);
        return NULL;
    }

    SiriPlusPCMMapSnapshot *snapshot = calloc(1, sizeof(SiriPlusPCMMapSnapshot));
    if (snapshot == NULL) {
        munmap(map, (size_t)statBuffer.st_size);
        close(fd);
        return NULL;
    }
    snapshot->fd = fd;
    snapshot->map = map;
    snapshot->mapSize = (size_t)statBuffer.st_size;
    snapshot->writable = writable;
    atomic_init(&snapshot->refCount, 1);
    atomic_init(&snapshot->retired, false);
    return snapshot;
}

static bool ensurePCMMapLocked(void) {
    SiriPlusPCMMapSnapshot *current = atomic_load_explicit(&gPCMMapSnapshot, memory_order_acquire);
    if (current != NULL) {
        const SiriPlusPCMHeader *header = (const SiriPlusPCMHeader *)current->map;
        if (validatePCMHeader(header, current->mapSize) && !isStalePCMHeader(header)) {
            return true;
        }
        closePCMMap();
    }

    int fd = shm_open(kSiriPlusSharedMemoryName, O_RDWR, 0);
    SiriPlusPCMMapSnapshot *snapshot = fd >= 0 ? adoptPCMFileDescriptor(fd, true) : NULL;
    if (snapshot != NULL) {
        publishPCMMapSnapshot(snapshot);
        return true;
    }

    fd = shm_open(kSiriPlusSharedMemoryName, O_RDONLY, 0);
    snapshot = fd >= 0 ? adoptPCMFileDescriptor(fd, false) : NULL;
    if (snapshot != NULL) {
        publishPCMMapSnapshot(snapshot);
        return true;
    }

    fd = open(kSiriPlusSharedMemoryPath, O_RDWR);
    snapshot = fd >= 0 ? adoptPCMFileDescriptor(fd, true) : NULL;
    if (snapshot != NULL) {
        publishPCMMapSnapshot(snapshot);
        return true;
    }

    fd = open(kSiriPlusSharedMemoryPath, O_RDONLY);
    snapshot = fd >= 0 ? adoptPCMFileDescriptor(fd, false) : NULL;
    if (snapshot != NULL) {
        publishPCMMapSnapshot(snapshot);
        return true;
    }

    return false;
}

static void startPCMRefreshThreadLocked(void) {
    if (gPCMRefreshThreadRunning) {
        gPCMRefreshThreadStopRequested = false;
        return;
    }
    pthread_t thread;
    pthread_attr_t attributes;
    if (pthread_attr_init(&attributes) != 0) {
        return;
    }
    pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
    gPCMRefreshThreadStopRequested = false;
    if (pthread_create(&thread, &attributes, pcmRefreshWorker, NULL) == 0) {
        gPCMRefreshThreadRunning = true;
    }
    pthread_attr_destroy(&attributes);
}

static void *pcmRefreshWorker(void *context) {
    (void)context;
    for (;;) {
        pthread_mutex_lock(&gStateMutex);
        bool shouldStop = gPCMRefreshThreadStopRequested || gRunningClientCount == 0;
        if (!shouldStop) {
            gReclaimEpoch++;
            ensurePCMMapLocked();
            reapRetiredPCMMapSnapshotsLocked(false);
        }
        if (shouldStop) {
            gPCMRefreshThreadRunning = false;
            pthread_mutex_unlock(&gStateMutex);
            return NULL;
        }
        pthread_mutex_unlock(&gStateMutex);
        usleep(250000);
    }
}

static bool validatePCMHeader(const SiriPlusPCMHeader *header, size_t mapSize) {
    if (memcmp(header->magic, "SPRM", 4) != 0) {
        return false;
    }
    if ((header->version != 1 && header->version != 2) || header->sampleRate != 16000 || header->channels != kSiriPlusSharedPCMChannelCount || header->bytesPerFrame != 2) {
        return false;
    }
    size_t headerBytes = header->version == 2 ? header->headerBytes : kSiriPlusPCMHeaderSizeV1;
    if (headerBytes < kSiriPlusPCMHeaderSizeV1 || headerBytes > kSiriPlusPCMHeaderSizeV2) {
        return false;
    }
    size_t requiredSize = headerBytes + ((size_t)header->capacityFrames * sizeof(int16_t) * kSiriPlusSharedPCMChannelCount);
    return header->capacityFrames > 0 && requiredSize <= mapSize;
}

static bool isStalePCMHeader(const SiriPlusPCMHeader *header) {
    if (header->version < 2) {
        return false;
    }
    if (header->writerPID == 0) {
        return true;
    }
    errno = 0;
    if (kill((pid_t)header->writerPID, 0) == 0) {
        return false;
    }
    return errno == ESRCH;
}

static size_t pcmHeaderBytes(const SiriPlusPCMHeader *header) {
    if (header->version == 2 && header->headerBytes >= kSiriPlusPCMHeaderSizeV1 && header->headerBytes <= kSiriPlusPCMHeaderSizeV2) {
        return header->headerBytes;
    }
    return kSiriPlusPCMHeaderSizeV1;
}

static void fillSilence(Float32 *output, UInt32 frameCount) {
    memset(output, 0, sizeof(Float32) * frameCount * kSiriPlusChannelCount);
}

static void writeOutputFrame(Float32 *output, UInt32 frame, Float32 sample) {
    UInt32 offset = frame * kSiriPlusChannelCount;
    for (UInt32 channel = 0; channel < kSiriPlusChannelCount; channel++) {
        output[offset + channel] = sample;
    }
}

static uint64_t resyncedReadFrame(uint64_t writeFrame, UInt32 frameCount) {
    if (writeFrame > kSiriPlusReadLatencyFrames) {
        return writeFrame - kSiriPlusReadLatencyFrames;
    }
    if (writeFrame > frameCount) {
        return writeFrame - frameCount;
    }
    return 0;
}

static uint64_t bufferedFrameCount(SiriPlusClientReadState *state, uint64_t writeFrame) {
    return writeFrame > state->readFrame ? writeFrame - state->readFrame : 0;
}

static uint64_t underrunRecoveryFrameCount(UInt32 frameCount) {
    return kSiriPlusUnderrunRecoveryFrames > frameCount ? kSiriPlusUnderrunRecoveryFrames : frameCount;
}

static uint64_t recoveredReadFrame(SiriPlusClientReadState *state, uint64_t writeFrame, UInt32 frameCount) {
    if (state->readFrame == 0 || writeFrame < state->readFrame) {
        return resyncedReadFrame(writeFrame, frameCount);
    }
    return state->readFrame;
}

static void recordReaderUnderrun(SiriPlusPCMMapSnapshot *snapshot, SiriPlusPCMHeader *header) {
    if (!snapshot->writable) {
        return;
    }
    if (header->version < 2 || header->headerBytes < kSiriPlusPCMHeaderSizeV2) {
        return;
    }
    __atomic_add_fetch(&header->readerUnderrunCount, 1, __ATOMIC_RELAXED);
}

static void fillFromSharedPCM(Float32 *output, UInt32 frameCount, UInt32 clientID) {
    SiriPlusPCMMapSnapshot *snapshot = retainPCMMapSnapshot();
    if (snapshot == NULL) {
        fillSilence(output, frameCount);
        return;
    }

    SiriPlusClientReadState *state = clientReadState(clientID, false);

    SiriPlusPCMHeader *header = (SiriPlusPCMHeader *)snapshot->map;
    if (!validatePCMHeader(header, snapshot->mapSize)) {
        releasePCMMapSnapshot(snapshot);
        fillSilence(output, frameCount);
        return;
    }

    const int16_t *samples = (const int16_t *)((const uint8_t *)snapshot->map + pcmHeaderBytes(header));
    const uint64_t writeFrame = __atomic_load_n(&header->writeFrame, __ATOMIC_ACQUIRE);
    const uint64_t generation = header->version == 2 ? __atomic_load_n(&header->generation, __ATOMIC_ACQUIRE) : 0;
    const uint32_t capacityFrames = header->capacityFrames;
    const bool readFrameTooOld = writeFrame > capacityFrames && state->readFrame + frameCount < writeFrame - capacityFrames;

    if (generation != state->pcmGeneration) {
        state->pcmGeneration = generation;
        state->readFrame = resyncedReadFrame(writeFrame, frameCount);
        state->pcmUnderrun = false;
    } else if (writeFrame < state->readFrame || state->readFrame == 0 || readFrameTooOld) {
        state->readFrame = resyncedReadFrame(writeFrame, frameCount);
        state->pcmUnderrun = false;
    }

    if (state->pcmUnderrun) {
        if (bufferedFrameCount(state, writeFrame) < underrunRecoveryFrameCount(frameCount)) {
            fillSilence(output, frameCount);
            releasePCMMapSnapshot(snapshot);
            return;
        }
        state->readFrame = recoveredReadFrame(state, writeFrame, frameCount);
        state->pcmUnderrun = false;
    } else if (state->readFrame < writeFrame) {
        state->pcmUnderrun = false;
    }

    for (UInt32 frame = 0; frame < frameCount; frame++) {
        if (state->readFrame >= writeFrame) {
            writeOutputFrame(output, frame, 0.0f);
            if (!state->pcmUnderrun) {
                recordReaderUnderrun(snapshot, header);
            }
            state->pcmUnderrun = true;
        } else {
            uint32_t index = (uint32_t)(state->readFrame % capacityFrames);
            Float32 sample = (Float32)samples[index] / 32768.0f;
            writeOutputFrame(output, frame, sample);
            state->readFrame++;
        }
    }
    releasePCMMapSnapshot(snapshot);
}

static HRESULT STDMETHODCALLTYPE QueryInterface(void *inDriver, REFIID inUUID, LPVOID *outInterface) {
    (void)inDriver;
    if (outInterface == NULL) {
        return E_POINTER;
    }

    CFUUIDRef requested = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, inUUID);
    if (requested == NULL) {
        *outInterface = NULL;
        return E_NOINTERFACE;
    }

    bool matches = CFEqual(requested, IUnknownUUID) || CFEqual(requested, kAudioServerPlugInDriverInterfaceUUID);
    CFRelease(requested);

    if (!matches) {
        *outInterface = NULL;
        return E_NOINTERFACE;
    }

    AddRef(gDriverRef);
    *outInterface = gDriverRef;
    return S_OK;
}

static ULONG STDMETHODCALLTYPE AddRef(void *inDriver) {
    (void)inDriver;
    return __sync_add_and_fetch(&gReferenceCount, 1);
}

static ULONG STDMETHODCALLTYPE Release(void *inDriver) {
    (void)inDriver;
    UInt32 count = __sync_sub_and_fetch(&gReferenceCount, 1);
    if (count == 0) {
        pthread_mutex_lock(&gStateMutex);
        gPCMRefreshThreadStopRequested = true;
        closePCMMap();
        reapRetiredPCMMapSnapshotsLocked(true);
        pthread_mutex_unlock(&gStateMutex);
    }
    return count;
}

static OSStatus STDMETHODCALLTYPE Initialize(AudioServerPlugInDriverRef inDriver, AudioServerPlugInHostRef inHost) {
    (void)inDriver;
    traceLine("SiriPlusRemoteMic: Initialize called host=%p", inHost);
    gHost = inHost;
    gAnchorHostTime = mach_absolute_time();
    hostTicksPerFrame();
    traceLine("SiriPlusRemoteMic: Initialize complete");
    return noErr;
}

static OSStatus STDMETHODCALLTYPE CreateDevice(AudioServerPlugInDriverRef inDriver, CFDictionaryRef inDescription, const AudioServerPlugInClientInfo *inClientInfo, AudioObjectID *outDeviceObjectID) {
    (void)inDriver;
    (void)inDescription;
    (void)inClientInfo;
    if (outDeviceObjectID != NULL) {
        *outDeviceObjectID = kAudioObjectUnknown;
    }
    return kAudioHardwareUnsupportedOperationError;
}

static OSStatus STDMETHODCALLTYPE DestroyDevice(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID) {
    (void)inDriver;
    (void)inDeviceObjectID;
    return kAudioHardwareUnsupportedOperationError;
}

static OSStatus STDMETHODCALLTYPE AddDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo *inClientInfo) {
    (void)inDriver;
    (void)inDeviceObjectID;
    (void)inClientInfo;
    return noErr;
}

static OSStatus STDMETHODCALLTYPE RemoveDeviceClient(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, const AudioServerPlugInClientInfo *inClientInfo) {
    (void)inDriver;
    (void)inDeviceObjectID;
    (void)inClientInfo;
    return noErr;
}

static OSStatus STDMETHODCALLTYPE PerformDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void *inChangeInfo) {
    (void)inDriver;
    (void)inDeviceObjectID;
    (void)inChangeAction;
    (void)inChangeInfo;
    return noErr;
}

static OSStatus STDMETHODCALLTYPE AbortDeviceConfigurationChange(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt64 inChangeAction, void *inChangeInfo) {
    (void)inDriver;
    (void)inDeviceObjectID;
    (void)inChangeAction;
    (void)inChangeInfo;
    return noErr;
}

static Boolean STDMETHODCALLTYPE HasProperty(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress) {
    (void)inDriver;
    (void)inClientProcessID;
    if (inAddress == NULL) {
        return false;
    }
    if (inObjectID == kSiriPlusDeviceObjectID && hasZeroLengthDeviceProperty(inAddress)) {
        return true;
    }
    return propertyDataSize(inObjectID, inAddress, 0) > 0;
}

static OSStatus STDMETHODCALLTYPE IsPropertySettable(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, Boolean *outIsSettable) {
    (void)inDriver;
    (void)inObjectID;
    (void)inClientProcessID;
    (void)inAddress;
    if (outIsSettable == NULL) {
        return kAudioHardwareBadPropertySizeError;
    }
    *outIsSettable = false;
    return noErr;
}

static OSStatus STDMETHODCALLTYPE GetPropertyDataSize(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 *outDataSize) {
    (void)inDriver;
    (void)inClientProcessID;
    (void)inQualifierData;
    if (inAddress == NULL || outDataSize == NULL) {
        traceProperty("GetPropertyDataSize", inObjectID, inAddress, kAudioHardwareBadPropertySizeError, 0);
        return kAudioHardwareBadPropertySizeError;
    }
    UInt32 size = propertyDataSize(inObjectID, inAddress, inQualifierDataSize);
    if (size == 0 && !HasProperty(inDriver, inObjectID, inClientProcessID, inAddress)) {
        OSStatus status = isKnownObject(inObjectID) ? kAudioHardwareUnknownPropertyError : kAudioHardwareBadObjectError;
        traceProperty("GetPropertyDataSize", inObjectID, inAddress, status, 0);
        return status;
    }
    *outDataSize = size;
    traceProperty("GetPropertyDataSize", inObjectID, inAddress, noErr, size);
    return noErr;
}

static OSStatus STDMETHODCALLTYPE GetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 inDataSize, UInt32 *outDataSize, void *outData) {
    (void)inDriver;
    (void)inClientProcessID;
    if (inAddress == NULL || outDataSize == NULL) {
        traceProperty("GetPropertyData", inObjectID, inAddress, kAudioHardwareBadPropertySizeError, 0);
        return kAudioHardwareBadPropertySizeError;
    }
    if (outData == NULL) {
        UInt32 size = propertyDataSize(inObjectID, inAddress, inQualifierDataSize);
        if (size == 0 && HasProperty(inDriver, inObjectID, inClientProcessID, inAddress)) {
            *outDataSize = 0;
            traceProperty("GetPropertyData", inObjectID, inAddress, noErr, 0);
            return noErr;
        }
        traceProperty("GetPropertyData", inObjectID, inAddress, kAudioHardwareBadPropertySizeError, 0);
        return kAudioHardwareBadPropertySizeError;
    }
    OSStatus status = noErr;
    if (inObjectID == kAudioObjectPlugInObject) {
        status = copyPlugInProperty(inAddress, inQualifierDataSize, inQualifierData, inDataSize, outDataSize, outData);
        traceProperty("GetPropertyData", inObjectID, inAddress, status, status == noErr ? *outDataSize : 0);
        return status;
    }
    if (inObjectID == kSiriPlusDeviceObjectID) {
        status = copyDeviceProperty(inAddress, inDataSize, outDataSize, outData);
        traceProperty("GetPropertyData", inObjectID, inAddress, status, status == noErr ? *outDataSize : 0);
        return status;
    }
    if (inObjectID == kSiriPlusStreamObjectID) {
        status = copyStreamProperty(inAddress, inDataSize, outDataSize, outData);
        traceProperty("GetPropertyData", inObjectID, inAddress, status, status == noErr ? *outDataSize : 0);
        return status;
    }
    traceProperty("GetPropertyData", inObjectID, inAddress, kAudioHardwareBadObjectError, 0);
    return kAudioHardwareBadObjectError;
}

static OSStatus STDMETHODCALLTYPE SetPropertyData(AudioServerPlugInDriverRef inDriver, AudioObjectID inObjectID, pid_t inClientProcessID, const AudioObjectPropertyAddress *inAddress, UInt32 inQualifierDataSize, const void *inQualifierData, UInt32 inDataSize, const void *inData) {
    (void)inDriver;
    (void)inObjectID;
    (void)inClientProcessID;
    (void)inAddress;
    (void)inQualifierDataSize;
    (void)inQualifierData;
    (void)inDataSize;
    (void)inData;
    return kAudioHardwareIllegalOperationError;
}

static OSStatus STDMETHODCALLTYPE StartIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID) {
    (void)inDriver;
    (void)inClientID;
    if (inDeviceObjectID != kSiriPlusDeviceObjectID) {
        return kAudioHardwareBadDeviceError;
    }
    pthread_mutex_lock(&gStateMutex);
    gRunningClientCount++;
    gIOSeed++;
    gReclaimEpoch++;
    resetClientReadState(clientReadState(inClientID, true));
    gAnchorHostTime = mach_absolute_time();
    ensurePCMMapLocked();
    startPCMRefreshThreadLocked();
    reapRetiredPCMMapSnapshotsLocked(false);
    pthread_mutex_unlock(&gStateMutex);
    return noErr;
}

static OSStatus STDMETHODCALLTYPE StopIO(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID) {
    (void)inDriver;
    (void)inClientID;
    if (inDeviceObjectID != kSiriPlusDeviceObjectID) {
        return kAudioHardwareBadDeviceError;
    }
    pthread_mutex_lock(&gStateMutex);
    if (gRunningClientCount > 0) {
        gRunningClientCount--;
    }
    gIOSeed++;
    gReclaimEpoch++;
    removeClientReadState(inClientID);
    if (gRunningClientCount == 0) {
        gPCMRefreshThreadStopRequested = true;
        closePCMMap();
    }
    reapRetiredPCMMapSnapshotsLocked(false);
    pthread_mutex_unlock(&gStateMutex);
    return noErr;
}

static OSStatus STDMETHODCALLTYPE GetZeroTimeStamp(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, Float64 *outSampleTime, UInt64 *outHostTime, UInt64 *outSeed) {
    (void)inDriver;
    (void)inClientID;
    if (inDeviceObjectID != kSiriPlusDeviceObjectID) {
        return kAudioHardwareBadDeviceError;
    }
    if (outSampleTime == NULL || outHostTime == NULL || outSeed == NULL) {
        return kAudioHardwareBadPropertySizeError;
    }

    UInt64 now = mach_absolute_time();
    UInt64 anchorHostTime = gAnchorHostTime == 0 ? now : gAnchorHostTime;
    double ticksPerFrame = hostTicksPerFrame();
    if (ticksPerFrame <= 0) {
        *outSampleTime = 0;
        *outHostTime = anchorHostTime;
        *outSeed = gIOSeed;
        return noErr;
    }

    UInt64 elapsedTicks = now > anchorHostTime ? now - anchorHostTime : 0;
    UInt64 elapsedFrames = (UInt64)((double)elapsedTicks / ticksPerFrame);
    UInt64 zeroSampleFrame = (elapsedFrames / (UInt64)kSiriPlusZeroTimeStampPeriod) * (UInt64)kSiriPlusZeroTimeStampPeriod;
    UInt64 zeroHostTime = anchorHostTime + (UInt64)((double)zeroSampleFrame * ticksPerFrame);
    *outSampleTime = (Float64)zeroSampleFrame;
    *outHostTime = zeroHostTime;
    *outSeed = gIOSeed;
    return noErr;
}

static OSStatus STDMETHODCALLTYPE WillDoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, Boolean *outWillDo, Boolean *outWillDoInPlace) {
    (void)inDriver;
    (void)inClientID;
    if (inDeviceObjectID != kSiriPlusDeviceObjectID) {
        return kAudioHardwareBadDeviceError;
    }
    if (outWillDo == NULL || outWillDoInPlace == NULL) {
        return kAudioHardwareBadPropertySizeError;
    }
    *outWillDo = inOperationID == kAudioServerPlugInIOOperationReadInput;
    *outWillDoInPlace = true;
    return noErr;
}

static OSStatus STDMETHODCALLTYPE BeginIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo *inIOCycleInfo) {
    (void)inDriver;
    (void)inClientID;
    (void)inOperationID;
    (void)inIOBufferFrameSize;
    (void)inIOCycleInfo;
    return inDeviceObjectID == kSiriPlusDeviceObjectID ? noErr : kAudioHardwareBadDeviceError;
}

static OSStatus STDMETHODCALLTYPE DoIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, AudioObjectID inStreamObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo *inIOCycleInfo, void *ioMainBuffer, void *ioSecondaryBuffer) {
    (void)inDriver;
    (void)inClientID;
    (void)inIOCycleInfo;
    (void)ioSecondaryBuffer;
    if (inDeviceObjectID != kSiriPlusDeviceObjectID || inStreamObjectID != kSiriPlusStreamObjectID) {
        return kAudioHardwareBadObjectError;
    }
    if (inOperationID != kAudioServerPlugInIOOperationReadInput) {
        return noErr;
    }
    if (ioMainBuffer == NULL) {
        return kAudioHardwareBadPropertySizeError;
    }
    fillFromSharedPCM((Float32 *)ioMainBuffer, inIOBufferFrameSize, inClientID);
    return noErr;
}

static OSStatus STDMETHODCALLTYPE EndIOOperation(AudioServerPlugInDriverRef inDriver, AudioObjectID inDeviceObjectID, UInt32 inClientID, UInt32 inOperationID, UInt32 inIOBufferFrameSize, const AudioServerPlugInIOCycleInfo *inIOCycleInfo) {
    (void)inDriver;
    (void)inClientID;
    (void)inOperationID;
    (void)inIOBufferFrameSize;
    (void)inIOCycleInfo;
    return inDeviceObjectID == kSiriPlusDeviceObjectID ? noErr : kAudioHardwareBadDeviceError;
}
