보이스 프로필 로컬 PoC 구현과 시험 환경
상위 기준: 보이스 프로필 등록 제품 구현 기준서 10~11장
이 문서는 현재 시험 보드, 산출물과 실행 명령만 관리한다. 제품 책임은 전체 구조와 책임을 본다.
현재 시험 구성
ADB 192.168.10.5:5555
Serial WRBA1M10KRDWA0925E00614
Gateway PC 127.0.0.1:8788
MQTT PC 127.0.0.1:1883
Mobile http://192.168.10.19:8788 (현재 PC LAN 주소)
External https://emphasis-staff-toe-cooperative.trycloudflare.com (현재 Quick Tunnel)
이 구성에서 모바일 앱은 MQTT에 직접 접속하지 않는다. 모바일은 PC Gateway에 HTTP만 보내고, PC Gateway가 요청을 검증한 뒤 로컬 MQTT Broker에 대신 발행한다. 따라서 Sample APK에는 MQTT 인증서나 자격증명이 들어가지 않는다.
Mobile Sample
-> HTTP :8788
PC Sample Gateway
-> MQTT QoS 1 :1883
Local MQTT Broker
-> adb reverse tcp:1883
A1 IotAgent
-> Binder Bundle
DeviceAgent -> Registration App / OnDevice Agent Service
| 구성 | 위치 |
|---|---|
| Mobile Sample | apps/VoiceProfileMobileSample |
| Gateway | tools/voice_profile_sample_gateway |
| IotAgent·DeviceAgent·Registration App | apps/ 하위 모듈 |
| OnDevice Agent Service | skmagic_ondeviceai_agent_speaker_recognition worktree |
전달 패키지:
/home/silogood/work/1.A1_SoC_new/SoC/a1-packages-mr6/
output/voice-profile-vendor-sample-20260827/
일반 휴대폰 APK는 apks/Android-VoiceProfileMobileSample-v0.4.0-test.apk다. 나머지 네 APK는
A1 플랫폼 인증서로 서명된 system/priv-app용 파일이다.
PC Broker와 Gateway
cd /home/silogood/work/1.A1_SoC_new/SoC/a1-packages-mr6
/home/silogood/.local/bin/amqtt \
-c tools/voice_profile_sample_gateway/amqtt-test.yml
VOICE_PROFILE_TRANSPORT=mqtt \
VOICE_PROFILE_MQTT_HOST=127.0.0.1 \
VOICE_PROFILE_MQTT_PORT=1883 \
VOICE_PROFILE_MQTT_API_VERSION=v1 \
python3 -m tools.voice_profile_sample_gateway.server --port 8788
Gateway가 발행·구독하는 토픽은 다음과 같다.
명령 skmg/airbot/{deviceId}/v1/command/voiceProfileEnrollment
응답 skmg/airbot/{deviceId}/v1/response/voiceProfileEnrollment/{requestId}
등록 시작, 취소, 프로필 목록·삭제, 대화·관심사 요청은 같은 명령 토픽에서 action과
payload method로 구분한다. IotAgent는 명령을 DeviceAgent Binder 호출로 바꾸고, 처리 결과를
같은 requestId의 응답 토픽으로 돌려준다.
보드 부팅 후 로컬 Broker 연결을 복구한다.
adb -s 192.168.10.5:5555 reverse tcp:1883 tcp:1883
adb -s 192.168.10.5:5555 shell setprop \
persist.sys.vp.mqtt_test_uri tcp://127.0.0.1:1883
adb reverse는 재부팅과 ADB 재연결 후 다시 설정한다. 제품에서는 이 개발용 Broker와
property를 사용하지 않는다.
property는 IotAgent 생성 시 읽는다. 실행 중인 IotAgent에 property만 바꾸면 로컬 MQTT bridge가 시작되지 않을 수 있으므로 프로세스를 재기동하고 아래 로그를 확인한다.
VoiceProfileMqttTest: Local MQTT connected: tcp://127.0.0.1:1883
VoiceProfileMqttTest: Local MQTT subscribed: skmg/airbot/{deviceId}/v1/command/voiceProfileEnrollment
휴대폰 Sample 사용
PC gateway를 선택한다.- Gateway URL에 휴대폰에서 접근 가능한 PC 주소와
8788포트를 넣는다. - Device ID에
WRBA1M10KRDWA0925E00614를 넣는다. - nickname과 locale을 입력하고 등록 요청을 보낸다.
- A1의 Registration App에서 시작을 누르고 5세트를 진행한다.
- 목록 새로고침은 A1 private storage의 실제 프로필을 읽는다.
휴대폰을 ADB로 PC에 연결했다면 휴대폰 쪽에도 adb reverse tcp:8788 tcp:8788을 설정하고
Gateway URL을 http://127.0.0.1:8788로 사용할 수 있다.
현재 Sample APK의 기본 Gateway URL은 http://192.168.10.19:8788이다. PC 네트워크가
바뀌면 앱에서 새 PC 주소로 수정한다. A1 주소 192.168.10.5는 Gateway 주소가 아니다.
외부망 휴대폰에서 접속
휴대폰이 PC와 같은 Wi-Fi에 없으면 PC Gateway의 8788 포트를 Cloudflare Quick Tunnel로
임시 공개한다. 모바일 앱은 MQTT가 아니라 아래 HTTPS Gateway URL을 사용한다.
https://emphasis-staff-toe-cooperative.trycloudflare.com
/home/silogood/.local/bin/cloudflared tunnel \
--url http://127.0.0.1:8788 \
--no-autoupdate
Quick Tunnel URL은 고정 서버 주소가 아니다. PC 재부팅, cloudflared 종료 또는 터널 재생성 시
주소가 바뀌므로 새 URL을 모바일 앱에 다시 입력해야 한다. 제품 배포에서는 인증된 AWS Backend와
AWS IoT를 사용하며 이 임시 URL을 사용하지 않는다.
현재 URL은 2026-09-10에 아래 두 단계로 확인했다.
curl 'https://emphasis-staff-toe-cooperative.trycloudflare.com/health'
curl 'https://emphasis-staff-toe-cooperative.trycloudflare.com/voice-profiles?deviceId=WRBA1M10KRDWA0925E00614'
두 요청 모두 HTTP 200이었고, 두 번째 요청은 A1에 저장된 yujin / 유진 프로필을 반환했다.
안전한 API 스모크
실제 프로필 목록 조회:
curl --max-time 15 \
'http://127.0.0.1:8788/voice-profiles?deviceId=WRBA1M10KRDWA0925E00614'
등록 시작과 취소는 같은 requestId를 사용한다. 취소 후 목록을 다시 조회해 시험 닉네임이
생성되지 않았는지 확인한다.
2026-08-27 검증 결과
| 항목 | 결과 |
|---|---|
| Gateway health | transport=mqtt, MQTT enabled |
| MQTT 구독 | 새 serial의 voiceProfileEnrollment command topic 구독 확인 |
| 목록 왕복 | A1 정본의 빈 목록을 voiceProfileListResult, HTTP 200으로 반환 |
| 등록 시작 | Registration App이 foreground로 실행됨 |
| 원격 취소 | 같은 request ID로 OnDevice 취소, UI 종료 |
| 취소 후 데이터 | CodexSmoke 프로필 미생성 |
| 안정성 스캔 | 해당 구간 FATAL, ANR, SIGABRT 없음 |
이 검증은 네트워크·Binder 시작/취소 경로다. 실제 5세트 음성 품질, 화자 정확도, 장시간 메모리 안정성은 사용자가 수행할 release E2E 항목으로 남아 있다.
2026-09-10 재검증
| 항목 | 확인 결과 |
|---|---|
| A1 연결 | 192.168.10.5:5555, serial WRBA1M10KRDWA0925E00614 |
| 설치·실행 | DeviceAgent 0.258, IotAgent 0.127, Registration App 0.1.0, OnDevice Agent 1.20.04 |
| Gateway | GET /health HTTP 200, transport=mqtt, mqttEnabled=true |
| MQTT bridge | IotAgent connect·command topic subscribe 확인 |
| 실제 목록 왕복 | voiceProfileListResult, success=true, 등록된 yujin / 유진 반환 |
초기 목록 조회는 HTTP 504였다. Broker보다 먼저 시작돼 있던 persistent IotAgent가 로컬 MQTT property를 다시 읽지 않은 것이 원인이었다. IotAgent 프로세스를 재생성한 뒤 connect·subscribe가 확인됐고 같은 API가 HTTP 200으로 응답했다.
이번 주소는 같은 개발망에서만 유효한 로컬 시험값이다. Gemini Live용 Cloudflare Broker는 음성 스트리밍 서버이며, 보이스 프로필 등록 MQTT Gateway 역할을 하지 않는다.
패키지 초기화 후 재설치 기록
2026-08-27 16:36 KST에 패키지 구성이 바뀐 시험 보드에 A1 시스템 APK 네 개를 다시
설치했다. 설치 전 APK를 먼저 백업하고 모든 후보의 platform certificate SHA-256이
c8a2e9bc...51192ab8로 같은지 확인한 뒤 교체했다.
| 패키지 | 설치 전 | Voice Profile 시험본 | 판단 |
|---|---|---|---|
| OnDevice Agent Service | 1.20.04 |
1.20.04 |
시험본 교체 |
| DeviceAgent | 0.262 |
0.258 |
Voice Profile 계약을 위해 시험 중에만 교체 |
| IotAgent | 0.131 |
0.127 |
로컬 MQTT bridge를 위해 시험 중에만 교체 |
| Registration App | 미설치 | 0.1.0 |
신규 system/priv-app 설치 |
DeviceAgent 0.262와 IotAgent 0.131 소스는 현재 speaker_identification 저장소에 없고,
설치 APK에도 Voice Profile method가 포함되지 않았다. 따라서 이번 보드는 백업 가능한 PoC
형상으로 낮춰 시험했다. 제품 릴리즈는 최신 DeviceAgent·IotAgent 소스에 Voice Profile
패치를 이식해 새 버전으로 빌드해야 하며, 이 PoC APK를 최신 제품 APK로 간주하면 안 된다.
설치 후 로컬 파일과 기기 /system/priv-app 파일의 SHA-256 일치, 패키지 인식, 세 agent
프로세스와 OnDevice ForegroundService 기동을 확인했다. 첫 조회의 504는 부팅 후 설정한
로컬 MQTT property를 기존 IotAgent 프로세스가 읽지 못해 발생했고, IotAgent 재기동 뒤
connect·subscribe 로그를 확인한 후 목록·시작·취소가 정상 왕복했다.
빌드 검증
| 모듈 | 결과 |
|---|---|
| OnDevice Agent Service | 품질 gate 집중 unit test, assembleDeviceRelease 통과 |
| Registration App | unit test, lint, release 통과 |
| DeviceAgent | unit test, release 통과 |
| IotAgent | unit test, devRelease 통과 |
| 전달 패키지 | APK 인증서, SHA-256 17개, patch reverse-check 통과 |
OnDevice 전체 unit suite에는 이번 변경과 무관한 기존 7개 실패가 남아 있다. 집중 테스트와 release 빌드 통과를 전체 회귀 통과로 표현하지 않는다.
개발용 완료 우회
adb -s 192.168.10.5:5555 shell setprop persist.sys.vp.local_ack true
이 값은 DeviceAgent outbox 저장 뒤 UI를 완료로 전환하는 개발 우회다. 실제 Cloud 저장 성공을 뜻하지 않으며 제품 릴리즈에서는 Cloud ACK로 교체한다.