OPWS Developers

TTS 방송

개요

TTS 방송에는 두 가지 진입점이 있습니다. oe.broadcast.tts.send() 는 텍스트를 직접 입력해 합성 후 방송하고, oe.broadcast.tts.fromContent() 는 이미 합성된 컨텐츠를 즉시 방송합니다. 진행 중인 방송은 oe.broadcast.tts.stop() 으로 중단합니다.

시작하기 전에

TTS 방송을 시작하기 전에 아래를 준비하세요.

  • 파트너 앱에 TTS_EXECUTE capability grant 가 있어야 합니다. 없으면 CapabilityDenied 에러가 발생합니다.
  • 방송 대상이 될 디바이스 또는 그룹의 handle 이 필요합니다. 대상 선택 절에서 조회 방법을 안내합니다.

대상 선택

방송 대상은 targetHandle(디바이스 또는 그룹 handle) 또는 deviceHandles(디바이스 handle 다중)로 지정합니다. 대상 목록은 아래와 같이 조회합니다.

ts
const [devices, groups] = await Promise.all([
  oe.targets.list(),
  oe.groups.list(),
]);

각 항목의 handle 값을 대상 지정에 사용합니다. 그룹에 방송하면 그룹에 속한 ASSIGNED 상태 디바이스 전체가 대상이 됩니다.

DeviceView.online 은 조회 시점의 온라인 여부를 나타내는 정보 라벨입니다. 방송 시점의 실제 상태를 보장하지 않으므로 대상 선택 제한 근거로 사용하지 마세요.

언어 선택지 — oe.languages.list()

번역 언어 선택지를 구성할 때 사용합니다. 앱이 바인딩된 현장의 활성 TTS 언어 목록을 반환합니다.

기본 정보

메서드앱 capability참조 handle 조건반환 타입
oe.languages.list()없음(게이트 없음)없음Promise<LanguageOption[]>

요청

입력 파라미터가 없습니다.

응답

이름타입설명
codestring언어 코드(canonical lowercase)
namestring언어 표시명

예제

ts
const langs = await oe.languages.list();
for (const lang of langs) {
  console.log(lang.code, lang.name);
}

참고: 목록은 ko(원문 언어)가 먼저 오고, 이후 표시명 가나다순으로 정렬됩니다.

직접 입력 방송 — oe.broadcast.tts.send()

원문 텍스트를 입력하면 번역·합성을 거쳐 대상에 방송합니다. 원문 언어는 항상 한국어입니다.

기본 정보

메서드앱 capability참조 handle 조건반환 타입
oe.broadcast.tts.send(input)TTS_EXECUTEtargetHandle 또는 deviceHandles 가 유효한 노출 대상이어야 함(그룹은 ASSIGNED 디바이스 전체로 전개, 디바이스 다중은 handle 전원이 유효해야 함)Promise<BroadcastReceipt>

요청

이름타입설명기본값필수
targetHandlestring대상 디바이스 또는 그룹 handle-조건부
deviceHandlesstring[]대상 디바이스 handle 다중 지정-조건부
textstring방송할 텍스트(한국어 원문)-O
languagestring원문 언어 코드. 항상 "ko"-O
additionalLanguagesstring[]추가 번역 언어. 배열 순서가 재생 순서로 유지됨[]X
partialboolean대상 일부 제외를 허용할지 여부-X
expectedRevisionnumber대상 그룹의 revision 고정. 어긋나면 TargetRevisionStale-X
idempotencyKeystring중복 방송 방지 키-O

주의: targetHandledeviceHandles 는 동시에 지정할 수 없습니다. 둘 중 정확히 하나만 지정하세요.

주의: 동일한 idempotencyKey 로 다른 페이로드를 재전송하면 IdempotencyKeyReused 에러가 발생합니다. 네트워크 오류로 재시도할 때는 동일한 키를 재사용하고, 새로운 방송을 시작할 때는 새 키를 생성하세요.

응답

이름타입설명
sessionIdstring | null방송 세션 ID. statusDENIED_BUSINESSnull
status"ADMITTED" | "DENIED_BUSINESS"방송 수락 여부
resolvedDeviceCountnumber실제 방송 대상 디바이스 수
revisionnumber대상 그룹의 현재 revision
denyReasonstring | null거부 사유(DENIED_BUSINESS 시)
skippedstring[]방송에서 제외된 디바이스 handle 목록

참고: 응답에는 admitted(파생 값) 필드도 포함되지만, 수락 여부 판정에는 status 를 사용하세요.

예제

ts
const receipt = await oe.broadcast.tts.send({
  targetHandle,
  text: "출입을 통제합니다",
  language: "ko",
  additionalLanguages: ["en", "ja"],
  idempotencyKey: crypto.randomUUID(),
});

const receipt2 = await oe.broadcast.tts.send({
  deviceHandles,
  text: "출입을 통제합니다",
  language: "ko",
  idempotencyKey: crypto.randomUUID(),
});

대표 에러

에러HTTP 상태원인해결 방법
CapabilityDenied403앱에 TTS_EXECUTE capability grant 가 없음Open Echo 지원 채널로 grant 를 요청하세요
TargetUnresolved404targetHandle/deviceHandles 를 해석할 수 없음대상 handle 이 유효한지 대상 목록을 다시 조회해 확인하세요
IdempotencyKeyReused409동일한 idempotencyKey 로 다른 페이로드를 재전송함새 방송마다 새 키를 생성하세요
DeviceInUse409대상 중 사용 중인 디바이스가 포함됨점유가 풀린 뒤 다시 시도하세요
UsageCapExceeded429일일 TTS 방송 한도를 초과함다음 날 자정(UTC) 이후 다시 시도하세요

