pile·
프론트엔드·카카오 엔터테인먼트 FE카카오 엔터테인먼트 FE·

리액트로 만든 게임에 사운드 추가하기

React로 만든 웹 게임에서 Safari의 HTMLMediaElement play() 재현 버그를 발견하고, Web Audio API로 근본적으로 해결하는 과정을 공유한다. 오디오 레이턴시와 크로스 브라우저 이슈까지 다루어 웹에서 효과음을 안정적으로 구현하려는 개발자에게 실용적인 해법을 제시한다.

핵심 포인트 - 문제 발견: Safari(맥/iOS)에서 audio.play() 두 번째 호출부터 재생 안 됨. Chrome은 정상. 아이패드 게임 플레이에 치명적 - audio.load() 우회법의 한계: sound.load() 후 sound.play()로 재생은 되지만 매번 네트워크 요청 발생. 잠재적 버그를 또 다른 버그로 막는 방식 - 레이턴시 문제: 키 입력 후 효과음 딜레이 — 게임 경험을 해치는 수준의 지연 발생 - Web Audio API 채택 이유: HTMLMediaElement의 Safari 버그와 레이턴시 없이 안정적으로 오디오 재생 가능. 버퍼 기반 재생으로 낮은 레이턴시 보장 - Web Audio API 핵심 흐름: AudioContext → fetch로 파일 로드 → decodeAudioData → AudioBufferSourceNode → connect(destination) → start() - 주의: AudioBufferSourceNode는 1회용 — 재생할 때마다 새 노드 생성 필요

상세 정리 - Safari의 currentTime=0 초기화 시도: 콘솔에선 0으로 표시되지만 play()는 동작 안 함. 사파리 HTMLMediaElement 버그로 추정 - audio.load() 해결책의 문제: 캐시로 커버되더라도 매 재생마다 네트워크 요청 발생. "버그를 버그로 막는" 방식이라 찜찜함 - AudioContext 생성: const ctx = new AudioContext(). 브라우저마다 vendor prefix 차이 주의(webkitAudioContext) - 오디오 파일 로드: fetch(url) → response.arrayBuffer() → ctx.decodeAudioData()로 AudioBuffer 획득 - 재생 코드: const source = ctx.createBufferSource(); source.buffer = audioBuffer; source.connect(ctx.destination); source.start(0) - 재생할 때마다 createBufferSource() 새로 호출 — 노드 재사용 불가 - Web Audio API 장점: 낮은 레이턴시(버퍼 직접 재생), 채널 수·재생 속도·피치 조절, 다중 오디오 믹싱 가능 - 게임 외 활용: 버튼 효과음, 알림음 등 웹에서 짧은 효과음 구현에 범용적으로 적용 가능 - iOS Safari 제약: 사용자 인터랙션(탭 등) 이전에 AudioContext 재생 불가 — 버튼 클릭 이벤트에서 시작해야 함

왜 읽나: Safari의 오디오 재생 버그를 Web Audio API로 근본 해결하는 과정과 AudioBufferSourceNode 기반 구현 패턴을 통해 크로스 브라우저 오디오 이슈 없는 웹 사운드 구현 방법을 익힐 수 있다.

카카오 엔터테인먼트 FE
카카오 엔터테인먼트 FE 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    항공 프론트엔드 구축기 (7/10): 창구를 하나만 두었습니다

    여기어때 항공 서비스 프론트엔드가 웹과 앱 웹뷰 두 환경에서 동일한 함수 호출로 동작하는 앱 브릿지 추상화 레이어를 설계한 과정을 다룬다. iOS·안드로이드 규약 차이와 "웹에 존재하지 않는 브릿지를 어떻게 호출하나"라는 문제를 단일 추상화 층으로 해결한 구현 사례다.

    요약 이어보기
    #react#typescript#webview+2