pcm: Dynamically-size the mixer buffer at higher audio bitrates.
Basically, existing sizes apply for <= 48KHz audio. Up to 96K, we double the mix buffer. up to 192K, we double it again. Will help reduce the interrupt load and overall latency, keeping it roughtly constant as a function of time, regardless of bitrate. (It is acutally a fixed-size buffer, statically-allocated to handle the worst-case bitrate the player supports. However, at runtime if we are using a lower bitrate we will only use a portion of it in order to keep latancies down) Change-Id: I61ca23180a86502732b0903fe9691c1a8c2aeaea
This commit is contained in:
parent
d4a620e85a
commit
2e708c48c5
1 changed files with 29 additions and 10 deletions
|
@ -25,6 +25,7 @@
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
#include "pcm_mixer.h"
|
#include "pcm_mixer.h"
|
||||||
|
#include "pcm_sampr.h"
|
||||||
|
|
||||||
/* Channels use standard-style PCM callback interface but a latency of one
|
/* Channels use standard-style PCM callback interface but a latency of one
|
||||||
frame by double-buffering is introduced in order to facilitate mixing and
|
frame by double-buffering is introduced in order to facilitate mixing and
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
parallel (as much as possible) with sending-out data. */
|
parallel (as much as possible) with sending-out data. */
|
||||||
|
|
||||||
static unsigned int mixer_sampr = HW_SAMPR_DEFAULT;
|
static unsigned int mixer_sampr = HW_SAMPR_DEFAULT;
|
||||||
|
static unsigned int mix_frame_size = MIX_FRAME_SAMPLES*4;
|
||||||
|
|
||||||
/* Define this to nonzero to add a marker pulse at each frame start */
|
/* Define this to nonzero to add a marker pulse at each frame start */
|
||||||
#define FRAME_BOUNDARY_MARKERS 0
|
#define FRAME_BOUNDARY_MARKERS 0
|
||||||
|
@ -49,13 +51,20 @@ struct mixer_channel
|
||||||
chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */
|
chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Forget about boost here for the moment */
|
#if (defined(HW_HAVE_192) || defined(HW_HAVE_176))
|
||||||
#define MIX_FRAME_SIZE (MIX_FRAME_SAMPLES*4)
|
#define FRAME_SIZE_MULT 4
|
||||||
|
#elif (defined(HW_HAVE_96) || defined(HW_HAVE_88))
|
||||||
|
#define FRAME_SIZE_MULT 2
|
||||||
|
#else
|
||||||
|
#define FRAME_SIZE_MULT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_MIX_FRAME_SAMPLES (MIX_FRAME_SAMPLES * FRAME_SIZE_MULT)
|
||||||
|
|
||||||
/* Because of the double-buffering, playback is always from here, otherwise a
|
/* Because of the double-buffering, playback is always from here, otherwise a
|
||||||
mechanism for the channel callbacks not to free buffers too early would be
|
mechanism for the channel callbacks not to free buffers too early would be
|
||||||
needed (if we _really_ want it and it's worth it, we _can_ do that ;-) ) */
|
needed (if we _really_ want it and it's worth it, we _can_ do that ;-) ) */
|
||||||
static uint32_t downmix_buf[2][MIX_FRAME_SAMPLES] DOWNMIX_BUF_IBSS MEM_ALIGN_ATTR;
|
static uint32_t downmix_buf[2][MAX_MIX_FRAME_SAMPLES] DOWNMIX_BUF_IBSS MEM_ALIGN_ATTR;
|
||||||
static int downmix_index = 0; /* Which downmix_buf? */
|
static int downmix_index = 0; /* Which downmix_buf? */
|
||||||
static size_t next_size = 0; /* Size of buffer to play next time */
|
static size_t next_size = 0; /* Size of buffer to play next time */
|
||||||
|
|
||||||
|
@ -66,7 +75,7 @@ static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR;
|
||||||
static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
|
static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
|
||||||
|
|
||||||
/* Number of silence frames to play after all data has played */
|
/* Number of silence frames to play after all data has played */
|
||||||
#define MAX_IDLE_FRAMES (mixer_sampr*3 / MIX_FRAME_SAMPLES)
|
#define MAX_IDLE_FRAMES (mixer_sampr*3 / mix_frame_size / 4)
|
||||||
static unsigned int idle_counter = 0;
|
static unsigned int idle_counter = 0;
|
||||||
|
|
||||||
/** Mixing routines, CPU optmized **/
|
/** Mixing routines, CPU optmized **/
|
||||||
|
@ -125,7 +134,7 @@ mixer_buffer_callback(enum pcm_dma_status status)
|
||||||
downmix_index ^= 1; /* Next buffer */
|
downmix_index ^= 1; /* Next buffer */
|
||||||
|
|
||||||
void *mixptr = downmix_buf[downmix_index];
|
void *mixptr = downmix_buf[downmix_index];
|
||||||
size_t mixsize = MIX_FRAME_SIZE;
|
size_t mixsize = mix_frame_size;
|
||||||
struct mixer_channel **chan_p;
|
struct mixer_channel **chan_p;
|
||||||
|
|
||||||
next_size = 0;
|
next_size = 0;
|
||||||
|
@ -216,11 +225,11 @@ fill_frame:
|
||||||
chan->last_size = mixsize;
|
chan->last_size = mixsize;
|
||||||
next_size += mixsize;
|
next_size += mixsize;
|
||||||
|
|
||||||
if (next_size < MIX_FRAME_SIZE)
|
if (next_size < mix_frame_size)
|
||||||
{
|
{
|
||||||
/* There is still space remaining in this frame */
|
/* There is still space remaining in this frame */
|
||||||
mixptr += mixsize;
|
mixptr += mixsize;
|
||||||
mixsize = MIX_FRAME_SIZE - next_size;
|
mixsize = mix_frame_size - next_size;
|
||||||
goto fill_frame;
|
goto fill_frame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,9 +237,9 @@ fill_frame:
|
||||||
{
|
{
|
||||||
/* Pad incomplete frames with silence */
|
/* Pad incomplete frames with silence */
|
||||||
if (idle_counter <= 3)
|
if (idle_counter <= 3)
|
||||||
memset(mixptr, 0, MIX_FRAME_SIZE - next_size);
|
memset(mixptr, 0, mix_frame_size - next_size);
|
||||||
|
|
||||||
next_size = MIX_FRAME_SIZE;
|
next_size = mix_frame_size;
|
||||||
}
|
}
|
||||||
/* else silence period ran out - go to sleep */
|
/* else silence period ran out - go to sleep */
|
||||||
|
|
||||||
|
@ -268,7 +277,7 @@ static void mixer_start_pcm(void)
|
||||||
mixer_buffer_callback(PCM_DMAST_STARTED);
|
mixer_buffer_callback(PCM_DMAST_STARTED);
|
||||||
|
|
||||||
pcm_play_data(mixer_pcm_callback, mixer_buffer_callback,
|
pcm_play_data(mixer_pcm_callback, mixer_buffer_callback,
|
||||||
start, MIX_FRAME_SIZE);
|
start, mix_frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Public interfaces **/
|
/** Public interfaces **/
|
||||||
|
@ -452,6 +461,16 @@ void mixer_set_frequency(unsigned int samplerate)
|
||||||
/* All data is now invalid */
|
/* All data is now invalid */
|
||||||
mixer_reset();
|
mixer_reset();
|
||||||
mixer_sampr = samplerate;
|
mixer_sampr = samplerate;
|
||||||
|
|
||||||
|
/* Work out how much space we really need */
|
||||||
|
if (samplerate > SAMPR_96)
|
||||||
|
mix_frame_size = 4;
|
||||||
|
else if (samplerate > SAMPR_48)
|
||||||
|
mix_frame_size = 2;
|
||||||
|
else
|
||||||
|
mix_frame_size = 1;
|
||||||
|
|
||||||
|
mix_frame_size *= MIX_FRAME_SAMPLES * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get output samplerate */
|
/* Get output samplerate */
|
||||||
|
|
Loading…
Reference in a new issue