UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
audio_buffer.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2016-2021 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif
43
44#include "audio/types.h"
45#include "debug.h"
46#include "host.h"
47#include "utils/audio_buffer.h"
48#include "utils/ring_buffer.h"
49
50#define WINDOW 50
51
52#undef max
53#undef min
54#define max(a, b) (((a) > (b))? (a): (b))
55#define min(a, b) (((a) < (b))? (a): (b))
56
57#define BUF_LAST_UNDERRUN_MAX 1000000000
58#define BUF_LAST_UNDERRUN_THRESHOLD 10000
59#define BUF_LAST_OVERRUN_THRESHOLD 10000
60#define AGGRESSIVITY_MAX 4
61#define AGGRESSIVITY_STEP 100
62
63static const int occupacy_windows[] = { 50, 200 };
64
69
70 // moving averages
73 int avg_occupancy[2]; // at read time
74 int last_underrun; // last underrun n output frames ago
75 int last_overrun; // last overrun n output frames ago
78};
79
80struct audio_buffer *audio_buffer_init(int sample_rate, int bps, int ch_count, int suggested_latency_ms)
81{
82 struct audio_buffer *buf = calloc(1, sizeof(struct audio_buffer));
84 buf->desc.bps = bps;
85 buf->desc.ch_count = ch_count;
86
88
89 buf->ring = ring_buffer_init(sample_rate * bps * ch_count);
90
92
93 buf->aggressivity = 1;
95
96 return buf;
97}
98
100{
101 if (!buf) {
102 return;
103 }
105 free(buf);
106}
107
108int audio_buffer_read(struct audio_buffer *buf, char *out, int max_len)
109{
110 if (buf->out_pkt_size > 0) {
111 buf->out_pkt_size = (max_len + (buf->out_pkt_size * (WINDOW-1))) / WINDOW;
112 } else {
113 buf->out_pkt_size = max_len;
114 }
115
116 int ring_size = ring_get_current_size(buf->ring);
117
118 for (unsigned int i = 0; i < sizeof buf->avg_occupancy / sizeof buf->avg_occupancy[0]; ++i) {
119 if (buf->avg_occupancy[i] > 0) {
120 buf->avg_occupancy[i] = (ring_size + (buf->avg_occupancy[i] * (occupacy_windows[i] -1))) / occupacy_windows[i];
121 } else {
122 buf->avg_occupancy[i] = ring_size;
123 }
124 }
125
126 // handle underruns
127 if (ring_size < max_len) {
128 buf->last_underrun = 0;
129 } else {
131 buf->last_underrun += 1;
132 }
133 }
134
135 int suggested_latency_bytes = buf->suggested_latency_ms * buf->desc.bps * buf->desc.ch_count * buf->desc.sample_rate / 1000;
136 int requested_latency_bytes = max(suggested_latency_bytes, 2*max(buf->in_pkt_size, buf->out_pkt_size));
137
138 int ret = ring_buffer_read(buf->ring, out, max_len);
139
140 // fiddle aggressivity
146 buf->aggressivity = max(buf->aggressivity - 1, 1);
147 }
148 } else {
149 buf->last_aggressivity_change += 1;
150 }
151
152 // handle overruns
153 int remaining_bytes = ring_size - ret;
154 if (requested_latency_bytes < remaining_bytes) {
155 int len_drop = (1<<buf->aggressivity) * buf->desc.bps * buf->desc.ch_count * 128;
156 len_drop = min(len_drop, remaining_bytes / 2);
157
158 char *tmp = alloca(len_drop);
159 ring_buffer_read(buf->ring, tmp, len_drop);
160 buf->last_overrun = 0;
161 log_msg(LOG_LEVEL_VERBOSE, "Dropped audio samples: req latency %d remaining %d dropped %d!\n", requested_latency_bytes, remaining_bytes, len_drop);
162 } else {
163 buf->last_overrun += 1;
164 }
165
166 log_msg(LOG_LEVEL_DEBUG, "buf - in a. %d, out a. %d, occ. a. [%d,%d] last under/overrun %d, %d aggressivity %d\n", buf->in_pkt_size, buf->out_pkt_size, buf->avg_occupancy[0],buf->avg_occupancy[1], buf->last_underrun, buf->last_overrun, buf->aggressivity);
167
168 return ret;
169}
170
171void audio_buffer_write(struct audio_buffer *buf, const char *in, int len)
172{
173 if (buf->in_pkt_size > 0) {
174 buf->in_pkt_size = (len + (buf->in_pkt_size * (WINDOW-1))) / WINDOW;
175 } else {
176 buf->in_pkt_size = len;
177 }
178 ring_buffer_write(buf->ring, in, len);
179}
180
182 (void (*)(void *)) audio_buffer_destroy,
183 (int (*)(void *, char *, int)) audio_buffer_read,
184 (void (*)(void *, const char *, int)) audio_buffer_write,
185};
186
int int int sample_rate
int void size_t * len
This file contains definition of some common audio types.
#define BUF_LAST_UNDERRUN_THRESHOLD
#define AGGRESSIVITY_STEP
static const int occupacy_windows[]
#define WINDOW
#define BUF_LAST_OVERRUN_THRESHOLD
#define AGGRESSIVITY_MAX
struct audio_buffer_api audio_buffer_fns
void audio_buffer_destroy(struct audio_buffer *buf)
#define BUF_LAST_UNDERRUN_MAX
struct audio_buffer * audio_buffer_init(int sample_rate, int bps, int ch_count, int suggested_latency_ms)
#define min(a, b)
int audio_buffer_read(struct audio_buffer *buf, char *out, int max_len)
void audio_buffer_write(struct audio_buffer *buf, const char *in, int len)
#define max(a, b)
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
int ring_get_current_size(struct ring_buffer *ring)
void ring_buffer_destroy(struct ring_buffer *ring)
struct ring_buffer * ring_buffer_init(int size)
int ring_buffer_read(struct ring_buffer *ring, char *out, int max_len)
void ring_buffer_write(struct ring_buffer *ring, const char *in, int len)
struct audio_desc desc
int suggested_latency_ms
int last_aggressivity_change
ring_buffer_t * ring
int avg_occupancy[2]
int sample_rate
Definition types.h:78
int ch_count
Definition types.h:79
int bps
Definition types.h:77