Skip to content

XMBP — Xylolabs Metadata Binary Protocol 명세서

특허 출원 중 — XAP (Xylolabs Audio Protocol) / XMBP (Xylolabs Metadata Binary Protocol)는 Xylolabs Inc.의 독점 기술이다. 특허 출원이 진행 중이다. 무단 사용, 복제 또는 배포를 금한다.


목차

  1. 개요
  2. 배치 와이어 포맷
  3. 스트림 블록 포맷
  4. 샘플 레이아웃
  5. 값 타입 레지스트리
  6. 오디오 코덱 식별자
  7. 인코딩 API
  8. 디코딩 API
  9. 기능 플래그
  10. 전송
  11. 저장 포맷 (XMCH)
  12. 와이어 포맷 예제
  13. 관련 문서
  14. 법적 고지

1. 개요

XMBP (Xylolabs Metadata Binary Protocol)는 IoT 센서 및 모터 텔레메트리 데이터를 위한 컴팩트 이진 프레이밍 프로토콜이다. Xylolabs SDK 탑재 장치와 Xylolabs 인제스트 서버 사이에서 사용되는 온-와이어 포맷이다.

설계 목표:

  • 제로 할당 인코딩. 인코더는 힙 할당 없이 호출자가 제공한 바이트 버퍼에 직접 쓴다. 메모리 할당자가 없는 베어메탈 마이크로컨트롤러(no_std, alloc 없음)에 적합하다.
  • 빅엔디언 바이트 순서. 모든 멀티바이트 정수와 IEEE 754 부동소수점은 네트워크 바이트 순서(빅엔디언, 최상위 바이트 먼저)로 전송된다.
  • 마이크로초 타임스탬프. 모든 샘플은 애플리케이션이 정의한 에포크 이후 마이크로초 단위로 측정된 u64 타임스탬프를 포함한다.
  • 멀티스트림 배칭. 단일 XMBP 배치는 각자의 타입과 샘플 수를 가진 여러 독립적인 센서 스트림의 샘플을 전송할 수 있다.
  • 타입이 지정된 스트림. 각 스트림 블록은 단일 MetadataValueType을 선언하며, 디코더가 샘플별 타입 태그 없이 샘플을 파싱할 수 있도록 한다.

2. 배치 와이어 포맷

XMBP 배치는 연속적인 빅엔디언 바이트 시퀀스이다. 배치는 고정 길이 엔벨로프 헤더로 시작하고, 선택적 장치 ID 필드와 가변 길이 스트림 블록 시퀀스가 뒤따른다.

2.1 엔벨로프 레이아웃

Offset  Size  Field
------  ----  -----
0       4     magic           0x58 0x4D 0x42 0x50  (ASCII "XMBP")
4       1     version         0x01
5       1     flags           bit field (see 2.2)
6       2     batch_seq       u16 BE — monotonically increasing sequence number
[8]     [4]   device_id       u32 BE — present only when flags & 0x01 != 0
8 or 12 2     stream_count    u16 BE — number of stream blocks that follow

스트림 없이 장치 ID 없는 최소 배치는 10 바이트이다.

장치 ID가 있는 경우 최소 배치는 14 바이트이다.

2.2 flags 필드

비트 상수 16진수 의미
0 FLAG_HAS_DEVICE_ID 0x01 4바이트 device_id 필드가 batch_seq 바로 다음에 온다.
1 FLAG_ZSTD_COMPRESSED 0x02 페이로드가 zstd 압축되어 있다. 예약됨. 아직 활성화되지 않았다.
2-7 예약됨. 쓸 때 0이어야 한다. 읽을 때 무시해야 한다.

2.3 필드 참조

필드 타입 크기 비고
magic u32 4 고정값 0x584D4250. 매직이 틀린 배치는 거부한다.
version u8 1 현재 0x01. 알 수 없는 버전은 거부한다.
flags u8 1 비트 필드. 위 표 참조.
batch_seq u16 BE 2 65535에서 래핑. 서버의 갭 감지에 사용된다.
device_id u32 BE 4 선택적. FLAG_HAS_DEVICE_ID가 설정된 경우 존재한다.
stream_count u16 BE 2 뒤따르는 StreamBlock 레코드의 수.

