hc.
← 모든 프로젝트
INTERCOM / REALTIME COMMUNICATION

화면이 꺼져도,
대화는 이어지도록.

모바일 데이터로 연결되는 Android 무전기.
발화권 제어부터 음성 전송, 기기 입력과 운영까지
하나의 서비스로 구현했습니다.

2026.08 — 2026.10 / 1인 개발
기획, 시스템 설계, 앱과 백엔드 구현, 배포 및 운영

FastAPIWebSocketLiveKitMySQLAWS EC2

● GOOGLE PLAY 출시 / 일반 사용자 다운로드 가능

50명

복합 부하의 오디오 참가자

0%

90초 복합 부하 테스트 패킷 손실

1대

EC2 t3.micro 기반 서버 구성

ONE CHANNEL, ONE SPEAKER01 / 04

음성은 LiveKit으로.
발화권은 서버에서.

01 / INPUTAndroid무전 버튼과 볼륨키
발화권 요청 →
CONTROL / WebSocketFastAPI한 채널에 한 명만 승인
승인 후 음성 송신 ↓
AUDIO / WebRTCLiveKit SFU승인된 발화자의 음성 중계
음성 전달 ↓
RECEIVE같은 채널의 수신자음성 수신과 발화 상태 갱신

발화 흐름을 설명하는 인터랙티브 도식
01 / THE PRODUCT

말하고, 확인하고,
놓친 대화를 다시 찾습니다.

실시간 무전과 채널 대화를 같은 앱에 연결했습니다. 화면을 선택하면 실제 Android 앱의 캡처를 볼 수 있습니다.

버튼 하나로 발화를 시작합니다.

같은 채널에 접속한 사용자끼리 음성을 주고받습니다. 마이크와 수신 음량을 각각 조절하고 호출음으로 상대에게 신호를 보낼 수 있습니다.

실제 앱 캡처 / 화면을 누르면 확대됩니다.

02 / DESIGN DECISIONS

기기에서 발생한 문제를,
서비스 구조에 반영했습니다.

01 / CONTROL & AUDIO

말할 순서를 정하는 일과
소리를 보내는 일을 분리.

한 채널에서 여러 사용자가 동시에 버튼을 눌러도 발화자는 한 명이어야 했습니다. WebRTC 미디어 중계는 LiveKit에 맡기고, 발화권은 FastAPI가 관리하도록 분리했습니다.

발화 요청→서버 승인→송신 권한 부여

서버는 발화권에 맞춰 LiveKit 송신 권한을 변경합니다. 종료와 타임아웃에서는 권한을 회수하고 채널에 발화 종료를 알립니다. 10명이 동시에 발화권을 요청하는 테스트에서 한 명만 승인되는 것을 확인했습니다.

02 / SCREEN-OFF INPUT

누른 시간을 믿을 수 없어,
입력 방식을 바꿨습니다.

화면이 꺼진 상태에서는 버튼 이벤트가 한꺼번에 전달됐습니다. 로그로 이 현상을 확인한 뒤, 누르는 시간에 의존하던 방식에서 한 번 눌러 시작하고 다시 눌러 종료하는 토글 방식으로 변경했습니다.

다른 앱 사용 중누르는 동안 말하기접근성 권한으로 볼륨키 입력 처리
화면 꺼짐과 잠금 상태한 번 시작 / 다시 종료버튼 간격 대신 발화 상태로 판단

화면을 확인하려고 켰을 때 발화가 끊기는 문제도 수정했습니다. 알림의 종료 버튼과 볼륨키가 같은 발화 상태를 참조하도록 통합해, 서로 다른 경로로 시작하고 종료해도 상태가 어긋나지 않게 했습니다.

03 / PRESENCE

변화가 없을 때는,
목록을 다시 요청하지 않도록.

접속자 현황을 10초마다 조회하면 50명이 화면을 열어 둔 동안 분당 300건의 조회가 발생합니다. 각 요청이 사용자와 채널 정보를 다시 읽는 구조를 변경했습니다.