컨텐츠 방송 — oe.broadcast.tts.fromContent()

이미 합성이 끝난 노출 컨텐츠를 대상에 즉시 방송합니다.

기본 정보

메서드앱 capability참조 handle 조건반환 타입
oe.broadcast.tts.fromContent(input)TTS_EXECUTE + CONTENT대상 handle 조건은 tts.send() 와 동일. contentHandleCONTENT EXECUTE grant 가 있어야 함Promise<BroadcastReceipt>

요청

이름타입설명기본값필수
contentHandlestring방송할 노출 컨텐츠 handle-O
targetHandlestring대상 디바이스 또는 그룹 handle-조건부
deviceHandlesstring[]대상 디바이스 handle 다중 지정-조건부
languageOrderstring[]재생 언어 순서. 생략하면 컨텐츠 자체 순서를 따름-X
partialboolean대상 일부 제외를 허용할지 여부-X
expectedRevisionnumber대상 그룹의 revision 고정-X
idempotencyKeystring중복 방송 방지 키-O

주의: targetHandledeviceHandles 는 동시에 지정할 수 없습니다. 둘 중 정확히 하나만 지정하세요.

주의: 동일한 idempotencyKey 로 다른 페이로드를 재전송하면 IdempotencyKeyReused 에러가 발생합니다. 네트워크 오류로 재시도할 때는 동일한 키를 재사용하고, 새로운 방송을 시작할 때는 새 키를 생성하세요.

응답

이름타입설명
sessionIdstring | null방송 세션 ID. statusDENIED_BUSINESSnull
status"ADMITTED" | "DENIED_BUSINESS"방송 수락 여부
resolvedDeviceCountnumber실제 방송 대상 디바이스 수
revisionnumber대상 그룹의 현재 revision
denyReasonstring | null거부 사유(DENIED_BUSINESS 시)
skippedstring[]방송에서 제외된 디바이스 handle 목록

예제

ts
const receipt = await oe.broadcast.tts.fromContent({
  contentHandle,
  targetHandle,
  languageOrder: ["ko", "en"],
  idempotencyKey: crypto.randomUUID(),
});

const receipt2 = await oe.broadcast.tts.fromContent({
  contentHandle,
  deviceHandles,
  idempotencyKey: crypto.randomUUID(),
});

대표 에러

에러HTTP 상태원인해결 방법
ContentNotReady400컨텐츠 오디오가 아직 준비되지 않음합성이 끝난 뒤 다시 시도하세요
CapabilityDenied403TTS_EXECUTE 또는 CONTENT grant 가 없음Open Echo 지원 채널로 grant 를 요청하세요
TargetUnresolved404대상 또는 contentHandle 을 해석할 수 없음handle 유효성을 다시 확인하세요
IdempotencyKeyReused409동일한 idempotencyKey 로 다른 페이로드를 재전송함새 방송마다 새 키를 생성하세요

방송 중단 — oe.broadcast.tts.stop()

재생 중(PLAYING)인 자기 소유 세션을 중단합니다.

기본 정보

메서드앱 capability참조 handle 조건반환 타입
oe.broadcast.tts.stop(sessionId)없음(소유권만)sessionId 가 호출 앱 소유의 세션이어야 함Promise<void>

요청

이름타입설명기본값필수
sessionIdstring중단할 방송 세션 ID-O

응답

반환값이 없습니다(Promise<void>).

참고: stop() 이 resolve 되어도 방송이 즉시 끝난 것은 아닙니다. 종결 확인은 subscribe() 로 받는 phase === "STOPPED"(terminal) 이벤트로 합니다.

예제

ts
await oe.broadcast.tts.stop(sessionId);

대표 에러

에러HTTP 상태원인해결 방법
BroadcastIneligible409세션이 재생 중이 아니거나(합성 중·이미 종결) 중단할 수 없는 상태세션 상태를 구독으로 확인한 뒤 다시 시도하세요

방송 상태 확인

send()fromContent() 모두 BroadcastReceipt 를 반환합니다. status 로 수락 여부를 확인하고, sessionId 로 진행 상태를 구독합니다.

status의미
ADMITTED방송이 수락되어 진행 중입니다. sessionId 로 구독하세요
DENIED_BUSINESS정책상 거부되었습니다. sessionIdnull, denyReason 에 사유가 담깁니다
ts
const receipt = await oe.broadcast.tts.send({
  targetHandle,
  text: "출입을 통제합니다",
  language: "ko",
  idempotencyKey: crypto.randomUUID(),
});

if (!receipt.sessionId) {
  console.warn("방송 거부:", receipt.denyReason);
} else {
  oe.broadcast.subscribe(receipt.sessionId, {
    onPhase: (snap) => {
      console.log(snap.phase, snap.terminal);
    },
  });
}

실시간 진행 상태 추적은 진행 구독을 참조하세요.

참고 코드

레퍼런스 앱의 TTS 방송 화면 구현은 partner-app/src/features/tts/TtsBroadcast.tsx 에서 확인할 수 있습니다.

더보기