2.4 바이트 레벨 다이어그램

Byte:  00 01 02 03  04  05  06 07  [08 09 0A 0B]  [08|0C] [09|0D]
       +-----------+---+---+------+[------------]+[------+-------]+---...
       | 58 4D 42  | 01 |   |      |[ device_id  ]| stream_count  |
       | 50 magic  |ver |flg|b_seq |[ u32 BE opt ]| u16 BE        | stream blocks...
       +-----------+---+---+------+[------------]+[------+-------]+---...

괄호 [ ] 안의 바이트 오프셋은 FLAG_HAS_DEVICE_ID에 따라 조건부이다.


3. 스트림 블록 포맷

stream_count 바로 다음에 정확히 stream_count개의 스트림 블록이 순서대로 온다. 각 스트림 블록은 단일 값 타입의 샘플을 전송한다.

Offset  Size  Field
------  ----  -----
0       2     stream_id     u16 BE — identifies the logical stream
2       1     value_type    u8    — MetadataValueType wire tag (see Section 5)
3       2     sample_count  u16 BE — number of samples in this block
5       var   samples       sample_count samples (see Section 4)

3.1 필드 참조

필드 타입 크기 비고
stream_id u16 BE 2 인제스트 세션 정의의 스트림 인덱스와 매칭된다.
value_type u8 1 MetadataValueType의 와이어 태그. 5절 참조.
sample_count u16 BE 2 샘플 수. 블록당 최대 65535. 서버는 배치당 256개 스트림 블록으로 제한한다.
samples var 연결된 샘플들. 값 타입에 따른 레이아웃. 4절 참조.

4. 샘플 레이아웃

모든 샘플은 8바이트 마이크로초 타임스탬프(u64 BE)로 시작하고, 인코딩된 값이 바로 뒤따른다. 값 인코딩은 스트림의 value_type에 따라 다르다.

4.1 고정 크기 타입

타입 타임스탬프 값 인코딩 샘플당 합계
F64 u64 BE (8) IEEE 754 double, BE (8) 16 바이트
F32 u64 BE (8) IEEE 754 single, BE (4) 12 바이트
I64 u64 BE (8) signed 64-bit int, BE (8) 16 바이트
I32 u64 BE (8) signed 32-bit int, BE (4) 12 바이트
I16 u64 BE (8) signed 16-bit int, BE (2) 10 바이트
I8 u64 BE (8) signed 8-bit int (u8 cast to i8, 1) 9 바이트
Bool u64 BE (8) u8: 0=false, 1=true (1) 9 바이트

4.2 가변 크기 타입

가변 길이 타입의 경우 각 샘플은 timestamp(8) + length_prefix + payload 형태이다.

타입 길이 접두사 페이로드 비고
String u16 BE (2) UTF-8 인코딩된 바이트 최대 65535 바이트
Bytes u16 BE (2) 원시 바이트 블롭 최대 65535 바이트
F64Array u16 BE (2) N x IEEE 754 double BE (각 8 바이트) 개수 최대 65535. 디코더는 4096으로 제한한다.
F32Array u16 BE (2) N x IEEE 754 single BE (각 4 바이트) 개수 최대 65535. 디코더는 4096으로 제한한다.
I32Array u16 BE (2) N x signed 32-bit int BE (각 4) 개수 최대 65535. 디코더는 4096으로 제한한다.
Json u32 BE (4) UTF-8 인코딩된 JSON 문자열 최대 약 4 GiB (u32). 드물게 사용한다.

참고: Json은 u16이 아닌 4바이트(u32) 길이 접두사를 사용한다. 다른 모든 가변 타입은 2바이트(u16) 접두사를 사용한다.

4.3 샘플 바이트 다이어그램

F32 샘플 (12 바이트):

+--+--+--+--+--+--+--+--+--+--+--+--+
| timestamp_us (u64 BE, 8 bytes)     | f32 BE (4B) |
+--+--+--+--+--+--+--+--+--+--+--+--+

Bool 샘플 (9 바이트):

