1use gbp::CodecError;
4use gbp_core::PayloadCodec;
5use serde::{Deserialize, Serialize};
6use serde_bytes::ByteBuf;
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct GapPayload {
11 #[serde(rename = "msid")]
13 pub media_source_id: u32,
14 #[serde(rename = "seq")]
16 pub rtp_sequence: u32,
17 #[serde(rename = "ts")]
19 pub rtp_timestamp: u64,
20 #[serde(rename = "kp")]
22 pub key_phase: u32,
23 #[serde(rename = "opus")]
25 pub opus_frame: ByteBuf,
26}
27
28impl GapPayload {
29 pub fn opus_20ms(
31 media_source_id: u32,
32 rtp_sequence: u16,
33 key_phase: u32,
34 opus: Vec<u8>,
35 ) -> Self {
36 Self {
37 media_source_id,
38 rtp_sequence: rtp_sequence as u32,
39 rtp_timestamp: 960,
40 key_phase,
41 opus_frame: ByteBuf::from(opus),
42 }
43 }
44
45 pub fn with_timestamp(
48 media_source_id: u32,
49 rtp_sequence: u16,
50 rtp_timestamp: u64,
51 key_phase: u32,
52 opus: Vec<u8>,
53 ) -> Self {
54 Self {
55 media_source_id,
56 rtp_sequence: rtp_sequence as u32,
57 rtp_timestamp,
58 key_phase,
59 opus_frame: ByteBuf::from(opus),
60 }
61 }
62
63 pub fn to_cbor(&self) -> Vec<u8> {
65 let mut buf = Vec::new();
66 ciborium::into_writer(self, &mut buf).expect("cbor encode");
67 buf
68 }
69
70 pub fn from_cbor(data: &[u8]) -> Result<Self, CodecError> {
72 ciborium::from_reader(data).map_err(|e| CodecError::Decode(e.to_string()))
73 }
74
75 pub fn to_bytes(&self, codec: PayloadCodec) -> Vec<u8> {
77 match codec {
78 PayloadCodec::Cbor => self.to_cbor(),
79 PayloadCodec::Protobuf => {
80 use prost::Message as _;
81 gbp_proto::gap::GapPayload::from(self).encode_to_vec()
82 }
83 PayloadCodec::FlatBuffers => {
84 let mut b = gbp_flat::planus::Builder::new();
85 b.finish(gbp_flat::gap::GapPayload::from(self), None)
86 .to_vec()
87 }
88 }
89 }
90
91 pub fn from_bytes(data: &[u8], codec: PayloadCodec) -> Result<Self, CodecError> {
93 match codec {
94 PayloadCodec::Cbor => Self::from_cbor(data),
95 PayloadCodec::Protobuf => {
96 use prost::Message as _;
97 let p = gbp_proto::gap::GapPayload::decode(data)
98 .map_err(|e| CodecError::Decode(e.to_string()))?;
99 Ok(Self::from(p))
100 }
101 PayloadCodec::FlatBuffers => {
102 use gbp_flat::planus::ReadAsRoot as _;
103 let r = gbp_flat::gap::GapPayloadRef::read_as_root(data)
104 .map_err(|e| CodecError::Decode(e.to_string()))?;
105 Self::try_from(r).map_err(|_| CodecError::Decode("flatbuffers field error".into()))
106 }
107 }
108 }
109}
110
111impl From<&GapPayload> for gbp_proto::gap::GapPayload {
114 fn from(p: &GapPayload) -> Self {
115 Self {
116 media_source_id: p.media_source_id,
117 rtp_sequence: p.rtp_sequence,
118 rtp_timestamp: p.rtp_timestamp,
119 key_phase: p.key_phase,
120 opus_frame: p.opus_frame.to_vec(),
121 }
122 }
123}
124
125impl From<gbp_proto::gap::GapPayload> for GapPayload {
126 fn from(p: gbp_proto::gap::GapPayload) -> Self {
127 Self {
128 media_source_id: p.media_source_id,
129 rtp_sequence: p.rtp_sequence,
130 rtp_timestamp: p.rtp_timestamp,
131 key_phase: p.key_phase,
132 opus_frame: ByteBuf::from(p.opus_frame),
133 }
134 }
135}
136
137impl From<&GapPayload> for gbp_flat::gap::GapPayload {
140 fn from(p: &GapPayload) -> Self {
141 Self {
142 media_source_id: p.media_source_id,
143 rtp_sequence: p.rtp_sequence,
144 rtp_timestamp: p.rtp_timestamp,
145 key_phase: p.key_phase,
146 opus_frame: Some(p.opus_frame.to_vec()),
147 }
148 }
149}
150
151impl<'a> TryFrom<gbp_flat::gap::GapPayloadRef<'a>> for GapPayload {
152 type Error = ();
153 fn try_from(r: gbp_flat::gap::GapPayloadRef<'a>) -> Result<Self, ()> {
154 let opus_frame = r.opus_frame().map_err(|_| ())?.unwrap_or(&[]).to_vec();
155 Ok(Self {
156 media_source_id: r.media_source_id().map_err(|_| ())?,
157 rtp_sequence: r.rtp_sequence().map_err(|_| ())?,
158 rtp_timestamp: r.rtp_timestamp().map_err(|_| ())?,
159 key_phase: r.key_phase().map_err(|_| ())?,
160 opus_frame: ByteBuf::from(opus_frame),
161 })
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 fn sample() -> GapPayload {
170 GapPayload::opus_20ms(1, 42, 7, vec![0xAB, 0xCD, 0xEF])
171 }
172
173 #[test]
174 fn cbor_roundtrip() {
175 let orig = sample();
176 let bytes = orig.to_bytes(PayloadCodec::Cbor);
177 let decoded = GapPayload::from_bytes(&bytes, PayloadCodec::Cbor).unwrap();
178 assert_eq!(decoded.media_source_id, orig.media_source_id);
179 assert_eq!(decoded.rtp_sequence, orig.rtp_sequence);
180 assert_eq!(decoded.key_phase, orig.key_phase);
181 assert_eq!(decoded.opus_frame.as_ref(), orig.opus_frame.as_ref());
182 }
183
184 #[test]
185 fn protobuf_roundtrip() {
186 let orig = sample();
187 let bytes = orig.to_bytes(PayloadCodec::Protobuf);
188 let decoded = GapPayload::from_bytes(&bytes, PayloadCodec::Protobuf).unwrap();
189 assert_eq!(decoded.media_source_id, orig.media_source_id);
190 assert_eq!(decoded.rtp_sequence, orig.rtp_sequence);
191 assert_eq!(decoded.opus_frame.as_ref(), orig.opus_frame.as_ref());
192 }
193
194 #[test]
195 fn flatbuffers_roundtrip() {
196 let orig = sample();
197 let bytes = orig.to_bytes(PayloadCodec::FlatBuffers);
198 let decoded = GapPayload::from_bytes(&bytes, PayloadCodec::FlatBuffers).unwrap();
199 assert_eq!(decoded.media_source_id, orig.media_source_id);
200 assert_eq!(decoded.rtp_sequence, orig.rtp_sequence);
201 assert_eq!(decoded.opus_frame.as_ref(), orig.opus_frame.as_ref());
202 }
203
204 #[test]
205 fn codec_bytes_differ() {
206 let p = sample();
207 let cbor = p.to_bytes(PayloadCodec::Cbor);
208 let proto = p.to_bytes(PayloadCodec::Protobuf);
209 let flat = p.to_bytes(PayloadCodec::FlatBuffers);
210 assert_ne!(cbor, proto);
211 assert_ne!(cbor, flat);
212 assert_ne!(proto, flat);
213 }
214}