summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/debug_menu.c2
-rw-r--r--apps/playback.c5
-rw-r--r--firmware/drivers/audio/rocker_codec.c30
-rw-r--r--firmware/drivers/audio/xduoolinux_codec.c78
-rw-r--r--firmware/export/audiohw.h6
-rw-r--r--firmware/export/config/agptekrocker.h9
-rw-r--r--firmware/export/config/xduoox20.h8
-rw-r--r--firmware/export/config/xduoox3ii.h5
-rw-r--r--firmware/export/rocker_codec.h4
-rw-r--r--firmware/export/system.h2
-rw-r--r--firmware/export/xduoolinux_codec.h3
-rw-r--r--firmware/target/hosted/agptek/debug-agptek.c52
-rw-r--r--firmware/target/hosted/pcm-alsa.c92
-rw-r--r--firmware/target/hosted/pcm-alsa.h6
-rw-r--r--firmware/target/hosted/xduoo/debug-xduoo.c7
15 files changed, 218 insertions, 91 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 3df7e97bce..0d2e125185 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -2525,7 +2525,7 @@ static const struct {
2525 { "Screendump", dbg_screendump }, 2525 { "Screendump", dbg_screendump },
2526#endif 2526#endif
2527 { "Skin Engine RAM usage", dbg_skin_engine }, 2527 { "Skin Engine RAM usage", dbg_skin_engine },
2528#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || (defined(SONY_NWZ_LINUX) && !defined(SIMULATOR)) 2528#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) || defined(AGPTEK_ROCKER) || defined(XDUOO_X3II) || defined(XDUOO_X20) && !defined(SIMULATOR)
2529 { "View HW info", dbg_hw_info }, 2529 { "View HW info", dbg_hw_info },
2530#endif 2530#endif
2531#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 2531#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
diff --git a/apps/playback.c b/apps/playback.c
index 922837af18..c7cfef018a 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -44,6 +44,7 @@
44#include "storage.h" 44#include "storage.h"
45#include "misc.h" 45#include "misc.h"
46#include "settings.h" 46#include "settings.h"
47#include "audiohw.h"
47 48
48#ifdef HAVE_TAGCACHE 49#ifdef HAVE_TAGCACHE
49#include "tagcache.h" 50#include "tagcache.h"
@@ -3850,6 +3851,10 @@ static void audio_change_frequency_callback(unsigned short id, void *data)
3850 static bool starting_playback = false; 3851 static bool starting_playback = false;
3851 struct mp3entry *id3; 3852 struct mp3entry *id3;
3852 3853
3854#ifdef AUDIOHW_HAVE_SET_OUTPUT
3855 audiohw_set_output();
3856#endif
3857
3853 switch (id) 3858 switch (id)
3854 { 3859 {
3855 case PLAYBACK_EVENT_START_PLAYBACK: 3860 case PLAYBACK_EVENT_START_PLAYBACK:
diff --git a/firmware/drivers/audio/rocker_codec.c b/firmware/drivers/audio/rocker_codec.c
index 23541a4ddb..5404ff9561 100644
--- a/firmware/drivers/audio/rocker_codec.c
+++ b/firmware/drivers/audio/rocker_codec.c
@@ -29,6 +29,9 @@
29 29
30static int fd_hw; 30static int fd_hw;
31 31
32static long int vol_l_hw = 255;
33static long int vol_r_hw = 255;
34
32static void hw_open(void) 35static void hw_open(void)
33{ 36{
34 fd_hw = open("/dev/snd/controlC0", O_RDWR); 37 fd_hw = open("/dev/snd/controlC0", O_RDWR);
@@ -41,19 +44,32 @@ static void hw_close(void)
41 close(fd_hw); 44 close(fd_hw);
42} 45}
43 46
44void audiohw_preinit(void) 47void audiohw_mute(int mute)
45{ 48{
46 long int hp = 2; 49 if(mute)
50 {
51 long int ps0 = 0;
52 alsa_controls_set_ints("Output Port Switch", 1, &ps0);
53 }
54 else
55 {
56 long int ps2 = 2;
57 alsa_controls_set_ints("Output Port Switch", 1, &ps2);
58 }
59}
47 60
61void audiohw_preinit(void)
62{
48 alsa_controls_init(); 63 alsa_controls_init();
49 hw_open(); 64 hw_open();
50
51 /* Output port switch set to Headphones */
52 alsa_controls_set_ints("Output Port Switch", 1, &hp);
53} 65}
54 66
55void audiohw_postinit(void) 67void audiohw_postinit(void)
56{ 68{
69 long int hp = 2;
70
71 /* Output port switch set to Headphones */
72 alsa_controls_set_ints("Output Port Switch", 1, &hp);
57} 73}
58 74
59void audiohw_close(void) 75void audiohw_close(void)
@@ -69,8 +85,8 @@ void audiohw_set_frequency(int fsel)
69 85
70void audiohw_set_volume(int vol_l, int vol_r) 86void audiohw_set_volume(int vol_l, int vol_r)
71{ 87{
72 long int vol_l_hw = -vol_l/5; 88 vol_l_hw = -vol_l/5;
73 long int vol_r_hw = -vol_r/5; 89 vol_r_hw = -vol_r/5;
74 90
75 alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw); 91 alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw);
76 alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw); 92 alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw);
diff --git a/firmware/drivers/audio/xduoolinux_codec.c b/firmware/drivers/audio/xduoolinux_codec.c
index 5db4902e5f..eedde1d667 100644
--- a/firmware/drivers/audio/xduoolinux_codec.c
+++ b/firmware/drivers/audio/xduoolinux_codec.c
@@ -29,9 +29,14 @@
29#include "panic.h" 29#include "panic.h"
30#include "sysfs.h" 30#include "sysfs.h"
31#include "alsa-controls.h" 31#include "alsa-controls.h"
32#include "pcm-alsa.h"
32 33
33static int fd_hw; 34static int fd_hw;
34 35
36static long int vol_l_hw = 255;
37static long int vol_r_hw = 255;
38static long int last_ps = 0;
39
35static void hw_open(void) 40static void hw_open(void)
36{ 41{
37 fd_hw = open("/dev/snd/controlC0", O_RDWR); 42 fd_hw = open("/dev/snd/controlC0", O_RDWR);
@@ -44,44 +49,69 @@ static void hw_close(void)
44 close(fd_hw); 49 close(fd_hw);
45} 50}
46 51
47void audiohw_preinit(void) 52void audiohw_mute(int mute)
48{ 53{
49 alsa_controls_init(); 54 if(mute)
50 hw_open(); 55 {
56#if defined(XDUOO_X3II)
57 alsa_controls_set_bool("AK4490 Soft Mute", true);
58#endif
59#if defined(XDUOO_X20)
60 long int ps0 = (last_ps > 1) ? 1 : 2;
61 alsa_controls_set_ints("Output Port Switch", 1, &ps0);
62#endif
63 }
64 else
65 {
66#if defined(XDUOO_X3II)
67 alsa_controls_set_bool("AK4490 Soft Mute", false);
68#endif
69#if defined(XDUOO_X20)
70 alsa_controls_set_ints("Output Port Switch", 1, &last_ps);
71#endif
72 }
51} 73}
52 74
53void audiohw_postinit(void) 75void audiohw_set_output(void)
54{ 76{
55 long int ps = 2; // headset 77 long int ps = 2; // headset
78
56 int status = 0; 79 int status = 0;
57 80
58 const char * const sysfs_lo_switch = "/sys/class/switch/lineout/state"; 81 const char * const sysfs_lo_switch = "/sys/class/switch/lineout/state";
59 const char * const sysfs_hs_switch = "/sys/class/switch/headset/state"; 82 const char * const sysfs_hs_switch = "/sys/class/switch/headset/state";
60#ifdef XDUOO_X20 83#if defined(XDUOO_X20)
61 const char * const sysfs_bal_switch = "/sys/class/switch/balance/state"; 84 const char * const sysfs_bal_switch = "/sys/class/switch/balance/state";
62#endif 85#endif
63 86
64#if defined(XDUOO_X3II)
65 alsa_controls_set_bool("AK4490 Soft Mute", true);
66#endif
67
68 sysfs_get_int(sysfs_lo_switch, &status); 87 sysfs_get_int(sysfs_lo_switch, &status);
69 if (status) ps = 1; // lineout 88 if (status) ps = 1; // lineout
70 89
71 sysfs_get_int(sysfs_hs_switch, &status); 90 sysfs_get_int(sysfs_hs_switch, &status);
72 if (status) ps = 2; // headset 91 if (status) ps = 2; // headset
73 92
74#ifdef XDUOO_X20 93#if defined(XDUOO_X20)
75 sysfs_get_int(sysfs_bal_switch, &status); 94 sysfs_get_int(sysfs_bal_switch, &status);
76 if (status) ps = 3; // balance 95 if (status) ps = 3; // balance
77#endif 96#endif
78 97
79 /* Output port switch */ 98 if (last_ps != ps)
80 alsa_controls_set_ints("Output Port Switch", 1, &ps); 99 {
100 /* Output port switch */
101 last_ps = ps;
102 alsa_controls_set_ints("Output Port Switch", 1, &last_ps);
103 }
104}
81 105
82#if defined(XDUOO_X3II) 106void audiohw_preinit(void)
83 alsa_controls_set_bool("AK4490 Soft Mute", false); 107{
84#endif 108 alsa_controls_init();
109 hw_open();
110}
111
112void audiohw_postinit(void)
113{
114 audiohw_set_output();
85} 115}
86 116
87void audiohw_close(void) 117void audiohw_close(void)
@@ -97,24 +127,24 @@ void audiohw_set_frequency(int fsel)
97 127
98void audiohw_set_volume(int vol_l, int vol_r) 128void audiohw_set_volume(int vol_l, int vol_r)
99{ 129{
100 long int vol_l_hw = -vol_l/5; 130 vol_l_hw = -vol_l/5;
101 long int vol_r_hw = -vol_r/5; 131 vol_r_hw = -vol_r/5;
102 132
103 alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw); 133 alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw);
104 alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw); 134 alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw);
105} 135}
106 136
107void audiohw_set_filter_roll_off(int value) 137void audiohw_set_filter_roll_off(int value)
108{ 138{
109 /* 0 = fast (sharp); 139 /* 0 = Sharp;
110 1 = slow; 140 1 = Slow;
111 2 = fast2 141 2 = Short Sharp
112 3 = slow2 142 3 = Short Slow */
113 4 = NOS ? */
114 long int value_hw = value;
115#if defined(XDUOO_X3II) 143#if defined(XDUOO_X3II)
144 long int value_hw = value;
116 alsa_controls_set_ints("AK4490 Digital Filter", 1, &value_hw); 145 alsa_controls_set_ints("AK4490 Digital Filter", 1, &value_hw);
117#elif defined(XDUOO_X20) 146#elif defined(XDUOO_X20)
147 long int value_hw = value;
118 alsa_controls_set_ints("ES9018_K2M Digital Filter", 1, &value_hw); 148 alsa_controls_set_ints("ES9018_K2M Digital Filter", 1, &value_hw);
119#else 149#else
120 (void)value; 150 (void)value;
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 490c8fc571..34a253e893 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -223,7 +223,7 @@ struct sound_settings_info
223#elif defined(HAVE_ROCKER_CODEC) 223#elif defined(HAVE_ROCKER_CODEC)
224#include "rocker_codec.h" 224#include "rocker_codec.h"
225#elif defined(HAVE_XDUOO_LINUX_CODEC) 225#elif defined(HAVE_XDUOO_LINUX_CODEC)
226#include "rocker_codec.h" 226#include "xduoolinux_codec.h"
227#endif 227#endif
228 228
229/* convert caps into defines */ 229/* convert caps into defines */
@@ -452,6 +452,10 @@ void audiohw_set_volume(int vol_l, int vol_r);
452void audiohw_set_lineout_volume(int vol_l, int vol_r); 452void audiohw_set_lineout_volume(int vol_l, int vol_r);
453#endif 453#endif
454 454
455#ifdef AUDIOHW_HAVE_SET_OUTPUT
456void audiohw_set_output(void);
457#endif
458
455#ifndef AUDIOHW_HAVE_CLIPPING 459#ifndef AUDIOHW_HAVE_CLIPPING
456#if defined(AUDIOHW_HAVE_BASS) || defined(AUDIOHW_HAVE_TREBLE) \ 460#if defined(AUDIOHW_HAVE_BASS) || defined(AUDIOHW_HAVE_TREBLE) \
457 || defined(AUDIOHW_HAVE_EQ) 461 || defined(AUDIOHW_HAVE_EQ)
diff --git a/firmware/export/config/agptekrocker.h b/firmware/export/config/agptekrocker.h
index 31ef904109..f14e65f7e9 100644
--- a/firmware/export/config/agptekrocker.h
+++ b/firmware/export/config/agptekrocker.h
@@ -75,10 +75,6 @@
75/* The number of bytes reserved for loadable plugins */ 75/* The number of bytes reserved for loadable plugins */
76#define PLUGIN_BUFFER_SIZE 0x100000 76#define PLUGIN_BUFFER_SIZE 0x100000
77 77
78
79
80#define HAVE_ROCKER_CODEC
81
82#define HAVE_HEADPHONE_DETECTION 78#define HAVE_HEADPHONE_DETECTION
83 79
84/* KeyPad configuration for plugins */ 80/* KeyPad configuration for plugins */
@@ -108,10 +104,7 @@
108#define CPU_FREQ 1008000000 104#define CPU_FREQ 1008000000
109 105
110/* No special storage */ 106/* No special storage */
111#define CONFIG_STORAGE (STORAGE_HOSTFS)//|STORAGE_SD) 107#define CONFIG_STORAGE STORAGE_HOSTFS
112//#define MULTIDRIVE_DIR "/mnt/sd_0"
113//#define NUM_DRIVES 1
114//#define HAVE_HOTSWAP
115#define HAVE_STORAGE_FLUSH 108#define HAVE_STORAGE_FLUSH
116 109
117/* Battery */ 110/* Battery */
diff --git a/firmware/export/config/xduoox20.h b/firmware/export/config/xduoox20.h
index a61f2c3aa7..5da5ee00f3 100644
--- a/firmware/export/config/xduoox20.h
+++ b/firmware/export/config/xduoox20.h
@@ -63,18 +63,12 @@
63/* define this if you have a real-time clock */ 63/* define this if you have a real-time clock */
64#define CONFIG_RTC APPLICATION 64#define CONFIG_RTC APPLICATION
65 65
66/* Define if the device can wake from an RTC alarm */
67//#define HAVE_RTC_ALARM
68
69/* The number of bytes reserved for loadable codecs */ 66/* The number of bytes reserved for loadable codecs */
70#define CODEC_SIZE 0x80000 67#define CODEC_SIZE 0x80000
71 68
72/* The number of bytes reserved for loadable plugins */ 69/* The number of bytes reserved for loadable plugins */
73#define PLUGIN_BUFFER_SIZE 0x100000 70#define PLUGIN_BUFFER_SIZE 0x100000
74 71
75
76
77
78#define HAVE_HEADPHONE_DETECTION 72#define HAVE_HEADPHONE_DETECTION
79 73
80/* KeyPad configuration for plugins */ 74/* KeyPad configuration for plugins */
@@ -125,6 +119,8 @@
125/* HW codec is flexible */ 119/* HW codec is flexible */
126#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 120#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192
127 121
122#define AUDIOHW_HAVE_SET_OUTPUT
123
128/* Battery */ 124/* Battery */
129#define BATTERY_CAPACITY_DEFAULT 2400 /* default battery capacity */ 125#define BATTERY_CAPACITY_DEFAULT 2400 /* default battery capacity */
130#define BATTERY_CAPACITY_MIN 2400 /* min. capacity selectable */ 126#define BATTERY_CAPACITY_MIN 2400 /* min. capacity selectable */
diff --git a/firmware/export/config/xduoox3ii.h b/firmware/export/config/xduoox3ii.h
index 13072ea3dc..678577f5f4 100644
--- a/firmware/export/config/xduoox3ii.h
+++ b/firmware/export/config/xduoox3ii.h
@@ -60,9 +60,6 @@
60/* define this if you have a real-time clock */ 60/* define this if you have a real-time clock */
61#define CONFIG_RTC APPLICATION 61#define CONFIG_RTC APPLICATION
62 62
63/* Define if the device can wake from an RTC alarm */
64//#define HAVE_RTC_ALARM
65
66/* The number of bytes reserved for loadable codecs */ 63/* The number of bytes reserved for loadable codecs */
67#define CODEC_SIZE 0x80000 64#define CODEC_SIZE 0x80000
68 65
@@ -119,6 +116,8 @@
119/* HW codec is flexible */ 116/* HW codec is flexible */
120#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 117#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192
121 118
119#define AUDIOHW_HAVE_SET_OUTPUT
120
122/* Battery */ 121/* Battery */
123#define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */ 122#define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */
124#define BATTERY_CAPACITY_MIN 2000 /* min. capacity selectable */ 123#define BATTERY_CAPACITY_MIN 2000 /* min. capacity selectable */
diff --git a/firmware/export/rocker_codec.h b/firmware/export/rocker_codec.h
index 366900d717..673b12b494 100644
--- a/firmware/export/rocker_codec.h
+++ b/firmware/export/rocker_codec.h
@@ -2,5 +2,7 @@
2#define __ROCKER_CODEC__ 2#define __ROCKER_CODEC__
3 3
4#define AUDIOHW_CAPS 0 4#define AUDIOHW_CAPS 0
5AUDIOHW_SETTING(VOLUME, "dB", 1, 5, -1020, 0, -300, ) 5AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -127, 0, -30)
6#endif 6#endif
7
8void audiohw_mute(int mute);
diff --git a/firmware/export/system.h b/firmware/export/system.h
index ebeef9c004..cfec235bc4 100644
--- a/firmware/export/system.h
+++ b/firmware/export/system.h
@@ -347,7 +347,7 @@ static inline void cpu_boost_unlock(void)
347#ifndef SIMULATOR 347#ifndef SIMULATOR
348bool dbg_ports(void); 348bool dbg_ports(void);
349#endif 349#endif
350#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) 350#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) || defined(AGPTEK_ROCKER) || defined(XDUOO_X3II) || defined(XDUOO_X20)
351bool dbg_hw_info(void); 351bool dbg_hw_info(void);
352#endif 352#endif
353 353
diff --git a/firmware/export/xduoolinux_codec.h b/firmware/export/xduoolinux_codec.h
index ccd49f09aa..ea0b2988f1 100644
--- a/firmware/export/xduoolinux_codec.h
+++ b/firmware/export/xduoolinux_codec.h
@@ -5,3 +5,6 @@
5AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -127, 0, -30) 5AUDIOHW_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
9void audiohw_mute(int mute);
10void audiohw_set_output(void);
diff --git a/firmware/target/hosted/agptek/debug-agptek.c b/firmware/target/hosted/agptek/debug-agptek.c
index 33f3ac4b97..b4fcb4246b 100644
--- a/firmware/target/hosted/agptek/debug-agptek.c
+++ b/firmware/target/hosted/agptek/debug-agptek.c
@@ -1,6 +1,52 @@
1#include <stdbool.h> 1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2020 by Solomon Peachy
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
2 20
3bool debug_hw_info(void) 21#include "config.h"
22#include "font.h"
23#include "lcd.h"
24#include "kernel.h"
25#include "button.h"
26
27#ifndef BOOTLOADER
28
29#include "pcm-alsa.h"
30
31static int line = 0;
32
33bool dbg_hw_info(void)
4{ 34{
5 return false; 35 int btn = 0;
36
37 lcd_setfont(FONT_SYSFIXED);
38
39 while(btn ^ BUTTON_POWER) {
40 lcd_clear_display();
41 line = 0;
42
43 lcd_putsf(0, line++, "pcm srate: %d", pcm_alsa_get_rate());
44 btn = button_read_device();
45
46 lcd_update();
47 sleep(HZ/16);
48 }
49 return true;
6} 50}
51
52#endif /* !BOOTLOADER */
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c
index 1b8e3c4477..f33b42429c 100644
--- a/firmware/target/hosted/pcm-alsa.c
+++ b/firmware/target/hosted/pcm-alsa.c
@@ -68,7 +68,7 @@
68 * with multple applications running */ 68 * with multple applications running */
69static char device[] = "plughw:0,0"; /* playback device */ 69static char device[] = "plughw:0,0"; /* playback device */
70static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ 70static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */
71#ifdef SONY_NWZ_LINUX 71#if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC)
72/* Sony NWZ must use 32-bit per sample */ 72/* Sony NWZ must use 32-bit per sample */
73static const snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; /* sample format */ 73static const snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; /* sample format */
74typedef long sample_t; 74typedef long sample_t;
@@ -77,6 +77,9 @@ static const snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format *
77typedef short sample_t; 77typedef short sample_t;
78#endif 78#endif
79static const int channels = 2; /* count of channels */ 79static const int channels = 2; /* count of channels */
80static unsigned int sample_rate = 0;
81static unsigned int real_sample_rate = 0;
82
80static snd_pcm_t *handle = NULL; 83static snd_pcm_t *handle = NULL;
81static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */ 84static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */
82static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */ 85static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */
@@ -93,14 +96,13 @@ static char signal_stack[SIGSTKSZ];
93static int recursion; 96static int recursion;
94#endif 97#endif
95 98
96static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate) 99static int set_hwparams(snd_pcm_t *handle)
97{ 100{
98 unsigned int rrate;
99 int err; 101 int err;
102 unsigned int srate;
100 snd_pcm_hw_params_t *params; 103 snd_pcm_hw_params_t *params;
101 snd_pcm_hw_params_malloc(&params); 104 snd_pcm_hw_params_malloc(&params);
102 105
103
104 /* choose all parameters */ 106 /* choose all parameters */
105 err = snd_pcm_hw_params_any(handle, params); 107 err = snd_pcm_hw_params_any(handle, params);
106 if (err < 0) 108 if (err < 0)
@@ -130,16 +132,17 @@ static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate)
130 goto error; 132 goto error;
131 } 133 }
132 /* set the stream rate */ 134 /* set the stream rate */
133 rrate = sample_rate; 135 sample_rate = srate = pcm_sampr;
134 err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); 136 err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
135 if (err < 0) 137 if (err < 0)
136 { 138 {
137 printf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err)); 139 printf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err));
138 goto error; 140 goto error;
139 } 141 }
140 if (rrate != sample_rate) 142 real_sample_rate = srate;
143 if (real_sample_rate != sample_rate)
141 { 144 {
142 printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, rrate); 145 printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, real_sample_rate);
143 err = -EINVAL; 146 err = -EINVAL;
144 goto error; 147 goto error;
145 } 148 }
@@ -159,8 +162,9 @@ static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate)
159 printf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err)); 162 printf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err));
160 goto error; 163 goto error;
161 } 164 }
162 if (!frames) 165
163 frames = malloc(period_size * channels * sizeof(sample_t)); 166 free(frames);
167 frames = calloc(1, period_size * channels * sizeof(sample_t));
164 168
165 /* write the parameters to device */ 169 /* write the parameters to device */
166 err = snd_pcm_hw_params(handle, params); 170 err = snd_pcm_hw_params(handle, params);
@@ -229,26 +233,37 @@ error:
229 * and add 48dB to the input volume. We cannot go lower -43dB because several 233 * and add 48dB to the input volume. We cannot go lower -43dB because several
230 * values between -48dB and -43dB would require a fractional multiplier, which is 234 * values between -48dB and -43dB would require a fractional multiplier, which is
231 * stupid to implement for such very low volume. */ 235 * stupid to implement for such very low volume. */
232static int dig_vol_mult = 2 ^ 16; /* multiplicative factor to apply to each sample */ 236static int dig_vol_mult_l = 2 ^ 16; /* multiplicative factor to apply to each sample */
237static int dig_vol_mult_r = 2 ^ 16; /* multiplicative factor to apply to each sample */
233 238
234void pcm_alsa_set_digital_volume(int vol_db) 239void pcm_alsa_set_digital_volume(int vol_db_l, int vol_db_r)
235{ 240{
236 if(vol_db > 0 || vol_db < -43) 241 if(vol_db_l > 0 || vol_db_r > 0 || vol_db_l < -43 || vol_db_r < -43)
237 panicf("invalid pcm alsa volume"); 242 panicf("invalid pcm alsa volume");
238 if(format != SND_PCM_FORMAT_S32_LE) 243 if(format != SND_PCM_FORMAT_S32_LE)
239 panicf("this function assumes 32-bit sample size"); 244 panicf("this function assumes 32-bit sample size");
240 vol_db += 48; /* -42dB .. 0dB => 5dB .. 48dB */ 245 vol_db_l += 48; /* -42dB .. 0dB => 5dB .. 48dB */
246 vol_db_r += 48; /* -42dB .. 0dB => 5dB .. 48dB */
241 /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0 247 /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0
242 * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */ 248 * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */
243 int vol_shift = vol_db / 3; 249 int vol_shift_l = vol_db_l / 3;
244 int r = vol_db % 3; 250 int vol_shift_r = vol_db_r / 3;
245 if(r == 0) 251 int r_l = vol_db_l % 3;
246 dig_vol_mult = 1 << vol_shift; 252 int r_r = vol_db_r % 3;
247 else if(r == 1) 253 if(r_l == 0)
248 dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 2); 254 dig_vol_mult_l = 1 << vol_shift_l;
255 else if(r_l == 1)
256 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 2);
257 else
258 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 1);
259 printf("l: %d dB -> factor = %d\n", vol_db_l - 48, dig_vol_mult_l);
260 if(r_r == 0)
261 dig_vol_mult_r = 1 << vol_shift_r;
262 else if(r_r == 1)
263 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 2);
249 else 264 else
250 dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 1); 265 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 1);
251 printf("%d dB -> factor = %d\n", vol_db - 48, dig_vol_mult); 266 printf("r: %d dB -> factor = %d\n", vol_db_r - 48, dig_vol_mult_r);
252} 267}
253 268
254/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ 269/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */
@@ -279,8 +294,11 @@ static bool fill_frames(void)
279 * sample by some value so the sound is not too low */ 294 * sample by some value so the sound is not too low */
280 const short *pcm_ptr = pcm_data; 295 const short *pcm_ptr = pcm_data;
281 sample_t *sample_ptr = &frames[2*(period_size-frames_left)]; 296 sample_t *sample_ptr = &frames[2*(period_size-frames_left)];
282 for (int i = 0; i < copy_n*2; i++) 297 for (int i = 0; i < copy_n; i++)
283 *sample_ptr++ = *pcm_ptr++ * dig_vol_mult; 298 {
299 *sample_ptr++ = *pcm_ptr++ * dig_vol_mult_l;
300 *sample_ptr++ = *pcm_ptr++ * dig_vol_mult_r;
301 }
284 } 302 }
285 else 303 else
286 { 304 {
@@ -378,7 +396,7 @@ static int async_rw(snd_pcm_t *handle)
378 396
379 /* fill buffer with silence to initiate playback without noisy click */ 397 /* fill buffer with silence to initiate playback without noisy click */
380 sample_size = buffer_size; 398 sample_size = buffer_size;
381 samples = malloc(sample_size * channels * sizeof(sample_t)); 399 samples = calloc(1, sample_size * channels * sizeof(sample_t));
382 400
383 snd_pcm_format_set_silence(format, samples, sample_size); 401 snd_pcm_format_set_silence(format, samples, sample_size);
384 err = snd_pcm_writei(handle, samples, sample_size); 402 err = snd_pcm_writei(handle, samples, sample_size);
@@ -428,7 +446,7 @@ void pcm_play_dma_init(void)
428 if ((err = snd_pcm_nonblock(handle, 1))) 446 if ((err = snd_pcm_nonblock(handle, 1)))
429 panicf("Could not set non-block mode: %s\n", snd_strerror(err)); 447 panicf("Could not set non-block mode: %s\n", snd_strerror(err));
430 448
431 if ((err = set_hwparams(handle, pcm_sampr)) < 0) 449 if ((err = set_hwparams(handle)) < 0)
432 { 450 {
433 panicf("Setting of hwparams failed: %s\n", snd_strerror(err)); 451 panicf("Setting of hwparams failed: %s\n", snd_strerror(err));
434 } 452 }
@@ -473,15 +491,28 @@ void pcm_play_unlock(void)
473#endif 491#endif
474} 492}
475 493
494#if defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_ROCKER_CODEC)
495static void pcm_dma_apply_settings_nolock(void)
496{
497 if (sample_rate != pcm_sampr)
498 {
499 audiohw_mute(true);
500 snd_pcm_drop(handle);
501 set_hwparams(handle);
502 audiohw_mute(false);
503 }
504}
505#else
476static void pcm_dma_apply_settings_nolock(void) 506static void pcm_dma_apply_settings_nolock(void)
477{ 507{
478 snd_pcm_drop(handle); 508 snd_pcm_drop(handle);
479 set_hwparams(handle, pcm_sampr); 509 set_hwparams(handle);
480#if defined(HAVE_NWZ_LINUX_CODEC) 510#if defined(HAVE_NWZ_LINUX_CODEC)
481 /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ 511 /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */
482 audiohw_set_frequency(pcm_sampr); 512 audiohw_set_frequency(pcm_sampr);
483#endif 513#endif
484} 514}
515#endif
485 516
486void pcm_dma_apply_settings(void) 517void pcm_dma_apply_settings(void)
487{ 518{
@@ -571,11 +602,16 @@ void pcm_play_dma_postinit(void)
571 audiohw_postinit(); 602 audiohw_postinit();
572} 603}
573 604
574
575void pcm_set_mixer_volume(int volume) 605void pcm_set_mixer_volume(int volume)
576{ 606{
577 (void)volume; 607 (void)volume;
578} 608}
609
610int pcm_alsa_get_rate(void)
611{
612 return real_sample_rate;
613}
614
579#ifdef HAVE_RECORDING 615#ifdef HAVE_RECORDING
580void pcm_rec_lock(void) 616void pcm_rec_lock(void)
581{ 617{
diff --git a/firmware/target/hosted/pcm-alsa.h b/firmware/target/hosted/pcm-alsa.h
index a2514494de..b746f0d259 100644
--- a/firmware/target/hosted/pcm-alsa.h
+++ b/firmware/target/hosted/pcm-alsa.h
@@ -22,10 +22,12 @@
22 22
23#include <config.h> 23#include <config.h>
24 24
25#ifdef SONY_NWZ_LINUX 25#if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC)
26/* Set the PCM volume in dB: each sample with have this volume applied digitally 26/* Set the PCM volume in dB: each sample with have this volume applied digitally
27 * before being sent to ALSA. Volume must satisfy -43 <= dB <= 0 */ 27 * before being sent to ALSA. Volume must satisfy -43 <= dB <= 0 */
28void pcm_alsa_set_digital_volume(int vol_db); 28void pcm_alsa_set_digital_volume(int vol_db_l, int vol_db_r);
29#endif 29#endif
30 30
31int pcm_alsa_get_rate(void);
32
31#endif /* __PCM_ALSA_RB_H__ */ 33#endif /* __PCM_ALSA_RB_H__ */
diff --git a/firmware/target/hosted/xduoo/debug-xduoo.c b/firmware/target/hosted/xduoo/debug-xduoo.c
index 33f3ac4b97..9812b8f8b9 100644
--- a/firmware/target/hosted/xduoo/debug-xduoo.c
+++ b/firmware/target/hosted/xduoo/debug-xduoo.c
@@ -1,6 +1 @@
1#include <stdbool.h> #include "../agptek/debug-agptek.c"
2
3bool debug_hw_info(void)
4{
5 return false;
6}