+--+--+--+--+--+--+--+--+--+
| timestamp_us (u64 BE, 8 bytes)     |v |
+--+--+--+--+--+--+--+--+--+
  v = 0x00 (false) or 0x01 (true)

String 샘플 (가변):

+--+--+--+--+--+--+--+--+--+--+-- ... --+
| timestamp_us (u64 BE, 8 bytes)     |len(u16)|  UTF-8 bytes (len bytes)  |
+--+--+--+--+--+--+--+--+--+--+-- ... --+

Json 샘플 (가변):

+--+--+--+--+--+--+--+--+--+--+--+--+-- ... --+
| timestamp_us (u64 BE, 8 bytes)     | len(u32 BE, 4B) | UTF-8 JSON (len bytes) |
+--+--+--+--+--+--+--+--+--+--+--+--+-- ... --+


5. 값 타입 레지스트리

MetadataValueType 판별자는 각 스트림 블록 헤더에서 단일 바이트 와이어 태그로 전송된다.

와이어 태그 Rust 변형 표시 이름 고정 값 크기 길이 접두사 비고
0x00 F64 f64 8 바이트 IEEE 754 배정밀도, BE
0x01 F32 f32 4 바이트 IEEE 754 단정밀도, BE
0x02 I64 i64 8 바이트 부호 있는 64비트 정수, BE
0x03 I32 i32 4 바이트 부호 있는 32비트 정수, BE
0x04 Bool bool 1 바이트 0x00=false, 0x01=true
0x05 String string 가변 u16 BE UTF-8. 최대 65535 바이트
0x06 Bytes bytes 가변 u16 BE 원시 블롭. 최대 65535 바이트
0x07 F64Array f64_array 가변 u16 BE N x f64 BE
0x08 F32Array f32_array 가변 u16 BE N x f32 BE
0x09 I32Array i32_array 가변 u16 BE N x i32 BE
0x0A Json json 가변 u32 BE UTF-8 JSON. 길이 접두사는 u32
0x0B I16 i16 2 바이트 부호 있는 16비트 정수, BE
0x0C I8 i8 1 바이트 부호 있는 8비트 정수 (u8 cast to i8)

와이어 태그 0x0D부터 0xFF는 예약되어 있다. 알 수 없는 태그를 받은 디코더는 오류(InvalidValueType)를 반환해야 한다.


6. 오디오 코덱 식별자

XMBP Bytes 스트림이 인코딩된 오디오를 전송할 때, 각 샘플 페이로드의 첫 번째 바이트는 코덱 식별자이다. 나머지 바이트는 코덱별 프레임 데이터이다.

코덱 ID 상수 이름 설명
0x01 CODEC_ID_RAW_PCM Raw PCM 비압축 PCM 오디오 샘플
0x02 CODEC_ID_ADPCM IMA-ADPCM IMA Adaptive Differential PCM, 4:1 압축
0x03 CODEC_ID_XAP XAP Xylolabs Audio Protocol
0x04 CODEC_ID_OPUS Opus Opus 코덱 (향후 사용을 위해 예약됨)

XAP 파일 확장자는 .xap(XAP_FILE_EXTENSION)이다.

XAP 프레이밍, 코덱 파라미터, 성능 특성에 대한 상세 내용은 XAP-SPECIFICATION.mdCODEC-ANALYSIS.md를 참조한다.


7. 인코딩 API

7.1 XmbpWriter

XmbpWriter는 제로 할당, no_std 호환 인코더이다. 호출자가 제공한 &mut [u8] 버퍼에 빅엔디언 인코딩 데이터를 직접 쓴다. 어느 시점에서든 버퍼가 요청된 쓰기를 수용할 수 없으면, 라이터는 오버플로우 상태로 진입하고 이후 모든 쓰기는 조용히 무시된다.

pub struct XmbpWriter<'a> {
    buf: &'a mut [u8],
    pos: usize,
    overflow: bool,
}

주요 메서드:

