Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./zerocopy/audio_frame.h"
25 : :
26 : : #include <cstdint>
27 : :
28 : : namespace vlink {
29 : :
30 : : namespace zerocopy {
31 : :
32 : : // AudioFrame
33 : 63 : AudioFrame::AudioFrame() noexcept {
34 : : #if defined(__arm__) || defined(__x86__) || defined(__i386__)
35 : : #ifndef __ANDROID__
36 : : #warning "[AudioFrame] No support for 32-bit architecture."
37 : : #endif
38 : : #else
39 : : static_assert(sizeof(AudioFrame) == 128, "Sizeof must be 128 bytes.");
40 : : #endif
41 : 63 : }
42 : :
43 : 65 : AudioFrame::~AudioFrame() noexcept {
44 [ + + + - : 65 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
45 : 30 : Bytes::bytes_free(data_, size_);
46 : : }
47 : 65 : }
48 : :
49 : 1 : AudioFrame::AudioFrame(const AudioFrame& target) noexcept { deep_copy(target); }
50 : :
51 : 1 : AudioFrame::AudioFrame(AudioFrame&& target) noexcept { move_copy(target); }
52 : :
53 : 1 : AudioFrame& AudioFrame::operator=(const AudioFrame& target) noexcept {
54 [ - + ]: 1 : if VUNLIKELY (this == &target) {
55 : 0 : return *this;
56 : : }
57 : :
58 : 1 : deep_copy(target);
59 : :
60 : 1 : return *this;
61 : : }
62 : :
63 : 1 : AudioFrame& AudioFrame::operator=(AudioFrame&& target) noexcept {
64 [ - + ]: 1 : if VUNLIKELY (this == &target) {
65 : 0 : return *this;
66 : : }
67 : :
68 : 1 : move_copy(target);
69 : :
70 : 1 : return *this;
71 : : }
72 : :
73 : 7 : bool AudioFrame::operator<<(const Bytes& bytes) noexcept {
74 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
75 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
76 : : // static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
77 : :
78 [ + + ]: 7 : if VUNLIKELY (bytes.empty()) {
79 : 1 : return false;
80 : : }
81 : :
82 [ + + ]: 6 : if VUNLIKELY (!check_valid(bytes)) {
83 : 2 : return false;
84 : : }
85 : :
86 : 4 : uint32_t wire_version = 0;
87 : 4 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
88 : :
89 [ - + ]: 4 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
90 : 0 : return false;
91 : : }
92 : :
93 [ + + + - : 4 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
94 : 1 : Bytes::bytes_free(data_, size_);
95 : : }
96 : :
97 : : #if defined(__GNUC__) && !defined(__clang__)
98 : : #pragma GCC diagnostic push
99 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
100 : : #if __GNUC__ >= 11
101 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
102 : : #endif
103 : : #endif
104 : :
105 : 4 : auto* target_ptr = reinterpret_cast<uint8_t*>(this);
106 : :
107 : 4 : std::memcpy(target_ptr, bytes.data() + kMagicNumberBeginSize + kVersionSize, sizeof(AudioFrame));
108 : :
109 : : #if defined(__GNUC__) && !defined(__clang__)
110 : : #pragma GCC diagnostic pop
111 : : #endif
112 : :
113 : 4 : data_ = const_cast<uint8_t*>(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(AudioFrame));
114 : 4 : is_owner_ = false;
115 : :
116 [ + + ]: 4 : if VUNLIKELY (bytes.size() != get_serialized_size()) {
117 : 1 : clear();
118 : 1 : return false;
119 : : }
120 : :
121 : 3 : return true;
122 : : }
123 : :
124 : 7 : bool AudioFrame::operator>>(Bytes& bytes) const noexcept {
125 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
126 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
127 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
128 : :
129 [ + + - + : 7 : if (bytes.empty() || bytes.size() != get_serialized_size()) {
+ + ]
130 : 6 : bytes = Bytes::create(get_serialized_size());
131 : : }
132 : :
133 : 7 : std::memcpy(bytes.data(), &kMagicNumberBegin, kMagicNumberBeginSize);
134 : :
135 : 7 : std::memcpy(bytes.data() + kMagicNumberBeginSize, &kWireVersion, kVersionSize);
136 : :
137 : : // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
138 : 7 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize, this, sizeof(AudioFrame));
139 : :
140 [ + + + - : 7 : if VLIKELY (data_ != nullptr && size_ != 0) {
+ + ]
141 : 6 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(AudioFrame), data_, size_);
142 : : }
143 : :
144 : 7 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(AudioFrame) + size_, &kMagicNumberEnd,
145 : : kMagicNumberEndSize);
146 : :
147 : 7 : return true;
148 : : }
149 : :
150 : 13 : bool AudioFrame::check_valid(const Bytes& bytes) noexcept {
151 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
152 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
153 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
154 : :
155 [ + + ]: 13 : if VUNLIKELY (bytes.size() < kMagicNumberBeginSize + kVersionSize + sizeof(AudioFrame) + kMagicNumberEndSize) {
156 : 2 : return false;
157 : : }
158 : :
159 : 11 : uint32_t check_magic = 0;
160 : :
161 : 11 : std::memcpy(&check_magic, bytes.begin(), kMagicNumberBeginSize);
162 : :
163 [ + + ]: 11 : if VUNLIKELY (check_magic != kMagicNumberBegin) {
164 : 1 : return false;
165 : : }
166 : :
167 : 10 : uint32_t wire_version = 0;
168 : 10 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
169 : :
170 [ + + ]: 10 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
171 : 2 : return false;
172 : : }
173 : :
174 : 8 : std::memcpy(&check_magic, bytes.end() - kMagicNumberEndSize, kMagicNumberEndSize);
175 : :
176 [ + + ]: 8 : if VUNLIKELY (check_magic != kMagicNumberEnd) {
177 : 1 : return false;
178 : : }
179 : :
180 : 7 : return true;
181 : : }
182 : :
183 : 15 : size_t AudioFrame::get_serialized_size() const noexcept {
184 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
185 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
186 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
187 : :
188 : 15 : return kMagicNumberBeginSize + kVersionSize + sizeof(AudioFrame) + size_ + kMagicNumberEndSize;
189 : : }
190 : :
191 [ + + + - ]: 17 : bool AudioFrame::is_valid() const noexcept { return data_ != nullptr && size_ != 0; }
192 : :
193 : 9 : bool AudioFrame::shallow_copy(const AudioFrame& target) noexcept {
194 [ + + ]: 9 : if VUNLIKELY (this == &target) {
195 : 2 : return false;
196 : : }
197 : :
198 [ - + - - : 7 : if (is_owner_ && data_ && size_ != 0) {
- - ]
199 : 0 : Bytes::bytes_free(data_, size_);
200 : : }
201 : :
202 : 7 : header = target.header;
203 : :
204 : 7 : update_time_ns_ = target.update_time_ns_;
205 : 7 : duration_ns_ = target.duration_ns_;
206 : 7 : std::memcpy(codec_, target.codec_, sizeof(codec_));
207 : 7 : std::memcpy(language_, target.language_, sizeof(language_));
208 : 7 : channel_ = target.channel_;
209 : 7 : freq_ = target.freq_;
210 : 7 : sample_rate_ = target.sample_rate_;
211 : 7 : num_samples_ = target.num_samples_;
212 : 7 : bitrate_ = target.bitrate_;
213 : 7 : num_channels_ = target.num_channels_;
214 : 7 : bit_depth_ = target.bit_depth_;
215 : 7 : format_ = target.format_;
216 : 7 : layout_ = target.layout_;
217 : 7 : reserved_buf_ = target.reserved_buf_;
218 : 7 : reserved_buf2_ = target.reserved_buf2_;
219 : 7 : is_owner_ = false;
220 : 7 : data_ = target.data_;
221 : 7 : size_ = target.size_;
222 : :
223 : 7 : return true;
224 : : }
225 : :
226 : 5 : bool AudioFrame::deep_copy(const AudioFrame& target) noexcept {
227 [ + + + - : 5 : if VLIKELY (data_ && is_owner_ && target.data_ && size_ != 0 && size_ == target.size_) {
+ + + - +
+ + - + +
+ - + + ]
228 [ + + ]: 2 : if VUNLIKELY (this == &target) {
229 : 1 : return false;
230 : : }
231 : :
232 : 1 : header = target.header;
233 : :
234 : 1 : update_time_ns_ = target.update_time_ns_;
235 : 1 : duration_ns_ = target.duration_ns_;
236 : 1 : std::memcpy(codec_, target.codec_, sizeof(codec_));
237 : 1 : std::memcpy(language_, target.language_, sizeof(language_));
238 : 1 : channel_ = target.channel_;
239 : 1 : freq_ = target.freq_;
240 : 1 : sample_rate_ = target.sample_rate_;
241 : 1 : num_samples_ = target.num_samples_;
242 : 1 : bitrate_ = target.bitrate_;
243 : 1 : num_channels_ = target.num_channels_;
244 : 1 : bit_depth_ = target.bit_depth_;
245 : 1 : format_ = target.format_;
246 : 1 : layout_ = target.layout_;
247 : 1 : reserved_buf_ = target.reserved_buf_;
248 : 1 : reserved_buf2_ = target.reserved_buf2_;
249 : :
250 : 1 : std::memcpy(data_, target.data_, size_);
251 : :
252 : 1 : return true;
253 : : }
254 : :
255 [ - + ]: 3 : if VUNLIKELY (!shallow_copy(target)) {
256 : 0 : return false;
257 : : }
258 : :
259 [ + - + - ]: 3 : if (data_ && size_ != 0) {
260 : 3 : data_ = Bytes::bytes_malloc(size_);
261 : :
262 : 3 : std::memcpy(data_, target.data_, size_);
263 : :
264 : 3 : is_owner_ = true;
265 : : }
266 : :
267 : 3 : return true;
268 : : }
269 : :
270 : 4 : bool AudioFrame::move_copy(AudioFrame& target) noexcept {
271 [ + + ]: 4 : if VUNLIKELY (!shallow_copy(target)) {
272 : 1 : return false;
273 : : }
274 : :
275 : 3 : is_owner_ = target.is_owner_;
276 : :
277 : 3 : target.update_time_ns_ = 0;
278 : 3 : target.duration_ns_ = 0;
279 : 3 : std::memset(target.codec_, 0, sizeof(target.codec_));
280 : 3 : std::memset(target.language_, 0, sizeof(target.language_));
281 : 3 : target.channel_ = 0;
282 : 3 : target.freq_ = 0;
283 : 3 : target.sample_rate_ = 0;
284 : 3 : target.num_samples_ = 0;
285 : 3 : target.bitrate_ = 0;
286 : 3 : target.num_channels_ = 0;
287 : 3 : target.bit_depth_ = 0;
288 : 3 : target.format_ = kFormatUnknown;
289 : 3 : target.layout_ = kLayoutUnknown;
290 : 3 : target.reserved_buf_ = 0;
291 : 3 : target.reserved_buf2_ = 0;
292 : 3 : target.is_owner_ = false;
293 : 3 : target.data_ = nullptr;
294 : 3 : target.size_ = 0;
295 : :
296 : : #if defined(__GNUC__) && !defined(__clang__)
297 : : #pragma GCC diagnostic push
298 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
299 : : #if __GNUC__ >= 11
300 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
301 : : #endif
302 : : #endif
303 : :
304 : 3 : std::memset(&target.header, 0, sizeof(header));
305 : :
306 : : #if defined(__GNUC__) && !defined(__clang__)
307 : : #pragma GCC diagnostic pop
308 : : #endif
309 : :
310 : 3 : return true;
311 : : }
312 : :
313 : 35 : bool AudioFrame::create(size_t _size) noexcept {
314 [ + + ]: 35 : if VUNLIKELY (_size == 0) {
315 : 1 : return false;
316 : : }
317 : :
318 [ + + + - : 34 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
319 : 2 : Bytes::bytes_free(data_, size_);
320 : : }
321 : :
322 : 34 : size_ = _size;
323 : :
324 : 34 : data_ = Bytes::bytes_malloc(size_);
325 : :
326 : 34 : is_owner_ = true;
327 : :
328 : 34 : return true;
329 : : }
330 : :
331 : 5 : void AudioFrame::clear() noexcept {
332 [ + + + - : 5 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
333 : 4 : Bytes::bytes_free(data_, size_);
334 : : }
335 : :
336 : 5 : update_time_ns_ = 0;
337 : 5 : duration_ns_ = 0;
338 : 5 : std::memset(codec_, 0, sizeof(codec_));
339 : 5 : std::memset(language_, 0, sizeof(language_));
340 : 5 : channel_ = 0;
341 : 5 : freq_ = 0;
342 : 5 : sample_rate_ = 0;
343 : 5 : num_samples_ = 0;
344 : 5 : bitrate_ = 0;
345 : 5 : num_channels_ = 0;
346 : 5 : bit_depth_ = 0;
347 : 5 : format_ = kFormatUnknown;
348 : 5 : layout_ = kLayoutUnknown;
349 : 5 : is_owner_ = false;
350 : 5 : data_ = nullptr;
351 : 5 : size_ = 0;
352 : :
353 : : #if defined(__GNUC__) && !defined(__clang__)
354 : : #pragma GCC diagnostic push
355 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
356 : : #if __GNUC__ >= 11
357 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
358 : : #endif
359 : : #endif
360 : :
361 : 5 : std::memset(&header, 0, sizeof(header));
362 : :
363 : : #if defined(__GNUC__) && !defined(__clang__)
364 : : #pragma GCC diagnostic pop
365 : : #endif
366 : 5 : }
367 : :
368 : 5 : bool AudioFrame::shallow_copy(uint8_t* data, size_t size) noexcept {
369 [ + + + + : 5 : if VUNLIKELY (!data || size == 0) {
+ + ]
370 : 2 : return false;
371 : : }
372 : :
373 [ + + ]: 3 : if VUNLIKELY (data_ == data) {
374 : 1 : return false;
375 : : }
376 : :
377 [ - + - - : 2 : if (is_owner_ && data_ && size_ != 0) {
- - ]
378 : 0 : Bytes::bytes_free(data_, size_);
379 : : }
380 : :
381 : 2 : is_owner_ = false;
382 : :
383 : 2 : data_ = data;
384 : 2 : size_ = size;
385 : :
386 : 2 : return true;
387 : : }
388 : :
389 : 6 : bool AudioFrame::deep_copy(uint8_t* data, size_t size) noexcept {
390 [ + + + + : 6 : if VUNLIKELY (!data || size == 0) {
+ + ]
391 : 2 : return false;
392 : : }
393 : :
394 [ + + ]: 4 : if (is_owner_) {
395 [ - + ]: 2 : if VUNLIKELY (!data_) {
396 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
397 : : }
398 : :
399 [ + + ]: 2 : if VUNLIKELY (data_ == data) {
400 : 1 : return false;
401 : : }
402 : :
403 [ + - ]: 1 : if VUNLIKELY (size_ != size) {
404 : 1 : create(size);
405 : : }
406 : : } else {
407 : 2 : create(size);
408 : : }
409 : :
410 : 3 : std::memcpy(data_, data, size);
411 : :
412 : 3 : return true;
413 : : }
414 : :
415 : 1 : bool AudioFrame::fill_data(uint8_t* data, size_t size) noexcept { return deep_copy(data, size); }
416 : :
417 : 3 : uint64_t AudioFrame::update_time_ns() const noexcept { return update_time_ns_; }
418 : :
419 : 4 : uint64_t AudioFrame::duration_ns() const noexcept { return duration_ns_; }
420 : :
421 : 9 : std::string_view AudioFrame::codec() const noexcept { return {codec_, ::strnlen(codec_, sizeof(codec_))}; }
422 : :
423 : 9 : std::string_view AudioFrame::language() const noexcept { return {language_, ::strnlen(language_, sizeof(language_))}; }
424 : :
425 : 3 : uint32_t AudioFrame::channel() const noexcept { return channel_; }
426 : :
427 : 3 : uint32_t AudioFrame::freq() const noexcept { return freq_; }
428 : :
429 : 11 : uint32_t AudioFrame::sample_rate() const noexcept { return sample_rate_; }
430 : :
431 : 4 : uint32_t AudioFrame::num_samples() const noexcept { return num_samples_; }
432 : :
433 : 3 : uint32_t AudioFrame::bitrate() const noexcept { return bitrate_; }
434 : :
435 : 8 : uint16_t AudioFrame::num_channels() const noexcept { return num_channels_; }
436 : :
437 : 5 : uint16_t AudioFrame::bit_depth() const noexcept { return bit_depth_; }
438 : :
439 : 17 : AudioFrame::Format AudioFrame::format() const noexcept { return format_; }
440 : :
441 : 9 : AudioFrame::Layout AudioFrame::layout() const noexcept { return layout_; }
442 : :
443 : 37 : const uint8_t* AudioFrame::data() const noexcept { return data_; }
444 : :
445 : 27 : size_t AudioFrame::size() const noexcept { return size_; }
446 : :
447 : 22 : bool AudioFrame::is_owner() const noexcept { return is_owner_; }
448 : :
449 : 2 : void AudioFrame::set_update_time_ns(uint64_t update_time_ns) noexcept { update_time_ns_ = update_time_ns; }
450 : :
451 : 3 : void AudioFrame::set_duration_ns(uint64_t duration_ns) noexcept { duration_ns_ = duration_ns; }
452 : :
453 : 8 : void AudioFrame::set_codec(std::string_view codec) noexcept {
454 : 8 : std::memset(codec_, 0, sizeof(codec_));
455 : :
456 : 8 : size_t copy_size = codec.size();
457 : :
458 [ + + ]: 8 : if (copy_size >= sizeof(codec_)) {
459 : 1 : copy_size = sizeof(codec_) - 1;
460 : : }
461 : :
462 [ + + ]: 8 : if VLIKELY (copy_size != 0) {
463 : 7 : std::memcpy(codec_, codec.data(), copy_size);
464 : : }
465 : 8 : }
466 : :
467 : 8 : void AudioFrame::set_language(std::string_view language) noexcept {
468 : 8 : std::memset(language_, 0, sizeof(language_));
469 : :
470 : 8 : size_t copy_size = language.size();
471 : :
472 [ + + ]: 8 : if (copy_size >= sizeof(language_)) {
473 : 1 : copy_size = sizeof(language_) - 1;
474 : : }
475 : :
476 [ + + ]: 8 : if VLIKELY (copy_size != 0) {
477 : 7 : std::memcpy(language_, language.data(), copy_size);
478 : : }
479 : 8 : }
480 : :
481 : 2 : void AudioFrame::set_channel(uint32_t channel) noexcept { channel_ = channel; }
482 : :
483 : 2 : void AudioFrame::set_freq(uint32_t freq) noexcept { freq_ = freq; }
484 : :
485 : 8 : void AudioFrame::set_sample_rate(uint32_t sample_rate) noexcept { sample_rate_ = sample_rate; }
486 : :
487 : 3 : void AudioFrame::set_num_samples(uint32_t num_samples) noexcept { num_samples_ = num_samples; }
488 : :
489 : 2 : void AudioFrame::set_bitrate(uint32_t bitrate) noexcept { bitrate_ = bitrate; }
490 : :
491 : 7 : void AudioFrame::set_num_channels(uint16_t num_channels) noexcept { num_channels_ = num_channels; }
492 : :
493 : 4 : void AudioFrame::set_bit_depth(uint16_t bit_depth) noexcept { bit_depth_ = bit_depth; }
494 : :
495 : 17 : void AudioFrame::set_format(Format format) noexcept { format_ = format; }
496 : :
497 : 7 : void AudioFrame::set_layout(Layout layout) noexcept { layout_ = layout; }
498 : :
499 : : } // namespace zerocopy
500 : :
501 : : } // namespace vlink
|