src/audio/SDL_audiocvt.c
changeset 11636 ec1c9bded2d0
parent 11634 ced7925b7a95
child 11641 e4ffc5a1b7ea
     1.1 --- a/src/audio/SDL_audiocvt.c	Thu Oct 19 13:54:56 2017 -0700
     1.2 +++ b/src/audio/SDL_audiocvt.c	Thu Oct 19 18:05:42 2017 -0400
     1.3 @@ -1362,7 +1362,7 @@
     1.4  }
     1.5  
     1.6  static int
     1.7 -SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len)
     1.8 +SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
     1.9  {
    1.10      int buflen = len;
    1.11      int workbuflen;
    1.12 @@ -1479,6 +1479,13 @@
    1.13      printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
    1.14      #endif
    1.15  
    1.16 +    if (maxputbytes) {
    1.17 +        const int maxbytes = *maxputbytes;
    1.18 +        if (buflen > maxbytes)
    1.19 +            buflen = maxbytes;
    1.20 +        *maxputbytes -= buflen;
    1.21 +    }
    1.22 +
    1.23      /* resamplebuf holds the final output, even if we didn't resample. */
    1.24      return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
    1.25  }
    1.26 @@ -1524,7 +1531,7 @@
    1.27             we don't need to store it for later, skip the staging process.
    1.28           */
    1.29          if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
    1.30 -            return SDL_AudioStreamPutInternal(stream, buf, len);
    1.31 +            return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
    1.32          }
    1.33  
    1.34          /* If there's not enough data to fill the staging buffer, just save it */
    1.35 @@ -1539,7 +1546,7 @@
    1.36          SDL_assert(amount > 0);
    1.37          SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
    1.38          stream->staging_buffer_filled = 0;
    1.39 -        if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size) < 0) {
    1.40 +        if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
    1.41              return -1;
    1.42          }
    1.43          buf = (void *)((Uint8 *)buf + amount);
    1.44 @@ -1548,6 +1555,58 @@
    1.45      return 0;
    1.46  }
    1.47  
    1.48 +int SDL_AudioStreamFlush(SDL_AudioStream *stream)
    1.49 +{
    1.50 +    if (!stream) {
    1.51 +        return SDL_InvalidParamError("stream");
    1.52 +    }
    1.53 +
    1.54 +    #if DEBUG_AUDIOSTREAM
    1.55 +    printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
    1.56 +    #endif
    1.57 +
    1.58 +    /* shouldn't use a staging buffer if we're not resampling. */
    1.59 +    SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
    1.60 +
    1.61 +    if (stream->staging_buffer_filled > 0) {
    1.62 +        /* push the staging buffer + silence. We need to flush out not just
    1.63 +           the staging buffer, but the piece that the stream was saving off
    1.64 +           for right-side resampler padding. */
    1.65 +        const SDL_bool first_run = stream->first_run;
    1.66 +        const int filled = stream->staging_buffer_filled;
    1.67 +        int actual_input_frames = filled / stream->src_sample_frame_size;
    1.68 +        if (!first_run)
    1.69 +            actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
    1.70 +
    1.71 +        if (actual_input_frames > 0) {  /* don't bother if nothing to flush. */
    1.72 +            /* This is how many bytes we're expecting without silence appended. */
    1.73 +            int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
    1.74 +
    1.75 +            #if DEBUG_AUDIOSTREAM
    1.76 +            printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
    1.77 +            #endif
    1.78 +
    1.79 +            SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
    1.80 +            if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
    1.81 +                return -1;
    1.82 +            }
    1.83 +
    1.84 +            /* we have flushed out (or initially filled) the pending right-side
    1.85 +               resampler padding, but we need to push more silence to guarantee
    1.86 +               the staging buffer is fully flushed out, too. */
    1.87 +            SDL_memset(stream->staging_buffer, '\0', filled);
    1.88 +            if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
    1.89 +                return -1;
    1.90 +            }
    1.91 +        }
    1.92 +    }
    1.93 +
    1.94 +    stream->staging_buffer_filled = 0;
    1.95 +    stream->first_run = SDL_TRUE;
    1.96 +
    1.97 +    return 0;
    1.98 +}
    1.99 +
   1.100  /* get converted/resampled data from the stream */
   1.101  int
   1.102  SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
   1.103 @@ -1587,6 +1646,7 @@
   1.104              stream->reset_resampler_func(stream);
   1.105          }
   1.106          stream->first_run = SDL_TRUE;
   1.107 +        stream->staging_buffer_filled = 0;
   1.108      }
   1.109  }
   1.110