Coverage Report

Created: 2026-06-13 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/audio/out/ao_null.c
Line
Count
Source
1
/*
2
 * null audio output driver
3
 *
4
 * This file is part of mpv.
5
 *
6
 * mpv is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * mpv 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
17
 * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
/*
21
 * Note: this does much more than just ignoring audio output. It simulates
22
 *       (to some degree) an ideal AO.
23
 */
24
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <math.h>
28
29
#include "mpv_talloc.h"
30
31
#include "osdep/timer.h"
32
#include "options/m_option.h"
33
#include "common/common.h"
34
#include "common/msg.h"
35
#include "audio/format.h"
36
#include "ao.h"
37
#include "internal.h"
38
39
struct priv {
40
    bool paused;
41
    double last_time;
42
    float buffered;     // samples
43
    int buffersize;     // samples
44
    bool playing;
45
46
    bool untimed;
47
    float bufferlen;    // seconds
48
    float speed;        // multiplier
49
    float latency_sec;  // seconds
50
    float latency;      // samples
51
    bool broken_eof;
52
    bool broken_delay;
53
54
    // Minimal unit of audio samples that can be written at once. If play() is
55
    // called with sizes not aligned to this, a rounded size will be returned.
56
    // (This is not needed by the AO API, but many AOs behave this way.)
57
    int outburst;       // samples
58
59
    struct m_channels channel_layouts;
60
    int format;
61
};
62
63
static void drain(struct ao *ao)
64
10.9M
{
65
10.9M
    struct priv *priv = ao->priv;
66
67
10.9M
    if (ao->untimed) {
68
10.9M
        priv->buffered = 0;
69
10.9M
        return;
70
10.9M
    }
71
72
0
    if (priv->paused)
73
0
        return;
74
75
0
    double now = mp_time_sec();
76
0
    if (priv->buffered > 0) {
77
0
        priv->buffered -= (now - priv->last_time) * ao->samplerate * priv->speed;
78
0
        if (priv->buffered < 0)
79
0
            priv->buffered = 0;
80
0
    }
81
0
    priv->last_time = now;
82
0
}
83
84
static int init(struct ao *ao)
85
30.4k
{
86
30.4k
    struct priv *priv = ao->priv;
87
88
30.4k
    if (priv->format)
89
0
        ao->format = priv->format;
90
91
30.4k
    ao->untimed = priv->untimed;
92
93
30.4k
    struct mp_chmap_sel sel = {.tmp = ao};
94
30.4k
    if (priv->channel_layouts.num_chmaps) {
95
0
        for (int n = 0; n < priv->channel_layouts.num_chmaps; n++)
96
0
            mp_chmap_sel_add_map(&sel, &priv->channel_layouts.chmaps[n]);
97
30.4k
    } else {
98
30.4k
        mp_chmap_sel_add_any(&sel);
99
30.4k
    }
100
30.4k
    if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
101
0
        mp_chmap_from_channels(&ao->channels, 2);
102
103
30.4k
    priv->latency = priv->latency_sec * ao->samplerate;
104
105
    // A "buffer" for this many seconds of audio
106
30.4k
    int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst;
107
30.4k
    ao->device_buffer = priv->outburst * bursts + priv->latency;
108
109
30.4k
    priv->last_time = mp_time_sec();
110
111
30.4k
    return 0;
112
30.4k
}
113
114
// close audio device
115
static void uninit(struct ao *ao)
116
30.4k
{
117
30.4k
}
118
119
// stop playing and empty buffers (for seeking)
120
static void reset(struct ao *ao)
121
17.5k
{
122
17.5k
    struct priv *priv = ao->priv;
123
17.5k
    priv->paused = false;
124
17.5k
    priv->buffered = 0;
125
17.5k
    priv->playing = false;
126
17.5k
}
127
128
static void start(struct ao *ao)
129
29.5k
{
130
29.5k
    struct priv *priv = ao->priv;
131
132
29.5k
    if (priv->paused)
133
29.5k
        MP_ERR(ao, "illegal state: start() while paused\n");
134
135
29.5k
    drain(ao);
136
29.5k
    priv->paused = false;
137
29.5k
    priv->last_time = mp_time_sec();
138
29.5k
    priv->playing = true;
139
29.5k
}
140
141
static bool set_pause(struct ao *ao, bool paused)
142
2
{
143
2
    struct priv *priv = ao->priv;
144
145
2
    if (!priv->playing)
146
2
        MP_ERR(ao, "illegal state: set_pause() while not playing\n");
147
148
2
    if (priv->paused != paused) {
149
150
2
        drain(ao);
151
2
        priv->paused = paused;
152
2
        if (!priv->paused)
153
1
            priv->last_time = mp_time_sec();
154
2
    }
155
156
2
    return true;
157
2
}
158
159
static bool audio_write(struct ao *ao, void **data, int samples)
160
7.51M
{
161
7.51M
    struct priv *priv = ao->priv;
162
163
7.51M
    if (priv->buffered <= 0)
164
7.51M
        priv->buffered = priv->latency; // emulate fixed latency
165
166
7.51M
    priv->buffered += samples;
167
7.51M
    return true;
168
7.51M
}
169
170
static void get_state(struct ao *ao, struct mp_pcm_state *state)
171
10.9M
{
172
10.9M
    struct priv *priv = ao->priv;
173
174
10.9M
    drain(ao);
175
176
10.9M
    state->free_samples = ao->device_buffer - priv->latency - priv->buffered;
177
10.9M
    state->free_samples = state->free_samples / priv->outburst * priv->outburst;
178
10.9M
    state->queued_samples = priv->buffered;
179
180
    // Note how get_state returns the delay in audio device time (instead of
181
    // adjusting for speed), since most AOs seem to also do that.
182
10.9M
    state->delay = priv->buffered;
183
184
    // Drivers with broken EOF handling usually always report the same device-
185
    // level delay that is additional to the buffer time.
186
10.9M
    if (priv->broken_eof && priv->buffered < priv->latency)
187
0
        state->delay = priv->latency;
188
189
10.9M
    state->delay /= ao->samplerate;
190
191
10.9M
    if (priv->broken_delay) { // Report only multiples of outburst
192
0
        double q = priv->outburst / (double)ao->samplerate;
193
0
        if (state->delay > 0)
194
0
            state->delay = (int)(state->delay / q) * q;
195
0
    }
196
197
10.9M
    state->playing = priv->playing && priv->buffered > 0;
198
10.9M
}
199
200
#define OPT_BASE_STRUCT struct priv
201
202
const struct ao_driver audio_out_null = {
203
    .description = "Null audio output",
204
    .name      = "null",
205
    .init      = init,
206
    .uninit    = uninit,
207
    .reset     = reset,
208
    .get_state = get_state,
209
    .set_pause = set_pause,
210
    .write     = audio_write,
211
    .start     = start,
212
    .priv_size = sizeof(struct priv),
213
    .priv_defaults = &(const struct priv) {
214
        .bufferlen = 0.2,
215
        .outburst = 256,
216
        .speed = 1,
217
    },
218
    .options = (const struct m_option[]) {
219
        {"untimed", OPT_BOOL(untimed)},
220
        {"buffer", OPT_FLOAT(bufferlen), M_RANGE(0, 100)},
221
        {"outburst", OPT_INT(outburst), M_RANGE(1, 100000)},
222
        {"speed", OPT_FLOAT(speed), M_RANGE(0, 10000)},
223
        {"latency", OPT_FLOAT(latency_sec), M_RANGE(0, 100)},
224
        {"broken-eof", OPT_BOOL(broken_eof)},
225
        {"broken-delay", OPT_BOOL(broken_delay)},
226
        {"channel-layouts", OPT_CHANNELS(channel_layouts)},
227
        {"format", OPT_AUDIOFORMAT(format)},
228
        {0}
229
    },
230
    .options_prefix = "ao-null",
231
};