HTMLMediaElement preservesPitch=true through AudioContext
Source/WebCore/Modules/webaudio/MediaElementAudioSourceNode.cpp
HTMLMediaElement를 createMediaElementSource()로 AudioContext에 연결하면, Apple 플랫폼에서 오디오는 GPU process 경계를 넘는 provider chain을 통해 전달됩니다. GPU process에서는 AVPlayer를 실행하고 AVAudioMix로 오디오 스트림을 tap합니다. 이렇게 수집된 raw sample은 IPC를 통해 WebContent process로 전달되고, Web Audio graph가 소비하는 구조입니다.
재생 속도가 1x가 아닌 경우, AVPlayer의 varispeed 모드로 인해 tap이 비례적으로 다른 속도로 sample을 내보내게 됩니다. 이는 사실상 sample-rate 이동에 pitch side-effect가 동반되는 현상입니다. 기존에는 MediaElementAudioSourceNode가 playback rate를 resampler의 scale factor에 포함시켜 이를 보정하려 했지만, cross-process 경로에서는 제대로 동작하지 않았습니다.
이번 commit은 접근 방식을 전면적으로 재구성했습니다. 새롭게 추가된 PitchShiftAudioUnit 클래스는 CoreAudio의 AUTimePitch AudioUnit을 래핑하며, GPU process의 AudioSourceProviderAVFObjC provider 레이어에 삽입되었습니다. preservesPitch=true인 경우, 이 pitch shift unit이 tap 이후 IPC를 통해 WebContent process로 sample이 전달되기 전에 varispeed로 인한 pitch 왜곡을 상쇄합니다.
한편 MediaElementAudioSourceNode의 resampler는 단순화되었습니다. 이제 playback rate는 전혀 고려하지 않으며, source와 AudioContext 간의 sample-rate 불일치만 처리합니다. playbackRate와 preservesPitch 상태는 GPU→WebContent 방향의 IPC 메시지로 전달됩니다.
AVPlayer (GPU process)
└─[varispeed tap]─► raw samples at N×sampleRate
│
AudioSourceProviderAVFObjC
├─ preservesPitch=true → PitchShiftAudioUnit (AUTimePitch)
│ └─► pitch-corrected samples at sampleRate
└─ preservesPitch=false → MultiChannelSampleRateConverter
└─► resampled (pitch-shifted) samples
│ [IPC: setPlaybackRate / setPreservesPitch]
▼
WebContent process
└─ MediaElementAudioSourceNode
└─ simple sample-rate resampler (no rate factor)
└─► AudioContext graph
Significance
이번 수정으로 createMediaElementSource()를 통해 오디오가 라우팅될 때 preservesPitch가 묵시적으로 무시되던 오랜 동작 문제가 해결되었습니다. 더 중요한 것은, 새로운 cross-process IPC surface, CoreAudio AudioUnit callback chain, 그리고 비교적 복잡한 audio pipeline 재구성이 도입되었다는 점입니다. 이 모든 변경은 audio 관련 vulnerability에서 공격 가능성이 높은 attack surface를 형성합니다.