메서드 설명
XmbpWriter::new(buf: &mut [u8]) -> Self 주어진 버퍼 위에 라이터를 생성한다.
reset(&mut self) 위치를 0으로 리셋하고 오버플로우 플래그를 초기화한다.
len(&self) -> usize 지금까지 쓴 바이트 수.
is_ok(&self) -> bool 오버플로우가 발생하지 않은 경우 true를 반환한다.
write_batch_header(version: u8, flags: u8, batch_seq: u16) magic + version + flags + batch_seq를 쓴다 (8 바이트).
write_device_id(device_id: u32) 선택적 장치 ID 필드를 쓴다 (4 바이트).
write_stream_count(count: u16) 스트림 카운트를 쓴다 (2 바이트).
begin_stream(stream_id: u16, value_type: MetadataValueType, sample_count: u16) 스트림 블록 헤더를 쓴다 (5 바이트).
write_sample_f32(timestamp_us: u64, value: f32) F32 샘플 하나를 쓴다 (12 바이트).
write_sample_f64(timestamp_us: u64, value: f64) F64 샘플 하나를 쓴다 (16 바이트).
write_sample_i32(timestamp_us: u64, value: i32) I32 샘플 하나를 쓴다 (12 바이트).
write_sample_i64(timestamp_us: u64, value: i64) I64 샘플 하나를 쓴다 (16 바이트).
write_sample_i16(timestamp_us: u64, value: i16) I16 샘플 하나를 쓴다 (10 바이트).
write_sample_i8(timestamp_us: u64, value: i8) I8 샘플 하나를 쓴다 (9 바이트).
write_sample_bool(timestamp_us: u64, value: bool) Bool 샘플 하나를 쓴다 (9 바이트).
write_sample_string(timestamp_us: u64, s: &str) String 샘플 하나를 쓴다 (가변).
write_sample_bytes(timestamp_us: u64, data: &[u8]) Bytes 샘플 하나를 쓴다 (가변).
write_sample_f32_array(timestamp_us: u64, values: &[f32]) F32Array 샘플 하나를 쓴다 (가변).
write_sample_f64_array(timestamp_us: u64, values: &[f64]) F64Array 샘플 하나를 쓴다 (가변).
write_sample_i32_array(timestamp_us: u64, values: &[i32]) I32Array 샘플 하나를 쓴다 (가변).
write_sample_json(timestamp_us: u64, json_str: &str) Json 샘플 하나를 쓴다 (가변. u32 길이 접두사).
build_f32_batch(...) -> usize 편의용: 단일 호출로 균일한 F32 배치 전체를 인코딩한다.

7.2 인코딩 예제

use xylolabs_protocol::{XmbpWriter, MetadataValueType, constants};

let mut buf = [0u8; 256];
let mut w = XmbpWriter::new(&mut buf);

// Write batch header: version=1, no flags, sequence=0
w.write_batch_header(constants::XMBP_VERSION, 0, 0);
// Write stream count
w.write_stream_count(1);
// Begin stream 0: F32 type, 1 sample
w.begin_stream(0, MetadataValueType::F32, 1);
// Write sample: timestamp 1000 µs, value 23.5
w.write_sample_f32(1000, 23.5);

assert!(w.is_ok());
let len = w.len();
drop(w);
let encoded = &buf[..len]; // 22 bytes total

7.3 편의 빌더 (균일 F32 스트림)

use xylolabs_protocol::{XmbpWriter, constants};

let mut buf = [0u8; 512];
let mut w = XmbpWriter::new(&mut buf);

let timestamps = [1000u64, 2000, 3000];
let values = [1.0f32, 2.0, 3.0,  // stream 0
               4.0, 5.0, 6.0];   // stream 1

let size = w.build_f32_batch(
    0,      // batch_seq
    0xABCD, // device_id (pass 0 to omit)
    2,      // num_streams
    3,      // samples_per_stream
    &timestamps,
    &values,
    3,      // values_stride
);
assert!(size > 0);

valuesvalues[stream * values_stride + sample] 형태로 배치된다. device_id = 0을 전달하면 장치 ID 필드가 생략된다.

7.4 버퍼 크기 상수

constants 모듈은 컴파일 타임 크기 헬퍼를 제공한다:

