From 141e91ef1fc5ce6c487988c29c00e57fa6e52fb6 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Mon, 12 Oct 2020 09:29:21 -0400 Subject: Hosted PCM: Rework auto-muting code a bit * If AUDIOHW_MUTE_ON_PAUSE, no meaningful change * Unconditionally unmute on playback start * xduoox3ii: Mute on sample rate change * rocker/xduoo: Stay muted after startup This avoids the nasty "pop" on startup, without doing the full mute-on-pause stuff that causes unacceptable dropouts on the X3ii. Change-Id: I2e3ee0bb8094e288f37a0acada86a80016ce5cac --- firmware/drivers/audio/erosqlinux_codec.c | 7 ++++-- firmware/drivers/audio/rocker_codec.c | 2 +- firmware/drivers/audio/xduoolinux_codec.c | 7 ++++-- firmware/export/xduoolinux_codec.h | 8 ++++++ firmware/target/hosted/pcm-alsa.c | 42 ++++++++++++++++++------------- 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/firmware/drivers/audio/erosqlinux_codec.c b/firmware/drivers/audio/erosqlinux_codec.c index deb3bb4b87..9336083d58 100644 --- a/firmware/drivers/audio/erosqlinux_codec.c +++ b/firmware/drivers/audio/erosqlinux_codec.c @@ -56,6 +56,8 @@ static void hw_close(void) close(fd_hw); } +static int muted = -1; + void audiohw_mute(int mute) { logf("mute %d", mute); @@ -70,6 +72,7 @@ void audiohw_mute(int mute) last_ps = 0; erosq_get_outputs(); } + muted = mute; } int erosq_get_outputs(void) { @@ -95,7 +98,7 @@ int erosq_get_outputs(void) { void erosq_set_output(int ps) { - if (!inited) return; + if (!inited || muted) return; if (last_ps != ps) { @@ -119,7 +122,7 @@ void audiohw_preinit(void) void audiohw_postinit(void) { logf("hw postinit"); - erosq_set_output(erosq_get_outputs()); /* Unmute */ + erosq_get_outputs(); // Unmutes } void audiohw_close(void) diff --git a/firmware/drivers/audio/rocker_codec.c b/firmware/drivers/audio/rocker_codec.c index 525507494b..e5573df843 100644 --- a/firmware/drivers/audio/rocker_codec.c +++ b/firmware/drivers/audio/rocker_codec.c @@ -70,7 +70,7 @@ void audiohw_postinit(void) long int hp = 2; /* Output port switch set to Headphones */ - alsa_controls_set_ints("Output Port Switch", 1, &hp); /* Unmutes */ + //alsa_controls_set_ints("Output Port Switch", 1, &hp); // Unmute happens on PCM start } void audiohw_close(void) diff --git a/firmware/drivers/audio/xduoolinux_codec.c b/firmware/drivers/audio/xduoolinux_codec.c index b114b1bbc9..59ef562d0a 100644 --- a/firmware/drivers/audio/xduoolinux_codec.c +++ b/firmware/drivers/audio/xduoolinux_codec.c @@ -55,6 +55,8 @@ static void hw_close(void) close(fd_hw); } +static int muted = -1; + void audiohw_mute(int mute) { logf("mute %d", mute); @@ -69,6 +71,7 @@ void audiohw_mute(int mute) last_ps = 0; xduoo_get_outputs(); } + muted = mute; } int xduoo_get_outputs(void){ @@ -102,7 +105,7 @@ int xduoo_get_outputs(void){ void xduoo_set_output(int ps) { - if (!inited) return; + if (!inited || muted) return; if (last_ps != ps) { @@ -128,7 +131,7 @@ void audiohw_postinit(void) // const char * const codec_pmdown = "/sys/devices/platform/ingenic-x3ii.0/x3ii-ak4490-i2s/pmdown_time"; // in ms, defaults 5000 logf("hw postinit"); - xduoo_set_output(xduoo_get_outputs()); /* Unmute */ + // xduoo_get_outputs(); // Unmute happens upon playback. } void audiohw_close(void) diff --git a/firmware/export/xduoolinux_codec.h b/firmware/export/xduoolinux_codec.h index a46976d386..09609d477c 100644 --- a/firmware/export/xduoolinux_codec.h +++ b/firmware/export/xduoolinux_codec.h @@ -6,6 +6,14 @@ AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -127, 0, -30) AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 4, 0) #endif +// We want this, but the codec takes over a second to unmute! +//#define AUDIOHW_MUTE_ON_PAUSE + +#if defined(XDUOO_X3II) +/* The AK4490 glitches when switching sample rates */ +#define AUDIOHW_MUTE_ON_SRATE_CHANGE +#endif + void audiohw_mute(int mute); void xduoo_set_output(int ps); int xduoo_get_outputs(void); diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c index 3d91bc18cf..428902b82e 100644 --- a/firmware/target/hosted/pcm-alsa.c +++ b/firmware/target/hosted/pcm-alsa.c @@ -81,8 +81,8 @@ static const snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format * typedef short sample_t; #endif static const int channels = 2; /* count of channels */ -static unsigned int sample_rate = 0; static unsigned int real_sample_rate = 0; +static unsigned int last_sample_rate = 0; static snd_pcm_t *handle = NULL; static snd_pcm_sframes_t buffer_size; @@ -148,17 +148,17 @@ static int set_hwparams(snd_pcm_t *handle) goto error; } /* set the stream rate */ - sample_rate = srate = pcm_sampr; + srate = pcm_sampr; err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); if (err < 0) { - logf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err)); + logf("Rate %iHz not available for playback: %s\n", pcm_sampr, snd_strerror(err)); goto error; } real_sample_rate = srate; - if (real_sample_rate != sample_rate) + if (real_sample_rate != pcm_sampr) { - logf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, real_sample_rate); + logf("Rate doesn't match (requested %iHz, get %iHz)\n", pcm_sampr, real_sample_rate); err = -EINVAL; goto error; } @@ -517,11 +517,13 @@ void pcm_play_unlock(void) static void pcm_dma_apply_settings_nolock(void) { - logf("PCM DMA Settings %d %d", sample_rate, pcm_sampr); + logf("PCM DMA Settings %d %d", last_sample_rate, pcm_sampr); - if (sample_rate != pcm_sampr) + if (last_sample_rate != pcm_sampr) { -#ifdef AUDIOHW_MUTE_ON_PAUSE + last_sample_rate = pcm_sampr; + +#ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE // XXX AK4450 (xDuoo X3ii) needs to be muted when switching rates. audiohw_mute(true); #endif @@ -531,8 +533,10 @@ static void pcm_dma_apply_settings_nolock(void) /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ audiohw_set_frequency(pcm_sampr); #endif - - /* (Will be unmuted by pcm resuming) */ +#ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE + audiohw_mute(false); +#endif + /* (Will be unmuted by pcm resuming) */ } } @@ -560,7 +564,7 @@ void pcm_play_dma_stop(void) snd_pcm_nonblock(handle, 0); snd_pcm_drain(handle); snd_pcm_nonblock(handle, 1); - sample_rate = 0; + last_sample_rate = 0; #ifdef AUDIOHW_MUTE_ON_PAUSE audiohw_mute(true); #endif @@ -575,6 +579,10 @@ void pcm_play_dma_start(const void *addr, size_t size) pcm_data = addr; pcm_size = size; +#if !defined(AUDIOHW_MUTE_ON_PAUSE) || !defined(AUDIOHW_MUTE_ON_SRATE_CHANGE) + audiohw_mute(false); +#endif + while (1) { snd_pcm_state_t state = snd_pcm_state(handle); @@ -605,14 +613,14 @@ void pcm_play_dma_start(const void *addr, size_t size) int err = async_rw(handle); if (err < 0) { logf("Start error: %s\n", snd_strerror(err)); - return; - } + return; + } #ifdef AUDIOHW_MUTE_ON_PAUSE - audiohw_mute(false); + audiohw_mute(false); #endif - if (err == 0) - return; - break; + if (err == 0) + return; + break; } case SND_PCM_STATE_PAUSED: { /* paused, simply resume */ -- cgit v1.2.3