diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2020-10-12 09:29:21 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2020-10-12 13:40:37 +0000 |
commit | 141e91ef1fc5ce6c487988c29c00e57fa6e52fb6 (patch) | |
tree | 96a29cb38a833565e099ce3b00016bb653695699 | |
parent | 9ad30869b86dd827fbbf56a67122d662a51514f5 (diff) | |
download | rockbox-141e91ef1fc5ce6c487988c29c00e57fa6e52fb6.tar.gz rockbox-141e91ef1fc5ce6c487988c29c00e57fa6e52fb6.zip |
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
-rw-r--r-- | firmware/drivers/audio/erosqlinux_codec.c | 7 | ||||
-rw-r--r-- | firmware/drivers/audio/rocker_codec.c | 2 | ||||
-rw-r--r-- | firmware/drivers/audio/xduoolinux_codec.c | 7 | ||||
-rw-r--r-- | firmware/export/xduoolinux_codec.h | 8 | ||||
-rw-r--r-- | 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) | |||
56 | close(fd_hw); | 56 | close(fd_hw); |
57 | } | 57 | } |
58 | 58 | ||
59 | static int muted = -1; | ||
60 | |||
59 | void audiohw_mute(int mute) | 61 | void audiohw_mute(int mute) |
60 | { | 62 | { |
61 | logf("mute %d", mute); | 63 | logf("mute %d", mute); |
@@ -70,6 +72,7 @@ void audiohw_mute(int mute) | |||
70 | last_ps = 0; | 72 | last_ps = 0; |
71 | erosq_get_outputs(); | 73 | erosq_get_outputs(); |
72 | } | 74 | } |
75 | muted = mute; | ||
73 | } | 76 | } |
74 | 77 | ||
75 | int erosq_get_outputs(void) { | 78 | int erosq_get_outputs(void) { |
@@ -95,7 +98,7 @@ int erosq_get_outputs(void) { | |||
95 | 98 | ||
96 | void erosq_set_output(int ps) | 99 | void erosq_set_output(int ps) |
97 | { | 100 | { |
98 | if (!inited) return; | 101 | if (!inited || muted) return; |
99 | 102 | ||
100 | if (last_ps != ps) | 103 | if (last_ps != ps) |
101 | { | 104 | { |
@@ -119,7 +122,7 @@ void audiohw_preinit(void) | |||
119 | void audiohw_postinit(void) | 122 | void audiohw_postinit(void) |
120 | { | 123 | { |
121 | logf("hw postinit"); | 124 | logf("hw postinit"); |
122 | erosq_set_output(erosq_get_outputs()); /* Unmute */ | 125 | erosq_get_outputs(); // Unmutes |
123 | } | 126 | } |
124 | 127 | ||
125 | void audiohw_close(void) | 128 | 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) | |||
70 | long int hp = 2; | 70 | long int hp = 2; |
71 | 71 | ||
72 | /* Output port switch set to Headphones */ | 72 | /* Output port switch set to Headphones */ |
73 | alsa_controls_set_ints("Output Port Switch", 1, &hp); /* Unmutes */ | 73 | //alsa_controls_set_ints("Output Port Switch", 1, &hp); // Unmute happens on PCM start |
74 | } | 74 | } |
75 | 75 | ||
76 | void audiohw_close(void) | 76 | 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) | |||
55 | close(fd_hw); | 55 | close(fd_hw); |
56 | } | 56 | } |
57 | 57 | ||
58 | static int muted = -1; | ||
59 | |||
58 | void audiohw_mute(int mute) | 60 | void audiohw_mute(int mute) |
59 | { | 61 | { |
60 | logf("mute %d", mute); | 62 | logf("mute %d", mute); |
@@ -69,6 +71,7 @@ void audiohw_mute(int mute) | |||
69 | last_ps = 0; | 71 | last_ps = 0; |
70 | xduoo_get_outputs(); | 72 | xduoo_get_outputs(); |
71 | } | 73 | } |
74 | muted = mute; | ||
72 | } | 75 | } |
73 | 76 | ||
74 | int xduoo_get_outputs(void){ | 77 | int xduoo_get_outputs(void){ |
@@ -102,7 +105,7 @@ int xduoo_get_outputs(void){ | |||
102 | 105 | ||
103 | void xduoo_set_output(int ps) | 106 | void xduoo_set_output(int ps) |
104 | { | 107 | { |
105 | if (!inited) return; | 108 | if (!inited || muted) return; |
106 | 109 | ||
107 | if (last_ps != ps) | 110 | if (last_ps != ps) |
108 | { | 111 | { |
@@ -128,7 +131,7 @@ void audiohw_postinit(void) | |||
128 | // const char * const codec_pmdown = "/sys/devices/platform/ingenic-x3ii.0/x3ii-ak4490-i2s/pmdown_time"; // in ms, defaults 5000 | 131 | // const char * const codec_pmdown = "/sys/devices/platform/ingenic-x3ii.0/x3ii-ak4490-i2s/pmdown_time"; // in ms, defaults 5000 |
129 | 132 | ||
130 | logf("hw postinit"); | 133 | logf("hw postinit"); |
131 | xduoo_set_output(xduoo_get_outputs()); /* Unmute */ | 134 | // xduoo_get_outputs(); // Unmute happens upon playback. |
132 | } | 135 | } |
133 | 136 | ||
134 | void audiohw_close(void) | 137 | 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) | |||
6 | AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 4, 0) | 6 | AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 4, 0) |
7 | #endif | 7 | #endif |
8 | 8 | ||
9 | // We want this, but the codec takes over a second to unmute! | ||
10 | //#define AUDIOHW_MUTE_ON_PAUSE | ||
11 | |||
12 | #if defined(XDUOO_X3II) | ||
13 | /* The AK4490 glitches when switching sample rates */ | ||
14 | #define AUDIOHW_MUTE_ON_SRATE_CHANGE | ||
15 | #endif | ||
16 | |||
9 | void audiohw_mute(int mute); | 17 | void audiohw_mute(int mute); |
10 | void xduoo_set_output(int ps); | 18 | void xduoo_set_output(int ps); |
11 | int xduoo_get_outputs(void); | 19 | 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 * | |||
81 | typedef short sample_t; | 81 | typedef short sample_t; |
82 | #endif | 82 | #endif |
83 | static const int channels = 2; /* count of channels */ | 83 | static const int channels = 2; /* count of channels */ |
84 | static unsigned int sample_rate = 0; | ||
85 | static unsigned int real_sample_rate = 0; | 84 | static unsigned int real_sample_rate = 0; |
85 | static unsigned int last_sample_rate = 0; | ||
86 | 86 | ||
87 | static snd_pcm_t *handle = NULL; | 87 | static snd_pcm_t *handle = NULL; |
88 | static snd_pcm_sframes_t buffer_size; | 88 | static snd_pcm_sframes_t buffer_size; |
@@ -148,17 +148,17 @@ static int set_hwparams(snd_pcm_t *handle) | |||
148 | goto error; | 148 | goto error; |
149 | } | 149 | } |
150 | /* set the stream rate */ | 150 | /* set the stream rate */ |
151 | sample_rate = srate = pcm_sampr; | 151 | srate = pcm_sampr; |
152 | err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); | 152 | err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); |
153 | if (err < 0) | 153 | if (err < 0) |
154 | { | 154 | { |
155 | logf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err)); | 155 | logf("Rate %iHz not available for playback: %s\n", pcm_sampr, snd_strerror(err)); |
156 | goto error; | 156 | goto error; |
157 | } | 157 | } |
158 | real_sample_rate = srate; | 158 | real_sample_rate = srate; |
159 | if (real_sample_rate != sample_rate) | 159 | if (real_sample_rate != pcm_sampr) |
160 | { | 160 | { |
161 | logf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, real_sample_rate); | 161 | logf("Rate doesn't match (requested %iHz, get %iHz)\n", pcm_sampr, real_sample_rate); |
162 | err = -EINVAL; | 162 | err = -EINVAL; |
163 | goto error; | 163 | goto error; |
164 | } | 164 | } |
@@ -517,11 +517,13 @@ void pcm_play_unlock(void) | |||
517 | 517 | ||
518 | static void pcm_dma_apply_settings_nolock(void) | 518 | static void pcm_dma_apply_settings_nolock(void) |
519 | { | 519 | { |
520 | logf("PCM DMA Settings %d %d", sample_rate, pcm_sampr); | 520 | logf("PCM DMA Settings %d %d", last_sample_rate, pcm_sampr); |
521 | 521 | ||
522 | if (sample_rate != pcm_sampr) | 522 | if (last_sample_rate != pcm_sampr) |
523 | { | 523 | { |
524 | #ifdef AUDIOHW_MUTE_ON_PAUSE | 524 | last_sample_rate = pcm_sampr; |
525 | |||
526 | #ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE | ||
525 | // XXX AK4450 (xDuoo X3ii) needs to be muted when switching rates. | 527 | // XXX AK4450 (xDuoo X3ii) needs to be muted when switching rates. |
526 | audiohw_mute(true); | 528 | audiohw_mute(true); |
527 | #endif | 529 | #endif |
@@ -531,8 +533,10 @@ static void pcm_dma_apply_settings_nolock(void) | |||
531 | /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ | 533 | /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ |
532 | audiohw_set_frequency(pcm_sampr); | 534 | audiohw_set_frequency(pcm_sampr); |
533 | #endif | 535 | #endif |
534 | 536 | #ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE | |
535 | /* (Will be unmuted by pcm resuming) */ | 537 | audiohw_mute(false); |
538 | #endif | ||
539 | /* (Will be unmuted by pcm resuming) */ | ||
536 | } | 540 | } |
537 | } | 541 | } |
538 | 542 | ||
@@ -560,7 +564,7 @@ void pcm_play_dma_stop(void) | |||
560 | snd_pcm_nonblock(handle, 0); | 564 | snd_pcm_nonblock(handle, 0); |
561 | snd_pcm_drain(handle); | 565 | snd_pcm_drain(handle); |
562 | snd_pcm_nonblock(handle, 1); | 566 | snd_pcm_nonblock(handle, 1); |
563 | sample_rate = 0; | 567 | last_sample_rate = 0; |
564 | #ifdef AUDIOHW_MUTE_ON_PAUSE | 568 | #ifdef AUDIOHW_MUTE_ON_PAUSE |
565 | audiohw_mute(true); | 569 | audiohw_mute(true); |
566 | #endif | 570 | #endif |
@@ -575,6 +579,10 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
575 | pcm_data = addr; | 579 | pcm_data = addr; |
576 | pcm_size = size; | 580 | pcm_size = size; |
577 | 581 | ||
582 | #if !defined(AUDIOHW_MUTE_ON_PAUSE) || !defined(AUDIOHW_MUTE_ON_SRATE_CHANGE) | ||
583 | audiohw_mute(false); | ||
584 | #endif | ||
585 | |||
578 | while (1) | 586 | while (1) |
579 | { | 587 | { |
580 | snd_pcm_state_t state = snd_pcm_state(handle); | 588 | snd_pcm_state_t state = snd_pcm_state(handle); |
@@ -605,14 +613,14 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
605 | int err = async_rw(handle); | 613 | int err = async_rw(handle); |
606 | if (err < 0) { | 614 | if (err < 0) { |
607 | logf("Start error: %s\n", snd_strerror(err)); | 615 | logf("Start error: %s\n", snd_strerror(err)); |
608 | return; | 616 | return; |
609 | } | 617 | } |
610 | #ifdef AUDIOHW_MUTE_ON_PAUSE | 618 | #ifdef AUDIOHW_MUTE_ON_PAUSE |
611 | audiohw_mute(false); | 619 | audiohw_mute(false); |
612 | #endif | 620 | #endif |
613 | if (err == 0) | 621 | if (err == 0) |
614 | return; | 622 | return; |
615 | break; | 623 | break; |
616 | } | 624 | } |
617 | case SND_PCM_STATE_PAUSED: | 625 | case SND_PCM_STATE_PAUSED: |
618 | { /* paused, simply resume */ | 626 | { /* paused, simply resume */ |