상수 설명
BATCH_HEADER_BASE 8 magic(4) + version(1) + flags(1) + batch_seq(2)
DEVICE_ID_SIZE 4 선택적 device_id 필드
STREAM_COUNT_SIZE 2 stream_count 필드
STREAM_HEADER_SIZE 5 stream_id(2) + value_type(1) + sample_count(2)
SAMPLE_F64_SIZE 16 timestamp(8) + f64(8)
SAMPLE_F32_SIZE 12 timestamp(8) + f32(4)
SAMPLE_I64_SIZE 16 timestamp(8) + i64(8)
SAMPLE_I32_SIZE 12 timestamp(8) + i32(4)
SAMPLE_I16_SIZE 10 timestamp(8) + i16(2)
SAMPLE_I8_SIZE 9 timestamp(8) + i8(1)
SAMPLE_BOOL_SIZE 9 timestamp(8) + bool(1)

batch_size 컴파일 타임 헬퍼:

use xylolabs_protocol::constants;

// Buffer for 4 streams × 100 F32 samples, with device ID
let required = constants::batch_size(4, 100, constants::SAMPLE_F32_SIZE, true);
// = 8 + 4 + 2 + 4 * (5 + 100 * 12) = 14 + 4 * 1205 = 4834 bytes

8. 디코딩 API

8.1 XmbpReader

XmbpReader는 무상태 디코더이다. 원시 &[u8] 슬라이스에서 완전한 XMBP 배치를 구조화된 힙 할당 타입으로 디코딩한다. 디코더는 alloc 기능이 필요하다.

pub struct XmbpReader;

impl XmbpReader {
    pub fn decode(data: &[u8]) -> Result<XmbpBatch, ProtocolError>;
}

디코딩된 타입:

타입 필드
XmbpBatch version: u8, flags: u8, batch_seq: u16, device_id: Option<u32>, stream_blocks: Vec<StreamBlock>
StreamBlock stream_id: u16, value_type: MetadataValueType, samples: Vec<Sample>
Sample timestamp_us: u64, value: SampleValue
SampleValue 열거형: F64(f64), F32(f32), I64(i64), I32(i32), Bool(bool), String(String), Bytes(Vec<u8>), F64Array(Vec<f64>), F32Array(Vec<f32>), I32Array(Vec<i32>), Json(String), I16(i16), I8(i8)

오류 타입 (ProtocolError):

변형 의미
BufferOverflow 할당 한계 초과 (스트림/배열 개수 제한)
InvalidMagic 매직 바이트가 0x584D4250과 일치하지 않는다.
UnsupportedVersion 버전 필드가 0x01이 아니다.
InvalidValueType(u8) 알 수 없는 값 타입 와이어 태그
UnexpectedEof 예상된 바이트가 모두 읽히기 전에 입력이 끝났다.
InvalidUtf8 String 또는 JSON 필드에 유효하지 않은 UTF-8이 포함되어 있다.

디코더 안전 한계:

  • 신뢰할 수 없는 데이터로부터 할당을 제한하기 위해 stream_count256으로 제한된다.
  • 배열 요소 개수(F64Array, F32Array, I32Array)는 샘플당 4096으로 제한된다.

8.2 디코딩 예제

use xylolabs_protocol::{XmbpReader, SampleValue};

let batch = XmbpReader::decode(&encoded_bytes)?;

println!("batch seq={}, device={:?}", batch.batch_seq, batch.device_id);
for block in &batch.stream_blocks {
    println!("stream {} ({:?}): {} samples", block.stream_id, block.value_type, block.samples.len());
    for sample in &block.samples {
        match &sample.value {
            SampleValue::F32(v) => {
                println!("  t={} us  val={}", sample.timestamp_us, v);
            }
            SampleValue::F64(v) => {
                println!("  t={} us  val={}", sample.timestamp_us, v);
            }
            _ => {}
        }
    }
}

9. 기능 플래그

xylolabs-protocol 크레이트는 코드 크기와 의존성을 제어하기 위해 Cargo 기능 플래그를 사용한다.

기능 기본값 효과
alloc 아니오 decode 모듈 활성화: XmbpReader, XmbpBatch, StreamBlock, Sample, SampleValue
std 아니오 alloc을 포함한다. ProtocolErrorstd::error::Error 구현을 제공한다.
serde 아니오 MetadataValueTypeSerialize / Deserialize를 파생시킨다.

