summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2020-10-12 09:29:21 -0400
committerSolomon Peachy <pizza@shaftnet.org>2020-10-12 13:40:37 +0000
commit141e91ef1fc5ce6c487988c29c00e57fa6e52fb6 (patch)
tree96a29cb38a833565e099ce3b00016bb653695699
parent9ad30869b86dd827fbbf56a67122d662a51514f5 (diff)
downloadrockbox-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.c7
-rw-r--r--firmware/drivers/audio/rocker_codec.c2
-rw-r--r--firmware/drivers/audio/xduoolinux_codec.c7
-rw-r--r--firmware/export/xduoolinux_codec.h8
-rw-r--r--firmware/target/hosted/pcm-alsa.c42
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
59static int muted = -1;
60
59void audiohw_mute(int mute) 61void 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
75int erosq_get_outputs(void) { 78int erosq_get_outputs(void) {
@@ -95,7 +98,7 @@ int erosq_get_outputs(void) {
95 98
96void erosq_set_output(int ps) 99void 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)
119void audiohw_postinit(void) 122void 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
125void audiohw_close(void) 128void 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
76void audiohw_close(void) 76void 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
58static int muted = -1;
59
58void audiohw_mute(int mute) 60void 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
74int xduoo_get_outputs(void){ 77int xduoo_get_outputs(void){
@@ -102,7 +105,7 @@ int xduoo_get_outputs(void){
102 105
103void xduoo_set_output(int ps) 106void 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
134void audiohw_close(void) 137void 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)
6AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 4, 0) 6AUDIOHW_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
9void audiohw_mute(int mute); 17void audiohw_mute(int mute);
10void xduoo_set_output(int ps); 18void xduoo_set_output(int ps);
11int xduoo_get_outputs(void); 19int 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 *
81typedef short sample_t; 81typedef short sample_t;
82#endif 82#endif
83static const int channels = 2; /* count of channels */ 83static const int channels = 2; /* count of channels */
84static unsigned int sample_rate = 0;
85static unsigned int real_sample_rate = 0; 84static unsigned int real_sample_rate = 0;
85static unsigned int last_sample_rate = 0;
86 86
87static snd_pcm_t *handle = NULL; 87static snd_pcm_t *handle = NULL;
88static snd_pcm_sframes_t buffer_size; 88static 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
518static void pcm_dma_apply_settings_nolock(void) 518static 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 */