forked from thesofproject/sof
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio_stream.h
More file actions
1039 lines (908 loc) · 31.8 KB
/
audio_stream.h
File metadata and controls
1039 lines (908 loc) · 31.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright(c) 2023 Intel Corporation. All rights reserved.
*
* Author: Karol Trzcinski <karolx.trzcinski@linux.intel.com>
*/
/**
* \file include/sof/audio/audio_stream.h
* \brief Audio Stream API definition
* \author Karol Trzcinski <karolx.trzcinski@linux.intel.com>
*/
#ifndef __SOF_AUDIO_AUDIO_STREAM_H__
#define __SOF_AUDIO_AUDIO_STREAM_H__
#include <sof/audio/format.h>
#include <sof/audio/sink_api.h>
#include <sof/audio/source_api.h>
#include <sof/compiler_attributes.h>
#include <rtos/panic.h>
#include <sof/math/numbers.h>
#include <rtos/alloc.h>
#include <rtos/cache.h>
#include <ipc/stream.h>
#include <ipc4/base-config.h>
#include <module/audio/audio_stream.h>
#include <stdbool.h>
#include <stdint.h>
/** \addtogroup audio_stream_api Audio Stream API
* @{
*/
/**
* Audio stream is a circular buffer aware of audio format of the data
* in the buffer so provides API for reading and writing not only bytes,
* but also samples and frames.
*
* Audio stream does not perform any memory allocations. A client (a component
* buffer or dma) must allocate the memory for the underlying data buffer and
* provide it to the initialization routine.
*
* Once the client is done with reading/writing the data, it must commit the
* consumption/production and update the buffer state by calling
* audio_stream_consume()/audio_stream_produce() (just a single call following
* series of reads/writes).
*
* Audio stream implements pipeline2.0 sink and source API
*/
struct audio_stream {
struct sof_source source_api; /**< source API, don't modify, use helper functions only */
struct sof_sink sink_api; /**< sink API, don't modify, use helper functions only */
/* runtime data */
uint32_t size; /**< Runtime buffer size in bytes (period multiple) */
uint32_t avail; /**< Available bytes for reading */
uint32_t free; /**< Free bytes for writing */
void *w_ptr; /**< Buffer write pointer */
void *r_ptr; /**< Buffer read position */
void *addr; /**< Buffer base address */
void *end_addr; /**< Buffer end address */
/* runtime stream params */
struct sof_audio_stream_params runtime_stream_params;
};
static inline void *audio_stream_get_rptr(const struct audio_stream *buf)
{
return buf->r_ptr;
}
static inline void *audio_stream_get_wptr(const struct audio_stream *buf)
{
return buf->w_ptr;
}
static inline void *audio_stream_get_end_addr(const struct audio_stream *buf)
{
return buf->end_addr;
}
static inline void *audio_stream_get_addr(const struct audio_stream *buf)
{
return buf->addr;
}
static inline uint32_t audio_stream_get_size(const struct audio_stream *buf)
{
return buf->size;
}
static inline uint32_t audio_stream_get_avail(const struct audio_stream *buf)
{
return buf->avail;
}
static inline uint32_t audio_stream_get_free(const struct audio_stream *buf)
{
return buf->free;
}
static inline enum sof_ipc_frame audio_stream_get_frm_fmt(const struct audio_stream *buf)
{
return buf->runtime_stream_params.frame_fmt;
}
static inline enum sof_ipc_frame audio_stream_get_valid_fmt(const struct audio_stream *buf)
{
return buf->runtime_stream_params.valid_sample_fmt;
}
static inline uint32_t audio_stream_get_rate(const struct audio_stream *buf)
{
return buf->runtime_stream_params.rate;
}
static inline uint32_t audio_stream_get_channels(const struct audio_stream *buf)
{
return buf->runtime_stream_params.channels;
}
static inline bool audio_stream_get_underrun(const struct audio_stream *buf)
{
return buf->runtime_stream_params.underrun_permitted;
}
static inline uint32_t audio_stream_get_buffer_fmt(const struct audio_stream *buf)
{
return buf->runtime_stream_params.buffer_fmt;
}
static inline bool audio_stream_get_overrun(const struct audio_stream *buf)
{
return buf->runtime_stream_params.overrun_permitted;
}
static inline void audio_stream_set_rptr(struct audio_stream *buf, void *val)
{
buf->r_ptr = val;
}
static inline void audio_stream_set_wptr(struct audio_stream *buf, void *val)
{
buf->w_ptr = val;
}
static inline void audio_stream_set_end_addr(struct audio_stream *buf, void *val)
{
buf->end_addr = val;
}
static inline void audio_stream_set_addr(struct audio_stream *buf, void *val)
{
buf->addr = val;
}
static inline void audio_stream_set_size(struct audio_stream *buf, uint32_t val)
{
buf->size = val;
}
static inline void audio_stream_set_avail(struct audio_stream *buf, uint32_t val)
{
buf->avail = val;
}
static inline void audio_stream_set_free(struct audio_stream *buf, uint32_t val)
{
buf->free = val;
}
static inline void audio_stream_set_frm_fmt(struct audio_stream *buf,
enum sof_ipc_frame val)
{
buf->runtime_stream_params.frame_fmt = val;
}
static inline void audio_stream_set_valid_fmt(struct audio_stream *buf,
enum sof_ipc_frame val)
{
buf->runtime_stream_params.valid_sample_fmt = val;
}
static inline void audio_stream_set_rate(struct audio_stream *buf, uint32_t val)
{
buf->runtime_stream_params.rate = val;
}
static inline void audio_stream_set_channels(struct audio_stream *buf, uint16_t val)
{
buf->runtime_stream_params.channels = val;
}
static inline void audio_stream_set_underrun(struct audio_stream *buf,
bool underrun_permitted)
{
buf->runtime_stream_params.underrun_permitted = underrun_permitted;
}
static inline void audio_stream_set_overrun(struct audio_stream *buf,
bool overrun_permitted)
{
buf->runtime_stream_params.overrun_permitted = overrun_permitted;
}
static inline void audio_stream_set_buffer_fmt(struct audio_stream *buf,
uint32_t buffer_fmt)
{
buf->runtime_stream_params.buffer_fmt = buffer_fmt;
}
/**
* Retrieves readable address of a sample at specified index (see versions of
* this macro specialized for various sample types).
* @param buffer Buffer.
* @param idx Index of sample.
* @param size Size of sample in bytes.
* @return Pointer to the sample.
*
* Once the consumer finishes reading samples from the buffer, it should
* "commit" the operation and update the buffer state by calling
* audio_stream_consume().
*
* @note Components should call comp_update_buffer_consume().
*
* @see audio_stream_get_frag().
* @see audio_stream_consume().
* @see comp_update_buffer_consume().
*/
#define audio_stream_read_frag(buffer, idx, size) \
audio_stream_get_frag(buffer, (buffer)->r_ptr, idx, size)
/**
* Retrieves readable address of a signed 16-bit sample at specified index.
* @param buffer Buffer.
* @param idx Index of sample.
* @return Pointer to the sample.
*
* @see audio_stream_get_frag().
*/
#define audio_stream_read_frag_s16(buffer, idx) \
audio_stream_get_frag(buffer, (buffer)->r_ptr, idx, sizeof(int16_t))
/**
* Retrieves readable address of a signed 32-bit sample at specified index.
* @param buffer Buffer.
* @param idx Index of sample.
* @return Pointer to the sample.
*
* @see audio_stream_get_frag().
*/
#define audio_stream_read_frag_s32(buffer, idx) \
audio_stream_get_frag(buffer, (buffer)->r_ptr, idx, sizeof(int32_t))
/**
* Retrieves writeable address of a sample at specified index (see versions of
* this macro specialized for various sample types).
* @param buffer Buffer.
* @param idx Index of sample.
* @param size Size of sample in bytes.
* @return Pointer to the space for sample.
*
* Once the producer finishes writing samples to the buffer, it should
* "commit" the operation and update the buffer state by calling
* audio_stream_produce().
*
* @note Components should call comp_update_buffer_produce().
*
* @see audio_stream_get_frag().
* @see audio_stream_produce().
* @see comp_update_buffer_produce().
*/
#define audio_stream_write_frag(buffer, idx, size) \
audio_stream_get_frag(buffer, (buffer)->w_ptr, idx, size)
/**
* Retrieves writeable address of a signed 16-bit sample at specified index.
* @param buffer Buffer.
* @param idx Index of sample.
* @return Pointer to the space for sample.
*
* @see audio_stream_get_frag().
*/
#define audio_stream_write_frag_s16(buffer, idx) \
audio_stream_get_frag(buffer, (buffer)->w_ptr, idx, sizeof(int16_t))
/**
* Retrieves writeable address of a signed 32-bit sample at specified index.
* @param buffer Buffer.
* @param idx Index of sample.
* @return Pointer to the space for sample.
*
* @see audio_stream_get_frag().
*/
#define audio_stream_write_frag_s32(buffer, idx) \
audio_stream_get_frag(buffer, (buffer)->w_ptr, idx, sizeof(int32_t))
/**
* Retrieves address of sample (space for sample) at specified index within
* the buffer. Index is interpreted as an offset relative to the specified
* pointer, rollover is ensured.
* @param buffer Circular buffer.
* @param ptr Pointer to start from, it may be either read or write pointer.
* @param idx Index of the sample.
* @param sample_size Size of the sample in bytes.
* @return Pointer to the sample.
*/
#define audio_stream_get_frag(buffer, ptr, idx, sample_size) \
audio_stream_wrap(buffer, (char *)(ptr) + ((idx) * (sample_size)))
/**
* Calculates period size in bytes based on component stream's parameters.
* @param buf Component buffer.
* @return Period size in bytes.
*/
static inline uint32_t audio_stream_frame_bytes(const struct audio_stream *buf)
{
return get_frame_bytes(buf->runtime_stream_params.frame_fmt,
buf->runtime_stream_params.channels);
}
/**
* Calculates sample size in bytes based on component stream's parameters.
* @param buf Component buffer.
* @return Size of sample in bytes.
*/
static inline uint32_t audio_stream_sample_bytes(const struct audio_stream *buf)
{
return get_sample_bytes(buf->runtime_stream_params.frame_fmt);
}
/**
* Return the frames that meet the align requirement of both byte_align and
* frame_align_req.
* @param byte_align Processing byte alignment requirement.
* @param frame_align_req Processing frames alignment requirement.
* @param frame_size Size of the frame in bytes.
* @return frame number.
*/
static inline uint32_t audio_stream_frame_align_get(const uint32_t byte_align,
const uint32_t frame_align_req,
uint32_t frame_size)
{
/* Figure out how many frames are needed to meet the byte_align alignment requirements */
uint32_t frame_num = byte_align / gcd(byte_align, frame_size);
/** return the lcm of frame_num and frame_align_req*/
return frame_align_req * frame_num / gcd(frame_num, frame_align_req);
}
/**
* Set align_shift_idx and align_frame_cnt of stream according to byte_align and
* frame_align_req alignment requirement. Once the channel number,frame size
* are determined,the align_frame_cnt and align_shift_idx are determined too.
* these two feature will be used in audio_stream_get_avail_frames_aligned
* to calculate the available frames. it should be called in component prepare
* or param functions only once before stream copy. if someone forgets to call
* this first, there would be unexampled error such as nothing is copied at all.
* @param byte_align Processing byte alignment requirement.
* @param frame_align_req Processing frames alignment requirement.
* @param stream Sink or source stream structure which to be set.
*/
static inline void audio_stream_init_alignment_constants(const uint32_t byte_align,
const uint32_t frame_align_req,
struct audio_stream *stream)
{
uint32_t process_size;
uint32_t frame_size = audio_stream_frame_bytes(stream);
stream->runtime_stream_params.align_frame_cnt =
audio_stream_frame_align_get(byte_align, frame_align_req, frame_size);
process_size = stream->runtime_stream_params.align_frame_cnt * frame_size;
stream->runtime_stream_params.align_shift_idx =
(is_power_of_2(process_size) ? 31 : 32) - clz(process_size);
}
/**
* Applies parameters to the buffer.
* @param buffer Audio stream buffer.
* @param params Parameters (frame format, rate, number of channels).
* @return 0 if succeeded, error code otherwise.
*/
static inline int audio_stream_set_params(struct audio_stream *buffer,
struct sof_ipc_stream_params *params)
{
if (!params)
return -EINVAL;
buffer->runtime_stream_params.frame_fmt = params->frame_fmt;
buffer->runtime_stream_params.rate = params->rate;
buffer->runtime_stream_params.channels = params->channels;
/* set the default alignment info.
* set byte_align as 1 means no alignment limit on byte.
* set frame_align as 1 means no alignment limit on frame.
*/
audio_stream_init_alignment_constants(1, 1, buffer);
return 0;
}
/**
* Calculates period size in bytes based on component stream's parameters.
* @param buf Component buffer.
* @param frames Number of processing frames.
* @return Period size in bytes.
*/
static inline uint32_t audio_stream_period_bytes(const struct audio_stream *buf, uint32_t frames)
{
return frames * audio_stream_frame_bytes(buf);
}
/**
* Verifies the pointer and performs rollover when reached the end of
* the buffer.
* @param buffer Buffer accessed by the pointer.
* @param ptr Pointer
* @return Pointer, adjusted if necessary.
*/
static inline void *audio_stream_wrap(const struct audio_stream *buffer, void *ptr)
{
if (ptr >= buffer->end_addr)
ptr = (char *)buffer->addr +
((char *)ptr - (char *)buffer->end_addr);
assert((intptr_t)ptr <= (intptr_t)buffer->end_addr);
return ptr;
}
/**
* Verifies the pointer and performs rollover when reached the end of
* the circular buffer.
* @param ptr Pointer
* @param buf_addr Start address of the circular buffer.
* @param buf_end End address of the circular buffer.
* @return Pointer, adjusted if necessary.
*/
static inline void *cir_buf_wrap(void *ptr, void *buf_addr, void *buf_end)
{
if (ptr >= buf_end)
ptr = (char *)buf_addr +
((char *)ptr - (char *)buf_end);
assert((intptr_t)ptr <= (intptr_t)buf_end);
return ptr;
}
/**
* Verifies the pointer and performs rollover when reached the end of
* the buffer.
* @param buffer Buffer accessed by the pointer.
* @param ptr Pointer
* @return Pointer, adjusted if necessary.
*/
static inline void *audio_stream_rewind_wrap(const struct audio_stream *buffer, void *ptr)
{
if (ptr < buffer->addr)
ptr = (char *)buffer->end_addr - ((char *)buffer->addr - (char *)ptr);
assert((intptr_t)ptr >= (intptr_t)buffer->addr);
return ptr;
}
/**
* Calculates available data in bytes, handling underrun_permitted behaviour
* @param stream Stream pointer
* @return amount of data available for processing in bytes
*/
static inline uint32_t
audio_stream_get_avail_bytes(const struct audio_stream *stream)
{
/*
* In case of underrun-permitted stream, report buffer full instead of
* empty. This way, any data present in such stream is processed at
* regular pace, but buffer will never be seen as completely empty by
* clients, and in turn will not cause underrun/XRUN.
*/
if (stream->runtime_stream_params.underrun_permitted)
return stream->avail != 0 ? stream->avail : stream->size;
return stream->avail;
}
/**
* Calculates available data in samples, handling underrun_permitted behaviour
* @param stream Stream pointer
* @return amount of data available for processing in samples
*/
static inline uint32_t
audio_stream_get_avail_samples(const struct audio_stream *stream)
{
return audio_stream_get_avail_bytes(stream) /
audio_stream_sample_bytes(stream);
}
/**
* Calculates available data in frames, handling underrun_permitted behaviour
* @param stream Stream pointer
* @return amount of data available for processing in frames
*/
static inline uint32_t
audio_stream_get_avail_frames(const struct audio_stream *stream)
{
return audio_stream_get_avail_bytes(stream) /
audio_stream_frame_bytes(stream);
}
/**
* Calculates free space in bytes, handling overrun_permitted behaviour
* @param stream Stream pointer
* @return amount of space free in bytes
*/
static inline uint32_t
audio_stream_get_free_bytes(const struct audio_stream *stream)
{
/*
* In case of overrun-permitted stream, report buffer empty instead of
* full. This way, if there's any actual free space for data it is
* processed at regular pace, but buffer will never be seen as
* completely full by clients, and in turn will not cause overrun/XRUN.
*/
if (stream->runtime_stream_params.overrun_permitted)
return stream->free != 0 ? stream->free : stream->size;
return stream->free;
}
/**
* Calculates free space in samples, handling overrun_permitted behaviour
* @param stream Stream pointer
* @return amount of space free in samples
*/
static inline uint32_t
audio_stream_get_free_samples(const struct audio_stream *stream)
{
return audio_stream_get_free_bytes(stream) /
audio_stream_sample_bytes(stream);
}
/**
* Calculates free space in frames, handling overrun_permitted behaviour
* @param stream Stream pointer
* @return amount of space free in frames
*/
static inline uint32_t
audio_stream_get_free_frames(const struct audio_stream *stream)
{
return audio_stream_get_free_bytes(stream) /
audio_stream_frame_bytes(stream);
}
/**
* Verifies whether specified number of bytes can be copied from source buffer
* to sink buffer.
* @param source Source buffer.
* @param sink Sink buffer.
* @param bytes Number of bytes to copy.
* @return 0 if there is enough data in source and enough free space in sink.
* @return 1 if there is not enough free space in sink.
* @return -1 if there is not enough data in source.
*/
static inline int audio_stream_can_copy_bytes(const struct audio_stream *source,
const struct audio_stream *sink,
uint32_t bytes)
{
/* check for underrun */
if (audio_stream_get_avail_bytes(source) < bytes)
return -1;
/* check for overrun */
if (audio_stream_get_free_bytes(sink) < bytes)
return 1;
/* we are good to copy */
return 0;
}
/**
* Computes maximum number of bytes that can be copied from source buffer to
* sink buffer, verifying number of bytes available in source vs. free space
* available in sink.
* @param source Source buffer.
* @param sink Sink buffer.
* @return Number of bytes.
*/
static inline uint32_t
audio_stream_get_copy_bytes(const struct audio_stream *source,
const struct audio_stream *sink)
{
uint32_t avail = audio_stream_get_avail_bytes(source);
uint32_t free = audio_stream_get_free_bytes(sink);
if (avail > free)
return free;
else
return avail;
}
/**
* Computes maximum number of frames that can be copied from source buffer
* to sink buffer, verifying number of available source frames vs. free
* space available in sink.
* @param source Source buffer.
* @param sink Sink buffer.
* @return Number of frames.
*/
static inline uint32_t
audio_stream_avail_frames(const struct audio_stream *source,
const struct audio_stream *sink)
{
uint32_t src_frames = audio_stream_get_avail_frames(source);
uint32_t sink_frames = audio_stream_get_free_frames(sink);
return MIN(src_frames, sink_frames);
}
/**
* Computes maximum number of frames aligned that can be copied from
* source buffer to sink buffer, verifying number of available source
* frames vs. free space available in sink.
* @param source Buffer of source.
* @param sink Buffer of sink.
* @return Number of frames.
*/
static inline uint32_t
audio_stream_avail_frames_aligned(const struct audio_stream *source,
const struct audio_stream *sink)
{
uint32_t src_frames = (audio_stream_get_avail_bytes(source) >>
source->runtime_stream_params.align_shift_idx) *
source->runtime_stream_params.align_frame_cnt;
uint32_t sink_frames = (audio_stream_get_free_bytes(sink) >>
sink->runtime_stream_params.align_shift_idx) *
sink->runtime_stream_params.align_frame_cnt;
return MIN(src_frames, sink_frames);
}
/**
* Updates the buffer state after writing to the buffer.
* @param buffer Buffer to update.
* @param bytes Number of written bytes.
*/
static inline void audio_stream_produce(struct audio_stream *buffer, uint32_t bytes)
{
buffer->w_ptr = audio_stream_wrap(buffer,
(char *)buffer->w_ptr + bytes);
/* "overwrite" old data in circular wrap case */
if (bytes > audio_stream_get_free_bytes(buffer))
buffer->r_ptr = buffer->w_ptr;
/* calculate available bytes */
if (buffer->r_ptr < buffer->w_ptr)
buffer->avail = (char *)buffer->w_ptr - (char *)buffer->r_ptr;
else if (buffer->r_ptr == buffer->w_ptr)
buffer->avail = buffer->size; /* full */
else
buffer->avail = buffer->size -
((char *)buffer->r_ptr - (char *)buffer->w_ptr);
/* calculate free bytes */
buffer->free = buffer->size - buffer->avail;
}
/**
* Updates the buffer state after reading from the buffer.
* @param buffer Buffer to update.
* @param bytes Number of read bytes.
*/
static inline void audio_stream_consume(struct audio_stream *buffer, uint32_t bytes)
{
buffer->r_ptr = audio_stream_wrap(buffer,
(char *)buffer->r_ptr + bytes);
/* calculate available bytes */
if (buffer->r_ptr < buffer->w_ptr)
buffer->avail = (char *)buffer->w_ptr - (char *)buffer->r_ptr;
else if (buffer->r_ptr == buffer->w_ptr)
buffer->avail = 0; /* empty */
else
buffer->avail = buffer->size -
((char *)buffer->r_ptr - (char *)buffer->w_ptr);
/* calculate free bytes */
buffer->free = buffer->size - buffer->avail;
}
/**
* Resets the buffer.
* @param buffer Buffer to reset.
*/
static inline void audio_stream_reset(struct audio_stream *buffer)
{
/* reset read and write pointer to buffer bas */
buffer->w_ptr = buffer->addr;
buffer->r_ptr = buffer->addr;
/* free space is buffer size */
buffer->free = buffer->size;
/* there are no avail samples at reset */
buffer->avail = 0;
}
/**
* Initializes the buffer with specified memory block and size.
* @param audio_stream the audio_stream a to initialize.
* @param buff_addr Address of the memory block to assign.
* @param size Size of the memory block in bytes.
*/
void audio_stream_init(struct audio_stream *audio_stream, void *buff_addr, uint32_t size);
/**
* Invalidates (in DSP d-cache) the buffer in range [r_ptr, r_ptr+bytes],
* with rollover if necessary.
* @param buffer Buffer.
* @param bytes Size of the fragment to invalidate.
*/
static inline void audio_stream_invalidate(struct audio_stream *buffer, uint32_t bytes)
{
uint32_t head_size = bytes;
uint32_t tail_size = 0;
/* check for potential wrap */
if ((char *)buffer->r_ptr + bytes > (char *)buffer->end_addr) {
head_size = (char *)buffer->end_addr - (char *)buffer->r_ptr;
tail_size = bytes - head_size;
}
dcache_invalidate_region((__sparse_force void __sparse_cache *)buffer->r_ptr, head_size);
if (tail_size)
dcache_invalidate_region((__sparse_force void __sparse_cache *)buffer->addr,
tail_size);
}
/**
* Writes back (from DSP d-cache) the buffer in range [w_ptr, w_ptr+bytes],
* with rollover if necessary.
* @param buffer Buffer.
* @param bytes Size of the fragment to write back.
*/
static inline void audio_stream_writeback(struct audio_stream *buffer, uint32_t bytes)
{
uint32_t head_size = bytes;
uint32_t tail_size = 0;
/* check for potential wrap */
if ((char *)buffer->w_ptr + bytes > (char *)buffer->end_addr) {
head_size = (char *)buffer->end_addr - (char *)buffer->w_ptr;
tail_size = bytes - head_size;
}
dcache_writeback_region((__sparse_force void __sparse_cache *)buffer->w_ptr, head_size);
if (tail_size)
dcache_writeback_region((__sparse_force void __sparse_cache *)buffer->addr,
tail_size);
}
/**
* @brief Calculates numbers of bytes to buffer wrap.
* @param source Stream to get information from.
* @param ptr Read or write pointer from source
* @return Number of data samples to buffer wrap.
*/
static inline int
audio_stream_bytes_without_wrap(const struct audio_stream *source, const void *ptr)
{
assert((intptr_t)source->end_addr >= (intptr_t)ptr);
return (intptr_t)source->end_addr - (intptr_t)ptr;
}
/**
* @brief Calculates numbers of bytes to buffer wrap when reading stream
* backwards from current sample pointed by ptr towards begin.
* @param source Stream to get information from.
* @param ptr Read or write pointer from source
* @return Number of bytes to buffer wrap. For number of samples calculate
* need to add size of sample to returned bytes count.
*/
static inline int
audio_stream_rewind_bytes_without_wrap(const struct audio_stream *source, const void *ptr)
{
assert((intptr_t)ptr >= (intptr_t)source->addr);
int to_begin = (intptr_t)ptr - (intptr_t)source->addr;
return to_begin;
}
/**
* @brief Calculate position of write pointer to the position before the data was copied
* to source buffer.
* @param source Stream to get information from.
* @param bytes Number of bytes copied to source buffer.
* @return Previous position of the write pointer.
*/
static inline uint32_t
*audio_stream_rewind_wptr_by_bytes(const struct audio_stream *source, const uint32_t bytes)
{
void *wptr = audio_stream_get_wptr(source);
int to_begin = audio_stream_rewind_bytes_without_wrap(source, wptr);
assert((intptr_t)wptr >= (intptr_t)source->addr);
assert((intptr_t)source->end_addr > (intptr_t)wptr);
if (to_begin > bytes)
return (uint32_t *)((intptr_t)wptr - bytes);
else
return (uint32_t *)((intptr_t)source->end_addr - (bytes - to_begin));
}
/**
* @brief Calculates numbers of s16 samples to buffer wrap when buffer
* is read forward towards end address.
* @param source Stream to get information from.
* @param ptr Read or write pointer from source
* @return Number of data s16 samples until circular wrap need at end
*/
static inline int
audio_stream_samples_without_wrap_s16(const struct audio_stream *source, const void *ptr)
{
int to_end = (int16_t *)source->end_addr - (int16_t *)ptr;
assert((intptr_t)source->end_addr >= (intptr_t)ptr);
return to_end;
}
/**
* @brief Calculates numbers of s24 samples to buffer wrap when buffer
* is read forward towards end address.
* @param source Stream to get information from.
* @param ptr Read or write pointer from source
* @return Number of data s24 samples until circular wrap need at end
*/
static inline int
audio_stream_samples_without_wrap_s24(const struct audio_stream *source, const void *ptr)
{
int to_end = (int32_t *)source->end_addr - (int32_t *)ptr;
assert((intptr_t)source->end_addr >= (intptr_t)ptr);
return to_end;
}
/**
* @brief Calculates numbers of s32 samples to buffer wrap when buffer
* is read forward towards end address.
* @param source Stream to get information from.
* @param ptr Read or write pointer from source
* @return Number of data s32 samples until circular wrap need at end
*/
static inline int
audio_stream_samples_without_wrap_s32(const struct audio_stream *source, const void *ptr)
{
int to_end = (int32_t *)source->end_addr - (int32_t *)ptr;
assert((intptr_t)source->end_addr >= (intptr_t)ptr);
return to_end;
}
/**
* @brief Calculates numbers of bytes to buffer wrap when reading stream
* backwards from current sample pointed by ptr towards begin.
* @param ptr Read or write pointer og circular buffer.
* @param buf_end End address of circular buffer.
* @return Number of bytes to buffer wrap. For number of samples calculate
* need to add size of sample to returned bytes count.
*/
static inline int cir_buf_bytes_without_wrap(void *ptr, void *buf_end)
{
assert((intptr_t)buf_end >= (intptr_t)ptr);
return (intptr_t)buf_end - (intptr_t)ptr;
}
/**
* @brief Calculates numbers of s32 samples to buffer wrap when reading stream
* backwards from current sample pointed by ptr towards begin.
* @param ptr Read or write pointer og circular buffer.
* @param buf_end End address of circular buffer.
* @return Number of bytes to buffer wrap. For number of samples calculate
* need to add size of sample to returned bytes count.
*/
static inline int cir_buf_samples_without_wrap_s32(void *ptr, void *buf_end)
{
int to_end = (int32_t *)buf_end - (int32_t *)ptr;
assert((intptr_t)buf_end >= (intptr_t)ptr);
return to_end;
}
/**
* @brief Calculates numbers of frames to buffer wrap and return
* minimum of calculated value.
* @param source Stream to get information from.
* @param ptr Read or write pointer from source
* @return Number of data frames to buffer wrap.
*/
static inline uint32_t
audio_stream_frames_without_wrap(const struct audio_stream *source, const void *ptr)
{
uint32_t bytes = audio_stream_bytes_without_wrap(source, ptr);
uint32_t frame_bytes = audio_stream_frame_bytes(source);
return bytes / frame_bytes;
}
/**
* Copies data from source buffer to sink buffer.
* @param source Source buffer.
* @param ioffset Offset (in samples) in source buffer to start reading from.
* @param sink Sink buffer.
* @param ooffset Offset (in samples) in sink buffer to start writing to.
* @param samples Number of samples to copy.
* @return number of processed samples.
*/
int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset,
struct audio_stream *sink, uint32_t ooffset, uint32_t samples);
/**
* Copies data from one circular buffer to another circular buffer.
* @param src Source pointer of source circular buffer.
* @param src_addr Start address of source circular buffer.
* @param src_end End address of source circular buffer.
* @param dst Sink pointer of source circular buffer.
* @param dst_addr Start address of sink circular buffer
* @param dst_end End address of sink circular buffer.
* @param byte_size Number of bytes to copy.
*/
void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst,
void *dst_addr, void *dst_end, size_t byte_size);
/**
* Copies data from linear source buffer to circular sink buffer.
* @param linear_source Source buffer.
* @param ioffset Offset (in samples) in source buffer to start reading from.
* @param sink Sink buffer.
* @param ooffset Offset (in samples) in sink buffer to start writing to.
* @param samples Number of samples to copy.
*/
void audio_stream_copy_from_linear(const void *linear_source, int ioffset,
struct audio_stream *sink, int ooffset,
unsigned int samples);
/**
* Copies data from circular source buffer to linear sink buffer.
* @param source Source buffer.
* @param ioffset Offset (in samples) in source buffer to start reading from.
* @param linear_sink Sink buffer.
* @param ooffset Offset (in samples) in sink buffer to start writing to.
* @param samples Number of samples to copy.
*/
void audio_stream_copy_to_linear(const struct audio_stream *source, int ioffset,
void *linear_sink, int ooffset, unsigned int samples);
/**
* Writes zeros in range [w_ptr, w_ptr+bytes], with rollover if necessary.
* @param buffer Buffer.
* @param bytes Size of the fragment to write zero.
* @return 0 if there is enough free space in buffer.
* @return 1 if there is not enough free space in buffer.
*/
static inline int audio_stream_set_zero(struct audio_stream *buffer, uint32_t bytes)
{
uint32_t head_size = bytes;
uint32_t tail_size = 0;
/* check for overrun */
if (audio_stream_get_free_bytes(buffer) < bytes)
return 1;
/* check for potential wrap */
if ((char *)buffer->w_ptr + bytes > (char *)buffer->end_addr) {
head_size = (char *)buffer->end_addr - (char *)buffer->w_ptr;
tail_size = bytes - head_size;
}
memset(buffer->w_ptr, 0, head_size);
if (tail_size)
memset(buffer->addr, 0, tail_size);
return 0;
}
static inline void audio_stream_fmt_conversion(enum ipc4_bit_depth depth,
enum ipc4_bit_depth valid,
enum sof_ipc_frame *frame_fmt,
enum sof_ipc_frame *valid_fmt,
enum ipc4_sample_type type)
{
/* IPC4_DEPTH_16BIT (16) <---> SOF_IPC_FRAME_S16_LE (0)
* IPC4_DEPTH_24BIT (24) <---> SOF_IPC_FRAME_S24_4LE (1)
* IPC4_DEPTH_32BIT (32) <---> SOF_IPC_FRAME_S32_LE (2)
*/
*frame_fmt = (depth >> 3) - 2;
*valid_fmt = (valid >> 3) - 2;
#ifdef CONFIG_FORMAT_U8