기능 플래그 없이는 XmbpWriter, MetadataValueType, ProtocolError, constants만 컴파일된다. 이것이 힙 할당이 불가능한 베어메탈 펌웨어에서 사용되는 설정이다.


10. 전송

10.1 API 키 검증 (Ping)

인제스트 세션을 시작하기 전에 펌웨어에서 API 키가 유효한지 간단히 확인할 수 있다:

GET /api/v1/ping
Host: api.xylolabs.com
X-Api-Key: <device-api-key>

키가 유효하면 200 OK{"pong": true, "api_key_name": "...", "facility_id": "..."}를 반환하고, 유효하지 않으면 401을 반환한다. 세션 리소스를 할당하기 전에 잘못된 키를 조기에 감지하는 데 사용한다.

10.2 인제스트 엔드포인트

XMBP 배치는 Xylolabs 인제스트 API에 HTTP/1.1 POST 요청으로 전달된다:

POST /api/v1/ingest/sessions/{session_id}/data
Host: api.xylolabs.com
Content-Type: application/octet-stream
X-API-Key: <device-api-key>
Content-Length: <byte count>

<raw XMBP batch bytes>
  • session_id는 활성 인제스트 세션을 식별하는 UUID이며, 세션 생성 엔드포인트에서 얻는다.
  • X-API-Key 헤더는 인증을 위한 장치 범위 API 키를 전달한다.
  • 요청 본문은 추가 프레이밍이나 인코딩 없는 원시 XMBP 배치이다.

10.3 배치 시퀀싱

batch_seq 필드(u16, 65535에서 래핑)는 송신자가 유지하는 단조 증가 카운터이다. 서버는 갭 감지에 이를 사용한다: 연속 수신 배치의 batch_seq 값이 순차적이지 않으면 서버는 갭 이벤트를 기록한다. 송신자는 각 전송 배치마다 batch_seq를 1씩 증가시킨다.

10.4 장치 ID

FLAG_HAS_DEVICE_ID가 설정된 경우, device_id 필드(u32)는 멀티 장치 배포에서 원본 하드웨어 단위를 식별한다. 서버는 배치를 매칭하는 등록된 장치 레코드와 연결한다.


11. 저장 포맷 (XMCH)

인제스트 후 서버는 XMCH (Xylolabs Metadata Chunk) 포맷으로 샘플을 저장한다. XMCH는 압축 개선을 위해 타임스탬프와 값을 분리하는 열 지향 레이아웃을 사용한다.

11.1 XMCH 헤더 (32 바이트, 고정)

Offset  Size  Field          Value / Notes
------  ----  -----          ------
0       4     magic          0x58 0x4D 0x43 0x48  (ASCII "XMCH")
4       1     version        0x01
5       1     value_type     MetadataValueType wire tag (same as XMBP)
6       2     reserved       0x0000
8       4     sample_count   u32 BE — number of samples in this chunk
12      8     start_ts_us    u64 BE — timestamp of first sample
20      8     end_ts_us      u64 BE — timestamp of last sample
28      4     data_bytes     u32 BE — byte count of the data section

총 헤더 크기: 32 바이트.

11.2 데이터 섹션 레이아웃

32바이트 헤더 바로 다음:

[timestamp column] [value column]
  • 타임스탬프 열: sample_count x u64 BE — 오름차순의 모든 타임스탬프.
  • 값 열: XMBP 샘플 값 인코딩과 동일하게 인코딩된 sample_count개의 값 (동일한 타입별 규칙, 동일한 바이트 순서). 단, 샘플별 타임스탬프 접두사는 없다.

가변 길이 타입(String, Bytes, F64Array, F32Array, I32Array)의 경우, 값 열의 각 값은 u32 BE 길이/개수 접두사를 사용한다 (XMBP 와이어 포맷의 u16과 다름).

Json의 경우, 값 열은 XMBP 와이어 포맷과 동일하게 u32 BE 길이 접두사를 사용한다.

11.3 압축

