Coverage Report

Created: 2026-03-07 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/src/audio_output/meter.c
Line
Count
Source
1
/*****************************************************************************
2
 * meter.c : audio meter
3
 *****************************************************************************
4
 * Copyright (C) 2020 VLC authors and VideoLAN
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published by
8
 * the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19
 *****************************************************************************/
20
21
#ifdef HAVE_CONFIG_H
22
# include "config.h"
23
#endif
24
25
#include <assert.h>
26
27
#include <vlc_common.h>
28
#include <vlc_configuration.h>
29
#include <vlc_aout.h>
30
#include "aout_internal.h"
31
32
struct vlc_audio_meter_plugin
33
{
34
    char *name;
35
    config_chain_t *cfg;
36
    filter_t *filter;
37
    vlc_tick_t last_date;
38
39
    struct vlc_audio_meter_plugin_owner owner;
40
41
    struct vlc_list node;
42
};
43
44
void
45
(vlc_audio_meter_Init)(struct vlc_audio_meter *meter, vlc_object_t *obj)
46
0
{
47
0
    vlc_mutex_init(&meter->lock);
48
0
    meter->parent = obj;
49
0
    meter->fmt = NULL;
50
0
    vlc_list_init(&meter->plugins);
51
0
}
52
53
void
54
vlc_audio_meter_Destroy(struct vlc_audio_meter *meter)
55
0
{
56
0
    vlc_audio_meter_plugin *plugin;
57
0
    vlc_list_foreach(plugin, &meter->plugins, node)
58
0
        vlc_audio_meter_RemovePlugin(meter, plugin);
59
0
}
60
61
static void
62
vlc_audio_meter_OnLoudnessChanged(filter_t *filter,
63
                             const struct vlc_audio_loudness *loudness)
64
0
{
65
0
    vlc_audio_meter_plugin *plugin = filter->owner.sys;
66
67
0
    if (plugin->owner.cbs->on_loudness != NULL)
68
0
        plugin->owner.cbs->on_loudness(plugin->last_date, loudness, plugin->owner.sys);
69
0
}
70
71
static filter_t *
72
vlc_audio_meter_CreatePluginFilter(struct vlc_audio_meter *meter, vlc_audio_meter_plugin *plugin)
73
0
{
74
0
    static const struct filter_audio_callbacks audio_cbs = {
75
0
        .meter_loudness = { .on_changed = vlc_audio_meter_OnLoudnessChanged }
76
0
    };
77
78
0
    const filter_owner_t owner = {
79
0
        .audio = &audio_cbs,
80
0
        .sys = plugin,
81
0
    };
82
83
0
    return aout_filter_Create(meter->parent, &owner, "audio meter", plugin->name,
84
0
                              meter->fmt, meter->fmt, plugin->cfg, true);
85
0
}
86
87
vlc_audio_meter_plugin *
88
vlc_audio_meter_AddPlugin(struct vlc_audio_meter *meter, const char *chain,
89
                          const struct vlc_audio_meter_plugin_owner *owner)
