Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/pcm/pcm_meter.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,7 @@ typedef struct _snd_pcm_scope_s16 {
snd_pcm_uframes_t old;
int16_t *buf;
snd_pcm_channel_area_t *buf_areas;
int silent;
} snd_pcm_scope_s16_t;

static int s16_enable(snd_pcm_scope_t *scope)
Expand Down Expand Up @@ -1043,15 +1044,31 @@ static int s16_enable(snd_pcm_scope_t *scope)
idx = snd_pcm_linear_convert_index(spcm->format, SND_PCM_FORMAT_S16);
break;
default:
return -EINVAL;
/* No S16 conversion exists for this format - DSD, the 3-byte
* packed formats, float. Leaving the scope disabled is worse
* than useless: scopes that depend on it, including our own
* level scope, call snd_pcm_scope_s16_get_channel_buffer()
* from their update callback and that assert()s on the buffer
* this function never allocated, killing the application.
* Hand out a silent buffer instead, so a scope reads zero on a
* format it cannot see rather than aborting the process.
*/
snd_error(PCM, "s16 scope: no S16 conversion for format %s, scopes will read silence",
snd_pcm_format_name(spcm->format));
s16->silent = 1;
idx = 0;
break;
}
s16->index = idx;
if (spcm->format == SND_PCM_FORMAT_IMA_ADPCM) {
s16->adpcm_states = calloc(spcm->channels, sizeof(*s16->adpcm_states));
if (!s16->adpcm_states)
return -ENOMEM;
}
s16->buf = malloc(meter->buf_size * 2 * spcm->channels);
/* calloc, not malloc: when s16->silent is set nothing ever writes to
* this buffer and scopes must read silence, not uninitialised memory.
*/
s16->buf = calloc(meter->buf_size * 2 * spcm->channels, 1);
if (!s16->buf) {
free(s16->adpcm_states);
return -ENOMEM;
Expand Down Expand Up @@ -1103,6 +1120,11 @@ static void s16_update(snd_pcm_scope_t *scope)
snd_pcm_t *spcm = meter->gen.slave;
snd_pcm_sframes_t size;
snd_pcm_uframes_t offset;
if (s16->silent) {
/* Nothing to convert; the buffer stays zero. */
s16->old = meter->now;
return;
}
size = meter->now - s16->old;
if (size < 0)
size += spcm->boundary;
Expand Down
Loading