XMCH 청크는 zstd를 사용하여 압축 저장될 수 있다. 압축 해제하면 위에서 설명한 원시 32바이트 헤더 + 데이터 섹션 레이아웃이 생성된다. 서버는 압축 해제 폭탄 공격을 방지하기 위해 압축 해제 출력에 64 MiB 한계를 적용한다.

11.4 빈 청크

sample_count = 0인 청크는 data_bytes = 0인 32바이트 헤더만 포함한다. 타임스탬프와 데이터 섹션은 없다.


12. 와이어 포맷 예제

12.1 최소 배치 (10 바이트)

스트림 없이, 장치 ID 없이, 시퀀스 번호 42인 배치:

Offset  Hex   Description
------  ---   -----------
0       58    magic[0] 'X'
1       4D    magic[1] 'M'
2       42    magic[2] 'B'
3       50    magic[3] 'P'
4       01    version = 1
5       00    flags = 0 (no device ID)
6       00    batch_seq high byte
7       2A    batch_seq low byte  (= 42)
8       00    stream_count high byte
9       00    stream_count low byte (= 0)

합계: 10 바이트.

12.2 단일 F32 스트림 (29 바이트)

스트림 하나, F32 샘플 하나 (timestamp=1000 µs, value=23.5):

Offset  Hex            Description
------  ---            -----------
0-3     58 4D 42 50    magic "XMBP"
4       01             version
5       00             flags (no device ID)
6-7     00 00          batch_seq = 0
8-9     00 01          stream_count = 1
--- stream block 0 ---
10-11   00 00          stream_id = 0
12      01             value_type = F32 (tag 0x01)
13-14   00 01          sample_count = 1
--- sample 0 ---
15-22   00 00 00 00    timestamp_us = 1000 µs
        00 00 03 E8    (u64 BE: 0x00000000000003E8)
23-26   41 BC 00 00    f32 BE = 23.5  (IEEE 754: 0x41BC0000)

합계: 29 바이트.

12.3 장치 ID가 있는 멀티스트림 배치

F32 스트림 둘 (각 2개 샘플), device_id = 0x0000ABCD:

Offset  Hex            Description
------  ---            -----------
0-3     58 4D 42 50    magic "XMBP"
4       01             version
5       01             flags = 0x01 (FLAG_HAS_DEVICE_ID)
6-7     00 05          batch_seq = 5
8-11    00 00 AB CD    device_id = 0x0000ABCD
12-13   00 02          stream_count = 2
--- stream block 0 (stream_id=0, F32, 2 samples) ---
14-15   00 00          stream_id = 0
16      01             value_type = F32
17-18   00 02          sample_count = 2
19-30   [sample 0: 8-byte ts + 4-byte f32]
31-42   [sample 1: 8-byte ts + 4-byte f32]
--- stream block 1 (stream_id=1, F32, 2 samples) ---
43-44   00 01          stream_id = 1
45      01             value_type = F32
46-47   00 02          sample_count = 2
48-59   [sample 0: 8-byte ts + 4-byte f32]
60-71   [sample 1: 8-byte ts + 4-byte f32]

합계: 14 (헤더 + device_id) + 2 * (5 + 2 * 12) = 14 + 2 * 29 = 72 바이트.


13. 관련 문서

문서 설명
XAP-SPECIFICATION.md XAP (Xylolabs Audio Protocol) 프레이밍, 코덱 파라미터, 컨테이너 포맷
CODEC-ANALYSIS.md XMBP에서 지원하는 오디오 코덱의 비교 분석
API.en.md Xylolabs REST API 참조 (인제스트, 세션, 장치)
PERFORMANCE-EVALUATION.md 프로토콜 처리량 및 지연 벤치마크

14. 법적 고지

XMBP (Xylolabs Metadata Binary Protocol)는 Xylolabs Inc.가 개발한 독점 기술이다.

XMBP 와이어 포맷, 인코딩 방법론 및 관련 시스템을 포함하는 특허 출원이 제출되었다. 모든 권리가 보유된다.

Xylolabs Inc.의 사전 서면 승인 없이 본 명세서 또는 그 구현의 전부 또는 일부를 무단으로 사용, 복제, 수정 또는 배포하는 것은 엄격히 금지된다.

Copyright (c) Xylolabs Inc. All rights reserved.