90
0
{
91
0
    assert(owner != NULL && owner->cbs != NULL);
92
93
0
    vlc_audio_meter_plugin *plugin = malloc(sizeof(*plugin));
94
0
    if (plugin == NULL)
95
0
        return NULL;
96
0
    plugin->owner = *owner;
97
0
    plugin->last_date = VLC_TICK_INVALID;
98
0
    plugin->name = NULL;
99
0
    plugin->cfg = NULL;
100
0
    plugin->filter = NULL;
101
102
0
    free(config_ChainCreate(&plugin->name, &plugin->cfg, chain));
103
0
    if (plugin->name == NULL)
104
0
        goto error;
105
106
0
    vlc_mutex_lock(&meter->lock);
107
0
    if (meter->fmt != NULL)
108
0
    {
109
0
        plugin->filter = vlc_audio_meter_CreatePluginFilter(meter, plugin);
110
0
        if (plugin->filter == NULL)
111
0
        {
112
0
            vlc_mutex_unlock(&meter->lock);
113
0
            goto error;
114
0
        }
115
116
0
        assert(plugin->filter->ops->drain_audio == NULL); /* Not supported */
117
0
    }
118
119
0
    vlc_list_append(&plugin->node, &meter->plugins);
120
0
    vlc_mutex_unlock(&meter->lock);
121
122
0
    return plugin;
123
124
0
error:
125
0
    free(plugin->name);
126
0
    if (plugin->cfg != NULL)
127
0
        config_ChainDestroy(plugin->cfg);
128
0
    free(plugin);
129
0
    return NULL;
130
0
}
131
132
void
133
vlc_audio_meter_RemovePlugin(struct vlc_audio_meter *meter, vlc_audio_meter_plugin *plugin)
134
0
{
135
0
    vlc_mutex_lock(&meter->lock);
136
137
0
    if (plugin->filter != NULL)
138
0
    {
139
0
        vlc_filter_Delete(plugin->filter);
140
0
    }
141
142
0
    if (plugin->cfg != NULL)
143
0
        config_ChainDestroy(plugin->cfg);
144
0
    free(plugin->name);
145
146
0
    vlc_list_remove(&plugin->node);
147
0
    free(plugin);
148
149
0
    vlc_mutex_unlock(&meter->lock);
150
0
}
151
152
int
153
vlc_audio_meter_Reset(struct vlc_audio_meter *meter, const audio_sample_format_t *fmt)
154
0
{
155
0
    int ret = VLC_SUCCESS;
156
157
0
    vlc_mutex_lock(&meter->lock);
158
159
0
    meter->fmt = fmt;
160
161
    /* Reload every plugins using the new fmt */
162
0
    vlc_audio_meter_plugin *plugin;
163
0
    vlc_list_foreach(plugin, &meter->plugins, node)
164
0
    {
165
0
        if (plugin->filter != NULL)
166
0
        {
167
0
            vlc_filter_Delete(plugin->filter);
168
0
            plugin->filter = NULL;
169
0
        }
170
0
        plugin->last_date = VLC_TICK_INVALID;
171
172
0
        if (meter->fmt != NULL)
173
0
        {
174
0
            plugin->filter = vlc_audio_meter_CreatePluginFilter(meter, plugin);
175
0
            if (plugin->filter == NULL)
176
0
            {
177
0
                ret = VLC_EGENERIC;
178
0
                break;
179
0
            }
180
0
        }
181
0
    }
182
183
0
    vlc_mutex_unlock(&meter->lock);
184
185
0
    return ret;
186
0
}
187
188
void
189
vlc_audio_meter_Process(struct vlc_audio_meter *meter, block_t *block, vlc_tick_t date)
190
0
{
191
0
    vlc_mutex_lock(&meter->lock);
192
193
0
    vlc_audio_meter_plugin *plugin;
194
0
    vlc_list_foreach(plugin, &meter->plugins, node)
195
0
    {
196
0
        filter_t *filter = plugin->filter;
197
198
0
        if (filter != NULL)
199
0
        {
200
0
            plugin->last_date = date + block->i_length;
201
202
0
            block_t *same_block = filter->ops->filter_audio(filter, block);
203
0
            assert(same_block == block); (void) same_block;
204
0
        }
205
0
    }
206
207
0
    vlc_mutex_unlock(&meter->lock);
208
0
}
209
210
void
211
vlc_audio_meter_Flush(struct vlc_audio_meter *meter)
212
0
{
213
0
    vlc_mutex_lock(&meter->lock);
214
215
0
    vlc_audio_meter_plugin *plugin;
216
0
    vlc_list_foreach(plugin, &meter->plugins, node)
217
0
    {
218
0
        filter_t *filter = plugin->filter;
219
0
        if (filter != NULL)
220
0
            filter_Flush(filter);
221
0
    }
222
223
0
    vlc_mutex_unlock(&meter->lock);
224
0
}