기존 / 50명, 10초 폴링
300회 / 분
변경 / 상태 변화 없는 동안
정기 조회 0회

연결, 입장, 퇴장 등 상태가 바뀔 때만 WebSocket으로 해당 사용자의 변경 사항을 보냅니다. 앱은 목록에 변경 사항을 반영하고, 재연결 시 전체 목록을 받아 다시 맞춥니다.

04 / PHYSICAL CONTROLS

블루투스 버튼마다 다른
입력을 등록해서 사용.

리모컨마다 전달하는 키 코드가 달랐고, 누르고 있어도 뗌 이벤트를 즉시 보내는 기기가 있었습니다. 버튼 입력을 직접 등록하고, 토글 방식으로 발화를 제어하도록 구성했습니다.

등록한 키 하나만 처리하면 같은 리모컨의 다른 버튼이 볼륨키 경로로 들어와 발화를 끊는 문제가 있었습니다. 등록된 기기를 기준으로 입력 경로를 구분하고 실시간 연결 상태를 화면에 표시했습니다.

05 / ONBOARDING

권한 설명을 읽는 대신,
화면을 따라 설정하도록.

다른 앱 사용 중 볼륨키로 말하려면 사용자가 시스템 설정에서 접근성 권한을 직접 켜야 합니다. 긴 텍스트 안내를 따라가기 어려워하는 사용자 피드백을 반영했습니다.

실기기 화면 녹화→터치 위치 강조→앱 안에서 반복 안내

16초 무음 안내 영상과 4단계 요약을 함께 배치했습니다. 기능 사용 목적과 동의 화면을 분리하고, 동의하지 않아도 앱 내 무전 버튼은 사용할 수 있도록 구성했습니다.

03 / LOAD VALIDATION

음성 통화 중 신규 접속까지,
같은 서버에 부하를 겹쳤습니다.

EC2 t3.micro에서 5개 채널의 오디오 참가자 50명과
별도의 신규 가입 50명 부하를 동시에 실행했습니다.

90초 복합 부하 테스트
채널 1
10명
채널 2
10명
채널 3
10명
채널 4
10명
채널 5
10명
발화자 1명수신자 9명 / 채널
+ 신규 사용자 50명
가입 → 로그인 → 입장 → WebSocket 연결 → 발화권 경쟁
100%

오디오 구독 성공

5개 채널 각각 수신자 9명 전원 구독

0%

패킷 손실

90초 복합 부하 시나리오에서 측정

1명

발화권 승인

동시 요청 10명 중 한 명만 승인

오디오 참가자 50명과 신규 가입 부하 50명은 서로 다른 테스트 집단입니다.

04 / RELEASE & OPERATIONS

개인 개발에서,
누구나 설치할 수 있는 앱으로.

GROUPS

모임별로 구분되는 대화

모임과 채널, 회원 권한을 분리하고 QR 입장을 연결했습니다. 접속자 현황도 모임을 기준으로 전달해 다른 모임의 채널 정보가 노출되지 않도록 구성했습니다.

CONVERSATION

실시간 이후의 대화까지

문자와 사진, 발화 이력을 시간순으로 통합했습니다. 기기에 남아 있는 음성을 다시 듣고 사람별로 대화를 찾아볼 수 있도록 구성했습니다.

OPERATIONS

운영자가 조절하는 채널

웹 관리 화면에서 모임별 채널을 추가하고 이름과 정원을 변경할 수 있게 했습니다. 제한을 낮춰도 기존 채널과 접속자를 바로 제거하지 않도록 처리했습니다.

AVAILABLE ON GOOGLE PLAY

INTERCOM 무전기

기획부터 앱과 서버 구현, 운영 및 Google Play 출시까지 진행했습니다.

Google Play에서 보기 ↗
다른 프로젝트 보기 INTERCOM 앱 화면 확대