From ea0d8d7b8bb07f688eed191b1300009e436e3091 Mon Sep 17 00:00:00 2001 From: Mike Engel Date: Wed, 27 Apr 2022 10:14:42 +0200 Subject: [PATCH] pulseaudio: add alsa and pulseaudio support for the CCMP15 Signed-off-by: Mike Engel --- .../alsa-state/alsa-state.bbappend | 2 +- .../alsa-state/alsa-state/ccmp15/asound.conf | 19 +- .../alsa-state/alsa-state/ccmp15/asound.state | 1160 +++++++++++++++-- ...conf-for-multichannel-support-in-imx.patch | 221 ++++ ...atus-fix-the-return-value-regression.patch | 46 + ...gin-status-revert-the-recent-changes.patch | 34 + ...ak4458-conf-for-multichannel-support.patch | 123 ++ ...006-add-conf-for-iMX-XCVR-sound-card.patch | 89 ++ .../alsa/alsa-lib_%.bbappend | 8 + .../recipes-multimedia/alsa/card-detect.bb | 28 + .../alsa/card-detect/card-detect.c | 47 + .../pulseaudio/pulseaudio_%.bbappend | 6 +- .../0001-tinycompress-Add-id3-decoding.patch | 1001 ++++++++++++++ .../0002-cplay-Support-wave-file.patch | 221 ++++ .../0003-cplay-Add-pause-feature.patch | 147 +++ ...ss-NULL-buffer-with-0-size-to-driver.patch | 41 + .../0005-cplay-Support-aac-streams.patch | 252 ++++ .../tinycompress/tinycompress_1.1.6.bb | 19 + 18 files changed, 3343 insertions(+), 121 deletions(-) create mode 100755 meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-add-conf-for-multichannel-support-in-imx.patch create mode 100644 meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-pcm-plugin-status-fix-the-return-value-regression.patch create mode 100644 meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0002-pcm-plugin-status-revert-the-recent-changes.patch create mode 100644 meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0005-add-ak4458-conf-for-multichannel-support.patch create mode 100755 meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0006-add-conf-for-iMX-XCVR-sound-card.patch create mode 100644 meta-digi-dey/recipes-multimedia/alsa/alsa-lib_%.bbappend create mode 100644 meta-digi-dey/recipes-multimedia/alsa/card-detect.bb create mode 100644 meta-digi-dey/recipes-multimedia/alsa/card-detect/card-detect.c create mode 100755 meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch create mode 100755 meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch create mode 100755 meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch create mode 100755 meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch create mode 100755 meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch create mode 100644 meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress_1.1.6.bb diff --git a/meta-digi-arm/recipes-bsp/alsa-state/alsa-state.bbappend b/meta-digi-arm/recipes-bsp/alsa-state/alsa-state.bbappend index f4654b75f..5f499507f 100644 --- a/meta-digi-arm/recipes-bsp/alsa-state/alsa-state.bbappend +++ b/meta-digi-arm/recipes-bsp/alsa-state/alsa-state.bbappend @@ -1,4 +1,4 @@ -# Copyright (C) 2013-2020 Digi International. +# Copyright (C) 2013-2022 Digi International. FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:" diff --git a/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.conf b/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.conf index 16a72be22..70ea91c3a 100644 --- a/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.conf +++ b/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.conf @@ -1,18 +1,9 @@ -pcm.!playback_codec { +pcm.stm32max98088 { type hw - card CCMP15DVK - device 0 + card 0 } - -pcm.!record_codec { +ctl.stm32max98088 { type hw - card CCMP15DVK - device 1 + card 0 } - -pcm.!playback_hdmi { - type hw - card CCMP15DVK - device 2 -} - +ctl.!default stm32max98088 diff --git a/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.state b/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.state index 7d5c041c8..dd7d64b01 100644 --- a/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.state +++ b/meta-digi-arm/recipes-bsp/alsa-state/alsa-state/ccmp15/asound.state @@ -1,23 +1,55 @@ -state.STM32MP15DK { +state.stm32max98088 { control.1 { iface MIXER - name 'PCM Playback Volume' - value.0 63 - value.1 63 + name 'Headphone Volume' + value.0 18 + value.1 18 comment { access 'read write' type INTEGER count 2 - range '0 - 127' - dbmin -5150 - dbmax 1200 - dbvalue.0 -2000 - dbvalue.1 -2000 + range '0 - 31' + dbmin -6700 + dbmax 300 + dbvalue.0 -1100 + dbvalue.1 -1100 } } control.2 { iface MIXER - name 'PCM Playback Switch' + name 'Speaker Volume' + value.0 16 + value.1 16 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 31' + dbmin -6200 + dbmax 800 + dbvalue.0 -1000 + dbvalue.1 -1000 + } + } + control.3 { + iface MIXER + name 'Receiver Volume' + value.0 16 + value.1 16 + comment { + access 'read write' + type INTEGER + count 2 + range '0 - 31' + dbmin -6200 + dbmax 800 + dbvalue.0 -1000 + dbvalue.1 -1000 + } + } + control.4 { + iface MIXER + name 'Headphone Switch' value.0 true value.1 true comment { @@ -26,43 +58,11 @@ state.STM32MP15DK { count 2 } } - control.3 { - iface MIXER - name 'Analog Playback Volume' - value.0 204 - value.1 204 - comment { - access 'read write' - type INTEGER - count 2 - range '0 - 228' - dbmin -10200 - dbmax 1200 - dbvalue.0 0 - dbvalue.1 0 - } - } - control.4 { - iface MIXER - name 'ADC Mixer Volume' - value.0 103 - value.1 103 - comment { - access 'read write' - type INTEGER - count 2 - range '0 - 127' - dbmin -5150 - dbmax 1200 - dbvalue.0 0 - dbvalue.1 0 - } - } control.5 { iface MIXER - name 'ADC Mixer Switch' - value.0 false - value.1 false + name 'Speaker Switch' + value.0 true + value.1 true comment { access 'read write' type BOOLEAN @@ -71,7 +71,134 @@ state.STM32MP15DK { } control.6 { iface MIXER - name 'Playback Deemphasis Switch' + name 'Receiver Switch' + value.0 true + value.1 true + comment { + access 'read write' + type BOOLEAN + count 2 + } + } + control.7 { + iface MIXER + name 'MIC1 Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + } + } + control.8 { + iface MIXER + name 'MIC2 Volume' + value 15 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 31' + } + } + control.9 { + iface MIXER + name 'MIC1 Boost Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 2' + dbmin 0 + dbmax 3000 + dbvalue.0 0 + } + } + control.10 { + iface MIXER + name 'MIC2 Boost Volume' + value 1 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 2' + dbmin 0 + dbmax 3000 + dbvalue.0 2000 + } + } + control.11 { + iface MIXER + name 'INA Volume' + value 4 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.12 { + iface MIXER + name 'INB Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.13 { + iface MIXER + name 'ADCL Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.14 { + iface MIXER + name 'ADCR Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.15 { + iface MIXER + name 'ADCL Boost Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 3' + } + } + control.16 { + iface MIXER + name 'ADCR Boost Volume' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 3' + } + } + control.17 { + iface MIXER + name 'EQ1 Switch' value false comment { access 'read write' @@ -79,9 +206,218 @@ state.STM32MP15DK { count 1 } } - control.7 { + control.18 { iface MIXER - name 'Auto-Mute Switch' + name 'EQ2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.19 { + iface MIXER + name 'EX Limiter Mode' + value Off + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Off + item.1 '100Hz' + item.2 '400Hz' + item.3 '600Hz' + item.4 '800Hz' + item.5 '1000Hz' + item.6 '200-400Hz' + item.7 '400-600Hz' + item.8 '400-800Hz' + } + } + control.20 { + iface MIXER + name 'EX Limiter Threshold' + value '0.6' + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 '0.6' + item.1 '1.2' + item.2 '1.8' + item.3 '2.4' + item.4 '3.0' + item.5 '3.6' + item.6 '4.2' + item.7 '4.8' + } + } + control.21 { + iface MIXER + name 'DAI1 Filter Mode' + value Music + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Voice + item.1 Music + } + } + control.22 { + iface MIXER + name 'DAI1 DAC Filter' + value Off + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Off + item.1 'fc=258/fs=16k' + item.2 'fc=500/fs=16k' + item.3 'fc=258/fs=8k' + item.4 'fc=500/fs=8k' + item.5 'fc=200' + } + } + control.23 { + iface MIXER + name 'DAI1 ADC Filter' + value Off + comment { + access 'read write' + type ENUMERATED + count 1 + item.0 Off + item.1 'fc=258/fs=16k' + item.2 'fc=500/fs=16k' + item.3 'fc=258/fs=8k' + item.4 'fc=500/fs=8k' + item.5 'fc=200' + } + } + control.24 { + iface MIXER + name 'DAI2 DC Block Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.25 { + iface MIXER + name 'ALC Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.26 { + iface MIXER + name 'ALC Threshold' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.27 { + iface MIXER + name 'ALC Multiband' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.28 { + iface MIXER + name 'ALC Release Time' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.29 { + iface MIXER + name 'PWR Limiter Threshold' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.30 { + iface MIXER + name 'PWR Limiter Weight' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.31 { + iface MIXER + name 'PWR Limiter Time1' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.32 { + iface MIXER + name 'PWR Limiter Time2' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.33 { + iface MIXER + name 'THD Limiter Threshold' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 15' + } + } + control.34 { + iface MIXER + name 'THD Limiter Time' + value 0 + comment { + access 'read write' + type INTEGER + count 1 + range '0 - 7' + } + } + control.35 { + iface MIXER + name 'REC Output Mode' value true comment { access 'read write' @@ -89,9 +425,9 @@ state.STM32MP15DK { count 1 } } - control.8 { + control.36 { iface MIXER - name 'Soft Ramp Switch' + name 'Right ADC Mixer MIC1 Switch' value false comment { access 'read write' @@ -99,100 +435,714 @@ state.STM32MP15DK { count 1 } } - control.9 { + control.37 { iface MIXER - name 'Zero Cross Switch' - value 0 + name 'Right ADC Mixer MIC2 Switch' + value true comment { access 'read write' - type INTEGER + type BOOLEAN count 1 - range '0 - 0' } } - control.10 { + control.38 { iface MIXER - name 'Mic Boost Volume' - value.0 1 - value.1 1 + name 'Right ADC Mixer INA1 Switch' + value false comment { access 'read write' - type INTEGER - count 2 - range '0 - 1' - dbmin 1600 - dbmax 3200 - dbvalue.0 3200 - dbvalue.1 3200 + type BOOLEAN + count 1 } } - control.11 { + control.39 { iface MIXER - name 'Bass Volume' - value 7 + name 'Right ADC Mixer INA2 Switch' + value true comment { access 'read write' - type INTEGER + type BOOLEAN count 1 - range '0 - 15' - dbmin -1050 - dbmax 1200 - dbvalue.0 0 } } - control.12 { + control.40 { iface MIXER - name 'Treble Volume' - value 7 + name 'Right ADC Mixer INB1 Switch' + value false comment { access 'read write' - type INTEGER + type BOOLEAN count 1 - range '0 - 15' - dbmin -1050 - dbmax 1200 - dbvalue.0 0 } } - control.13 { + control.41 { iface MIXER - name 'PCM channel mixer' - value 'L R' + name 'Right ADC Mixer INB2 Switch' + value false comment { access 'read write' - type ENUMERATED + type BOOLEAN count 1 - item.0 'L R' - item.1 L+R - item.2 'R L' } } - control.14 { + control.42 { iface MIXER - name 'PGA-ADC Mux Left' - value 'MIC+preamp Left' + name 'Left ADC Mixer MIC1 Switch' + value false comment { access 'read write' - type ENUMERATED + type BOOLEAN count 1 - item.0 'AIN1 Left' - item.1 'AIN2 Left' - item.2 'MIC Left' - item.3 'MIC+preamp Left' } } - control.15 { + control.43 { iface MIXER - name 'PGA-ADC Mux Right' - value 'AIN1 Right' + name 'Left ADC Mixer MIC2 Switch' + value true comment { access 'read write' - type ENUMERATED + type BOOLEAN + count 1 + } + } + control.44 { + iface MIXER + name 'Left ADC Mixer INA1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.45 { + iface MIXER + name 'Left ADC Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.46 { + iface MIXER + name 'Left ADC Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.47 { + iface MIXER + name 'Left ADC Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.48 { + iface MIXER + name 'Right REC Mixer Left DAC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.49 { + iface MIXER + name 'Right REC Mixer Right DAC1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.50 { + iface MIXER + name 'Right REC Mixer Left DAC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.51 { + iface MIXER + name 'Right REC Mixer Right DAC2 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.52 { + iface MIXER + name 'Right REC Mixer MIC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.53 { + iface MIXER + name 'Right REC Mixer MIC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.54 { + iface MIXER + name 'Right REC Mixer INA1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.55 { + iface MIXER + name 'Right REC Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.56 { + iface MIXER + name 'Right REC Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.57 { + iface MIXER + name 'Right REC Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.58 { + iface MIXER + name 'Left REC Mixer Left DAC1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.59 { + iface MIXER + name 'Left REC Mixer Right DAC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.60 { + iface MIXER + name 'Left REC Mixer Left DAC2 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.61 { + iface MIXER + name 'Left REC Mixer Right DAC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.62 { + iface MIXER + name 'Left REC Mixer MIC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.63 { + iface MIXER + name 'Left REC Mixer MIC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.64 { + iface MIXER + name 'Left REC Mixer INA1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.65 { + iface MIXER + name 'Left REC Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.66 { + iface MIXER + name 'Left REC Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.67 { + iface MIXER + name 'Left REC Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.68 { + iface MIXER + name 'Right SPK Mixer Left DAC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.69 { + iface MIXER + name 'Right SPK Mixer Right DAC1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.70 { + iface MIXER + name 'Right SPK Mixer Left DAC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.71 { + iface MIXER + name 'Right SPK Mixer Right DAC2 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.72 { + iface MIXER + name 'Right SPK Mixer MIC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.73 { + iface MIXER + name 'Right SPK Mixer MIC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.74 { + iface MIXER + name 'Right SPK Mixer INA1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.75 { + iface MIXER + name 'Right SPK Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.76 { + iface MIXER + name 'Right SPK Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.77 { + iface MIXER + name 'Right SPK Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.78 { + iface MIXER + name 'Left SPK Mixer Left DAC1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.79 { + iface MIXER + name 'Left SPK Mixer Right DAC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.80 { + iface MIXER + name 'Left SPK Mixer Left DAC2 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.81 { + iface MIXER + name 'Left SPK Mixer Right DAC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.82 { + iface MIXER + name 'Left SPK Mixer MIC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.83 { + iface MIXER + name 'Left SPK Mixer MIC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.84 { + iface MIXER + name 'Left SPK Mixer INA1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.85 { + iface MIXER + name 'Left SPK Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.86 { + iface MIXER + name 'Left SPK Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.87 { + iface MIXER + name 'Left SPK Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.88 { + iface MIXER + name 'Right HP Mixer Left DAC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.89 { + iface MIXER + name 'Right HP Mixer Right DAC1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.90 { + iface MIXER + name 'Right HP Mixer Left DAC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.91 { + iface MIXER + name 'Right HP Mixer Right DAC2 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.92 { + iface MIXER + name 'Right HP Mixer MIC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.93 { + iface MIXER + name 'Right HP Mixer MIC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.94 { + iface MIXER + name 'Right HP Mixer INA1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.95 { + iface MIXER + name 'Right HP Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.96 { + iface MIXER + name 'Right HP Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.97 { + iface MIXER + name 'Right HP Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.98 { + iface MIXER + name 'Left HP Mixer Left DAC1 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.99 { + iface MIXER + name 'Left HP Mixer Right DAC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.100 { + iface MIXER + name 'Left HP Mixer Left DAC2 Switch' + value true + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.101 { + iface MIXER + name 'Left HP Mixer Right DAC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.102 { + iface MIXER + name 'Left HP Mixer MIC1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.103 { + iface MIXER + name 'Left HP Mixer MIC2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.104 { + iface MIXER + name 'Left HP Mixer INA1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.105 { + iface MIXER + name 'Left HP Mixer INA2 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.106 { + iface MIXER + name 'Left HP Mixer INB1 Switch' + value false + comment { + access 'read write' + type BOOLEAN + count 1 + } + } + control.107 { + iface MIXER + name 'Left HP Mixer INB2 Switch' + value false + comment { + access 'read write' + type BOOLEAN count 1 - item.0 'AIN1 Right' - item.1 'AIN2 Right' - item.2 'MIC Right' - item.3 'MIC+preamp Right' } } } diff --git a/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-add-conf-for-multichannel-support-in-imx.patch b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-add-conf-for-multichannel-support-in-imx.patch new file mode 100755 index 000000000..87c0311ed --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-add-conf-for-multichannel-support-in-imx.patch @@ -0,0 +1,221 @@ +From cc06048dcd722049f92ab17958760bd798fb4781 Mon Sep 17 00:00:00 2001 +From: Shengjiu Wang +Date: Thu, 5 Jun 2014 17:37:47 +0800 +Subject: [PATCH] add conf for multichannel support in imx + +Upstream Status: Inappropriate [platform specific] + +Signed-off-by: Shengjiu Wang +--- + src/conf/cards/CS42888.conf | 94 ++++++++++++++++++++++++++++++++++++++++++++ + src/conf/cards/IMX-HDMI.conf | 67 +++++++++++++++++++++++++++++++ + src/conf/cards/Makefile.am | 4 +- + src/conf/cards/aliases.conf | 2 + + 4 files changed, 166 insertions(+), 1 deletion(-) + create mode 100644 src/conf/cards/CS42888.conf + create mode 100644 src/conf/cards/IMX-HDMI.conf + +diff --git a/src/conf/cards/CS42888.conf b/src/conf/cards/CS42888.conf +new file mode 100644 +index 0000000..671a284 +--- /dev/null ++++ b/src/conf/cards/CS42888.conf +@@ -0,0 +1,94 @@ ++# ++# Configuration for the CS42888 chip ++# ++ ++# default with dmix & dsnoop ++CS42888.pcm.default { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type asym ++ playback.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] ++ } ++ } ++ capture.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] ++ } ++ } ++} ++ ++ ++ ++CS42888.pcm.surround40.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 4 ++ ttable.0.0 1 ++ ttable.1.2 1 ++ ttable.2.1 1 ++ ttable.3.3 1 ++} ++ ++ ++ ++ ++ ++ ++CS42888.pcm.surround51.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 6 ++ ttable.0.0 1 ++ ttable.1.3 1 ++ ttable.2.1 1 ++ ttable.3.4 1 ++ ttable.4.2 1 ++ ttable.5.5 1 ++} ++ ++ ++ ++CS42888.pcm.surround71.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 8 ++ ttable.0.0 1 ++ ttable.1.4 1 ++ ttable.2.1 1 ++ ttable.3.5 1 ++ ttable.4.2 1 ++ ttable.5.6 1 ++ ttable.6.3 1 ++ ttable.7.7 1 ++} ++ ++# vim: ft=alsaconf +diff --git a/src/conf/cards/IMX-HDMI.conf b/src/conf/cards/IMX-HDMI.conf +new file mode 100644 +index 0000000..a51509e +--- /dev/null ++++ b/src/conf/cards/IMX-HDMI.conf +@@ -0,0 +1,67 @@ ++# ++# Configuration for the CS42888 chip ++# ++ ++# default with dmix & dsnoop ++IMX-HDMI.pcm.default { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type asym ++ playback.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] ++ } ++ } ++ capture.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] ++ } ++ } ++} ++ ++ ++ ++IMX-HDMI.pcm.surround40.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type hw ++ card $CARD ++ channels 4 ++} ++ ++ ++ ++ ++ ++ ++IMX-HDMI.pcm.surround51.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type hw ++ card $CARD ++ channels 6 ++} ++ ++ ++ ++IMX-HDMI.pcm.surround71.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type hw ++ card $CARD ++ channels 8 ++} ++ ++# vim: ft=alsaconf +diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am +index 00999f0..fbf0697 100644 +--- a/src/conf/cards/Makefile.am ++++ b/src/conf/cards/Makefile.am +@@ -58,7 +58,9 @@ cfg_files = aliases.conf \ + VIA8237.conf \ + VX222.conf \ + VXPocket.conf \ +- VXPocket440.conf ++ VXPocket440.conf \ ++ CS42888.conf \ ++ IMX-HDMI.conf + + if BUILD_ALISP + cfg_files += aliases.alisp +diff --git a/src/conf/cards/aliases.conf b/src/conf/cards/aliases.conf +index 18a920f..2c422ee 100644 +--- a/src/conf/cards/aliases.conf ++++ b/src/conf/cards/aliases.conf +@@ -57,6 +57,8 @@ CMI8786 cards.CMI8788 + CMI8787 cards.CMI8788 + pistachio cards.pistachio-card + VC4-HDMI cards.vc4-hdmi ++imx-cs42888 cards.CS42888 ++imx-hdmi-soc cards.IMX-HDMI + + + +-- +2.7.4 + diff --git a/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-pcm-plugin-status-fix-the-return-value-regression.patch b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-pcm-plugin-status-fix-the-return-value-regression.patch new file mode 100644 index 000000000..3a7aa772d --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0001-pcm-plugin-status-fix-the-return-value-regression.patch @@ -0,0 +1,46 @@ +From 67be50a9d95c8659d4821d0cd8c228e4f57b2c32 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Wed, 30 Dec 2020 09:31:10 +0100 +Subject: [PATCH 1/2] pcm: plugin status - fix the return value (regression) + +The snd_pcm_plugin_avail_update() error code in snd_pcm_plugin_status() +should not be reported to the caller. The state errors can be determined +using the state member in the status structure. + +Fixes: 4f90392f07e ("pcm: fix the snd_pcm_plugin_status() avail and delay fields") +BugLink: https://github.com/alsa-project/alsa-lib/issues/107 +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_plugin.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index 5739cfc2eb07..76a524fa801d 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -541,19 +541,17 @@ static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) + static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + { + snd_pcm_plugin_t *plugin = pcm->private_data; +- snd_pcm_sframes_t err, avail; ++ snd_pcm_sframes_t err; + + /* sync with the latest hw and appl ptrs */ +- avail = snd_pcm_plugin_avail_update(pcm); +- if (avail < 0) +- return avail; ++ snd_pcm_plugin_avail_update(pcm); + + err = snd_pcm_status(plugin->gen.slave, status); + if (err < 0) + return err; + status->appl_ptr = *pcm->appl.ptr; + status->hw_ptr = *pcm->hw.ptr; +- status->avail = avail; ++ status->avail = snd_pcm_mmap_avail(pcm); + status->delay = snd_pcm_mmap_delay(pcm); + return 0; + } +-- +2.27.0 + diff --git a/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0002-pcm-plugin-status-revert-the-recent-changes.patch b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0002-pcm-plugin-status-revert-the-recent-changes.patch new file mode 100644 index 000000000..4d91b20ec --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0002-pcm-plugin-status-revert-the-recent-changes.patch @@ -0,0 +1,34 @@ +From eeea1c8c352e54908f464e8dfd7a06b0f7ce0e6e Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Sun, 3 Jan 2021 16:16:10 +0100 +Subject: [PATCH 2/2] pcm: plugin status - revert the recent changes + +It's no reason to sync the avail/delay fields using the mirrored +buffer pointers. The slave information must be valid. + +The original report probably tries to fix something for +the specific plugin. Revert all changes. + +Fixes: afe6ff3b33e ("pcm: plugin status - fix the return value (regression)") +Fixes: 4f90392f07e ("pcm: fix the snd_pcm_plugin_status() avail and delay fields") +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_plugin.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index 76a524fa801d..ea60eb98986e 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -551,8 +551,6 @@ static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + return err; + status->appl_ptr = *pcm->appl.ptr; + status->hw_ptr = *pcm->hw.ptr; +- status->avail = snd_pcm_mmap_avail(pcm); +- status->delay = snd_pcm_mmap_delay(pcm); + return 0; + } + +-- +2.27.0 + diff --git a/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0005-add-ak4458-conf-for-multichannel-support.patch b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0005-add-ak4458-conf-for-multichannel-support.patch new file mode 100644 index 000000000..98fca311d --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0005-add-ak4458-conf-for-multichannel-support.patch @@ -0,0 +1,123 @@ +From 1641ce8c724018365d7fa598f9a70c6492e7c271 Mon Sep 17 00:00:00 2001 +From: Shengjiu Wang +Date: Wed, 31 Jan 2018 15:06:53 +0800 +Subject: [PATCH] add ak4458 conf for multichannel support + +one limitation is that ALSA and pulseaudio only support +maximum 8 channels, but ak4458 may support 16 channels + +Upstream-Status: Inappropriate [i.MX specific] + +Signed-off-by: Shengjiu Wang +--- + src/conf/cards/AK4458.conf | 74 +++++++++++++++++++++++++++++++++++++++++++++ + src/conf/cards/Makefile.am | 3 +- + src/conf/cards/aliases.conf | 1 + + 3 files changed, 77 insertions(+), 1 deletion(-) + create mode 100644 src/conf/cards/AK4458.conf + +Index: alsa-lib-1.1.6/src/conf/cards/AK4458.conf +=================================================================== +--- /dev/null ++++ alsa-lib-1.1.6/src/conf/cards/AK4458.conf +@@ -0,0 +1,74 @@ ++# ++# Configuration for the AK4458 chip ++# ++ ++# default with dmix & dsnoop ++AK4458.pcm.default { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type asym ++ playback.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dmix:" $CARD ",FORMAT=S32_LE" ] ++ } ++ } ++ capture.pcm { ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "dsnoop:" $CARD ",FORMAT=S32_LE" ] ++ } ++ } ++} ++ ++ ++ ++AK4458.pcm.surround40.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 4 ++} ++ ++ ++ ++ ++ ++ ++AK4458.pcm.surround51.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 6 ++} ++ ++ ++ ++AK4458.pcm.surround71.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 8 ++} +Index: alsa-lib-1.1.6/src/conf/cards/Makefile.am +=================================================================== +--- alsa-lib-1.1.6.orig/src/conf/cards/Makefile.am ++++ alsa-lib-1.1.6/src/conf/cards/Makefile.am +@@ -60,7 +60,8 @@ cfg_files = aliases.conf \ + VXPocket.conf \ + VXPocket440.conf \ + CS42888.conf \ +- IMX-HDMI.conf ++ IMX-HDMI.conf \ ++ AK4458.conf + + if BUILD_ALISP + cfg_files += aliases.alisp +Index: alsa-lib-1.1.6/src/conf/cards/aliases.conf +=================================================================== +--- alsa-lib-1.1.6.orig/src/conf/cards/aliases.conf ++++ alsa-lib-1.1.6/src/conf/cards/aliases.conf +@@ -59,6 +59,7 @@ pistachio cards.pistachio-card + VC4-HDMI cards.vc4-hdmi + imx-cs42888 cards.CS42888 + imx-hdmi-soc cards.IMX-HDMI ++ak4458-audio cards.AK4458 + + + diff --git a/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0006-add-conf-for-iMX-XCVR-sound-card.patch b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0006-add-conf-for-iMX-XCVR-sound-card.patch new file mode 100755 index 000000000..a702f946c --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib/0006-add-conf-for-iMX-XCVR-sound-card.patch @@ -0,0 +1,89 @@ +From d2be0f650f9fec265f0f0b4ba646a157f2a4cb7c Mon Sep 17 00:00:00 2001 +From: Viorel Suman +Date: Mon, 9 Mar 2020 14:25:46 +0200 +Subject: [PATCH] add conf for iMX XCVR sound card + +Upstream Status: Pending + +Signed-off-by: Viorel Suman +--- + src/conf/cards/IMX-XCVR.conf | 39 +++++++++++++++++++++++++++++++++++++++ + src/conf/cards/Makefile.am | 3 ++- + src/conf/cards/aliases.conf | 1 + + 3 files changed, 42 insertions(+), 1 deletion(-) + create mode 100755 src/conf/cards/IMX-XCVR.conf + +diff --git a/src/conf/cards/IMX-XCVR.conf b/src/conf/cards/IMX-XCVR.conf +new file mode 100755 +index 0000000..009000c +--- /dev/null ++++ b/src/conf/cards/IMX-XCVR.conf +@@ -0,0 +1,39 @@ ++# ++# Configuration for the IMX-XCVR sound card using software IEC958 ++# subframe conversion ++# ++IMX-XCVR.pcm.default { ++ @args [ CARD ] ++ @args.CARD { type string } ++ type plug ++ slave.pcm { ++ @func concat ++ strings [ "iec958:" $CARD ] ++ } ++} ++ ++ ++ ++IMX-XCVR.pcm.iec958.0 { ++ @args [ CARD AES0 AES1 AES2 AES3 ] ++ @args.CARD { type string } ++ @args.AES0 { type integer } ++ @args.AES1 { type integer } ++ @args.AES2 { type integer } ++ @args.AES3 { type integer } ++ type iec958 ++ slave { ++ format IEC958_SUBFRAME_LE ++ pcm { ++ type plug ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ } ++ } ++ status [ $AES0 $AES1 $AES2 $AES3 ] ++ preamble.z 0x0 ++ preamble.x 0x1 ++ preamble.y 0x3 ++} +diff --git a/src/conf/cards/Makefile.am b/src/conf/cards/Makefile.am +index 34fa5a3..70b9bab 100644 +--- a/src/conf/cards/Makefile.am ++++ b/src/conf/cards/Makefile.am +@@ -61,7 +61,8 @@ cfg_files = aliases.conf \ + VXPocket440.conf \ + CS42888.conf \ + IMX-HDMI.conf \ +- AK4458.conf ++ AK4458.conf \ ++ IMX-XCVR.conf + + if BUILD_ALISP + cfg_files += aliases.alisp +diff --git a/src/conf/cards/aliases.conf b/src/conf/cards/aliases.conf +index 5d92ac7..c195848 100644 +--- a/src/conf/cards/aliases.conf ++++ b/src/conf/cards/aliases.conf +@@ -60,6 +60,7 @@ VC4-HDMI cards.vc4-hdmi + imx-cs42888 cards.CS42888 + imx-hdmi-soc cards.IMX-HDMI + ak4458-audio cards.AK4458 ++imx-audio-xcvr cards.IMX-XCVR + + + +-- +2.7.4 + diff --git a/meta-digi-dey/recipes-multimedia/alsa/alsa-lib_%.bbappend b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib_%.bbappend new file mode 100644 index 000000000..ee10914c9 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/alsa-lib_%.bbappend @@ -0,0 +1,8 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +IMX_PATCH += " \ + file://0001-pcm-plugin-status-fix-the-return-value-regression.patch \ + file://0002-pcm-plugin-status-revert-the-recent-changes.patch \ +" + +PACKAGE_ARCH_imx = "${TUNE_PKGARCH}" diff --git a/meta-digi-dey/recipes-multimedia/alsa/card-detect.bb b/meta-digi-dey/recipes-multimedia/alsa/card-detect.bb new file mode 100644 index 000000000..5bff1c87c --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/card-detect.bb @@ -0,0 +1,28 @@ +# Copyright (C) 2017 Digi International. + +SUMMARY = "DEY sound card detection app" +SECTION = "multimedia" +LICENSE = "MPL-2.0" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad" + +DEPENDS = "alsa-lib" + +SRC_URI = "file://card-detect.c" + +S = "${WORKDIR}" + +inherit pkgconfig + +export CFLAGS += "`pkg-config --cflags alsa`" +export LDLIBS += "`pkg-config --libs alsa`" + +do_configure[noexec] = "1" + +do_compile() { + oe_runmake card-detect +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 card-detect ${D}${bindir} +} diff --git a/meta-digi-dey/recipes-multimedia/alsa/card-detect/card-detect.c b/meta-digi-dey/recipes-multimedia/alsa/card-detect/card-detect.c new file mode 100644 index 000000000..7ead91235 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/alsa/card-detect/card-detect.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 Digi International Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int len, ret = EXIT_SUCCESS; + snd_pcm_t *handle; + char *device; + + if (argc < 2) { + printf("Usage: %s [CARD NUMBER]\n", argv[0]); + return EXIT_FAILURE; + } + + len = strlen("hw:") + strlen(argv[1]) + 1; + device = calloc(1, len); + snprintf(device, len, "hw:%s", argv[1]); + + /* Open the PCM-device in playback mode */ + if (snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0) < 0) { + printf("Could't open PCM '%s'\n", device); + ret = EXIT_FAILURE; + } else { + printf("Device %s opened successfully\n", device); + snd_pcm_close(handle); + } + + free(device); + return ret; +} diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend b/meta-digi-dey/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend index 54bd2f6e8..fae502430 100644 --- a/meta-digi-dey/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend @@ -1,4 +1,4 @@ -# Copyright (C) 2019 Digi International +# Copyright (C) 2019-2022 Digi International FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:" @@ -40,6 +40,10 @@ SRC_URI_append_ccimx6ulsbc = " \ file://0001-pulseaudio-keep-headphones-volume-in-platforms-witho.patch \ " +SRC_URI_append_ccmp15 = " \ + file://0001-pulseaudio-keep-headphones-volume-in-platforms-witho.patch \ +" + # This default setting should be added on all i.MX SoC, # For now, the setting for mx6(including mx6ul & mx6sll)/mx7 has been upstreamed SRC_URI_append_mx8 = " \ diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch new file mode 100755 index 000000000..f578148a1 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch @@ -0,0 +1,1001 @@ +From 16f6b7a5baec41f18fde75fd311fb988e3c31810 Mon Sep 17 00:00:00 2001 +From: Shengjiu Wang +Date: Fri, 13 Jul 2018 18:13:24 +0800 +Subject: [PATCH] tinycompress: Add id3 decoding + +Signed-off-by: Shengjiu Wang +--- + include/tinycompress/id3_tag_decode.h | 198 +++++++++++ + src/utils/Makefile.am | 2 +- + src/utils/cplay.c | 88 +++++ + src/utils/id3_tag_decode.c | 642 ++++++++++++++++++++++++++++++++++ + 4 files changed, 929 insertions(+), 1 deletion(-) + create mode 100644 include/tinycompress/id3_tag_decode.h + create mode 100644 src/utils/id3_tag_decode.c + +diff --git a/include/tinycompress/id3_tag_decode.h b/include/tinycompress/id3_tag_decode.h +new file mode 100644 +index 0000000..1a911d7 +--- /dev/null ++++ b/include/tinycompress/id3_tag_decode.h +@@ -0,0 +1,198 @@ ++/* ++ * Copyright (c) 2006-2017 Cadence Design Systems, Inc. ++ * Copyright 2018 NXP ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included ++ * in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++/****************************************************************** ++ * file name : id3_tag_decode.h ++ * ++ * description : stores typedefs of structures specific to MP3 tag ++ * ++ * revision history: ++ * 29 04 2004 DK creation ++ *****************************************************************/ ++ ++#ifndef ID3_TAG_DECODE_H ++#define ID3_TAG_DECODE_H ++ ++typedef signed char WORD8; ++typedef signed char * pWORD8; ++typedef unsigned char UWORD8; ++typedef unsigned char * pUWORD8; ++ ++typedef signed short WORD16; ++typedef signed short * pWORD16; ++typedef unsigned short UWORD16; ++typedef unsigned short * pUWORD16; ++ ++typedef signed int WORD24; ++typedef signed int * pWORD24; ++typedef unsigned int UWORD24; ++typedef unsigned int * pUWORD24; ++ ++typedef signed int WORD32; ++typedef signed int * pWORD32; ++typedef unsigned int UWORD32; ++typedef unsigned int * pUWORD32; ++ ++typedef void VOID; ++typedef void * pVOID; ++ ++typedef signed int BOOL; ++typedef unsigned int UBOOL; ++typedef signed int FLAG; ++typedef unsigned int UFLAG; ++typedef signed int LOOPIDX; ++typedef unsigned int ULOOPIDX; ++typedef signed int WORD; ++typedef unsigned int UWORD; ++ ++#define MAX_TAG_FRAME_SIZE 100 ++ ++#define ID3V1 (0x544147) /* 0x544147 is TAG in WORD8 */ ++ ++#define ID3V2 (0x494433) /* 0x494433 is ID3 in WORD8 */ ++ ++/* ++ * structure corresponding to ID3 tag v1 header. ++ * this structure has all the field corresponding to ID3 tag v1 header. ++ */ ++ ++typedef struct { ++ WORD32 tag; // 3 bytes ++ ++ WORD16 version; // 2 bytes ++ ++ WORD8 flag; //1 byte ++ ++ WORD32 size; //4 bytes ++ ++} id3_v2_header_struct; ++ ++/* structure which will store the frame data and ++ * also put a limit max data to be stored ++ */ ++typedef struct { ++ WORD8 frame_data[MAX_TAG_FRAME_SIZE]; ++ ++ WORD32 max_size; //4 bytes ++ ++ WORD16 tag_present; ++ ++ WORD16 exceeds_buffer_size; ++ ++} id3_v2_frame_struct; ++ ++/* ++ * structure corresponding to ID3 tag v2. ++ * this structure has some of the field corresponding to ID3 tag v2. ++ * if user wants to read some more tag information from ++ * the MP3 file, he can add that field in this structure and pass address ++ * of that element to get_inf function in id3_tag_decode.c under the ++ * corresponding field frame header. few fields which are needed are already ++ * populated by reading from the TAG header. ++ */ ++typedef struct { ++ id3_v2_frame_struct album_movie_show_title; ++ ++ id3_v2_frame_struct composer_name; ++ ++ id3_v2_frame_struct content_type; ++ ++ id3_v2_frame_struct encoded_by; ++ ++ id3_v2_frame_struct lyricist_text_writer; ++ ++ id3_v2_frame_struct content_group_description; ++ ++ id3_v2_frame_struct title_songname_content_description; ++ ++ id3_v2_frame_struct medxa_type; ++ ++ id3_v2_frame_struct original_album_movie_show_title; ++ ++ id3_v2_frame_struct original_filename; ++ ++ id3_v2_frame_struct original_lyricist_text_writer; ++ ++ id3_v2_frame_struct original_artist_performer; ++ ++ id3_v2_frame_struct file_owner_licensee; ++ ++ id3_v2_frame_struct lead_performer_soloist; ++ ++ id3_v2_frame_struct publisher; ++ ++ id3_v2_frame_struct private_frame; ++ ++ id3_v2_frame_struct other_info; ++ ++ id3_v2_header_struct id3_v2_header; ++ ++ WORD32 header_end; ++ ++ WORD32 bytes_consumed; ++ ++} id3v2_struct; ++ ++/* ++ * structure corresponding to ID3 tag v1. ++ * this structure has all the field corresponding to ID3 tag v1. ++ */ ++typedef struct { ++ WORD8 song_title[30]; //30 word8acters ++ ++ WORD8 artist[30]; //30 word8acters ++ ++ WORD8 album[30]; //30 word8acters ++ ++ WORD8 year[4]; //4 word8acters ++ ++ WORD8 comment[30]; //30 word8acters ++ ++ WORD8 genre[1]; //1 byte ++ ++} id3v1_struct; ++ ++WORD32 get_info(const char *inp_buffer, ++ unsigned int avail_inp, ++ WORD32 tag_size, ++ id3_v2_frame_struct *dest); ++ ++WORD32 search_id3_v2(UWORD8 *buffer); ++ ++WORD32 decode_id3_v2(const char *const buffer, ++ id3v2_struct *id3v2, ++ WORD32 continue_flag, ++ WORD32 insize); ++ ++WORD32 get_id3_v2_bytes(UWORD8 *buffer); ++ ++WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1); ++ ++WORD32 search_id3_v1(UWORD8 *buffer); ++ ++WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1); ++ ++void init_id3v2_field(id3v2_struct *id3v2); ++ ++#endif +diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am +index 1b996d4..e813689 100644 +--- a/src/utils/Makefile.am ++++ b/src/utils/Makefile.am +@@ -1,6 +1,6 @@ + bin_PROGRAMS = cplay crecord + +-cplay_SOURCES = cplay.c ++cplay_SOURCES = cplay.c id3_tag_decode.c + crecord_SOURCES = crecord.c + + cplay_CFLAGS = -I$(top_srcdir)/include +diff --git a/src/utils/cplay.c b/src/utils/cplay.c +index 87863a3..2a52b52 100644 +--- a/src/utils/cplay.c ++++ b/src/utils/cplay.c +@@ -72,6 +72,7 @@ + #include "sound/compress_params.h" + #include "tinycompress/tinycompress.h" + #include "tinycompress/tinymp3.h" ++#include "tinycompress/id3_tag_decode.h" + + static int verbose; + static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM; +@@ -245,12 +246,97 @@ int main(int argc, char **argv) + exit(EXIT_SUCCESS); + } + ++void shift_buffer(char *buf, int buf_size, int bytes_consumed) ++{ ++ int i; ++ ++ if (bytes_consumed <= 0) ++ return; ++ ++ for (i = 0; i < buf_size - bytes_consumed; i++) ++ buf[i] = buf[i + bytes_consumed]; ++} ++ ++void parse_id3(FILE *file, int *offset) { ++ /* ID3 tag specific declarations */ ++ unsigned char id3_buf[128]; ++ unsigned char id3v2_buf[4096]; ++ signed int id3_v1_found = 0, id3_v1_decoded = 0; ++ signed int id3_v2_found = 0, id3_v2_complete = 0; ++ signed int i_bytes_consumed = 0; ++ signed int i_fread_bytes; ++ id3v1_struct id3v1; ++ id3v2_struct id3v2; ++ ++ { ++ fseek(file, -128, SEEK_END); ++ fread(id3_buf, 1, 128, file); ++ ++ /* search for ID3V1 */ ++ id3_v1_found = search_id3_v1(id3_buf + 0); ++ if (id3_v1_found) { ++ /* if ID3V1 is found, decode ID3V1 */ ++ decode_id3_v1(id3_buf + 3, &id3v1); ++ id3_v1_decoded = 1; ++ } ++ fseek(file, 0, SEEK_SET); ++ } ++ ++ { ++ signed int flag = 0; ++ signed int continue_flag = 0; ++ ++ i_fread_bytes = fread(id3v2_buf, ++ sizeof(char), 0x1000, file); ++ ++ /* search for ID3V2 */ ++ id3_v2_found = ++ search_id3_v2(id3v2_buf); ++ ++ if (id3_v2_found) { ++ /* initialise the max fields */ ++ init_id3v2_field(&id3v2); ++ ++ while (!id3_v2_complete && id3_v2_found) { ++ /* if ID3V2 is found, decode ID3V2 */ ++ id3_v2_complete = decode_id3_v2((const char *const)id3v2_buf, ++ &id3v2, continue_flag, i_fread_bytes); ++ ++ if (!id3_v2_complete) { ++ continue_flag = 1; ++ i_bytes_consumed = id3v2.bytes_consumed; ++ ++ fseek(file, i_bytes_consumed, SEEK_SET); ++ ++ i_fread_bytes = fread(id3v2_buf, ++ sizeof(unsigned char), 0x1000, file); ++ if (i_fread_bytes <= 0) { ++ return; ++ } ++ } ++ } ++ ++ if (id3_v2_complete) { ++ i_bytes_consumed = id3v2.bytes_consumed; ++ fseek(file, i_bytes_consumed, SEEK_SET); ++ } ++ } ++ } ++ ++ *offset = i_bytes_consumed; ++} ++ + void get_codec_mp3(FILE *file, struct compr_config *config, + struct snd_codec *codec) + { + size_t read; + struct mp3_header header; + unsigned int channels, rate, bits; ++ int offset = 0; ++ ++ parse_id3(file, &offset); ++ ++ fseek(file, offset, SEEK_SET); + + read = fread(&header, 1, sizeof(header), file); + if (read != sizeof(header)) { +@@ -279,6 +365,8 @@ void get_codec_mp3(FILE *file, struct compr_config *config, + codec->level = 0; + codec->ch_mode = 0; + codec->format = 0; ++ ++ fseek(file, offset, SEEK_SET); + } + + void get_codec_iec(FILE *file, struct compr_config *config, +diff --git a/src/utils/id3_tag_decode.c b/src/utils/id3_tag_decode.c +new file mode 100644 +index 0000000..393967a +--- /dev/null ++++ b/src/utils/id3_tag_decode.c +@@ -0,0 +1,642 @@ ++/* ++ * Copyright (c) 2006-2017 Cadence Design Systems, Inc. ++ * Copyright 2018 NXP ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included ++ * in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#include ++#include "tinycompress/id3_tag_decode.h" ++ ++#define CHAR4(c1, c2, c3, c4) \ ++ (int)(((unsigned char)(c1) << 24) | \ ++ ((unsigned char)(c2) << 16) | \ ++ ((unsigned char)(c3) << 8) | \ ++ ((unsigned char)c4)) ++ ++#ifndef MSVC_BUILD ++unsigned int umin(unsigned int a, unsigned int b) ++{ ++ return (a < b ? a : b); ++} ++ ++#else ++unsigned int umin(unsigned int a, unsigned int b) ++{ ++ return (a < b ? a : b); ++} ++#endif ++ ++/*********************************************************** ++ * function name : display ++ * ++ * description : display ID3 tag contents. ++ * ++ * arguments : input parameters ++ * ++ * values returned : 0 ++ ***********************************************************/ ++ ++static void display2(const id3_v2_frame_struct * const src, ++ int size, ++ const char * const disp) ++{ ++ int j; ++ ++ ++ for (j = 0; j < size; j++) { ++ int c = src->frame_data[j]; ++ ++ if (c) { ++ if (!isprint(c)) ++ break; ++ } ++ } ++} ++ ++static VOID display1(WORD8 src[], WORD32 size, WORD8 disp[]) ++{ ++ WORD32 j; ++ ++ for (j = 0; j < size ; j++) { ++ int c = src[j]; ++ ++ if (c) { ++ if (!isprint(c)) ++ break; ++ } ++ } ++} ++ ++/***************************************************************** ++ * function name : init_id3_header ++ * ++ * description : initialise the max filed size of teh farem. ++ * ++ * arguments : input parameters ++ * ++ * values returned : 0 ++ ****************************************************************/ ++ ++VOID init_id3v2_field(id3v2_struct *id3v2) ++{ ++ id3v2->album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->composer_name.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->content_type.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->encoded_by.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->content_group_description.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->title_songname_content_description.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->medxa_type.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->original_album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->original_filename.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->original_lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->original_artist_performer.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->file_owner_licensee.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->lead_performer_soloist.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->publisher.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->private_frame.max_size = MAX_TAG_FRAME_SIZE; ++ id3v2->other_info.max_size = MAX_TAG_FRAME_SIZE; ++ ++ /* resetting the flag to indicate presese of frame */ ++ id3v2->album_movie_show_title.tag_present = 0; ++ id3v2->composer_name.tag_present = 0; ++ id3v2->content_type.tag_present = 0; ++ id3v2->encoded_by.tag_present = 0; ++ id3v2->lyricist_text_writer.tag_present = 0; ++ id3v2->content_group_description.tag_present = 0; ++ id3v2->title_songname_content_description.tag_present = 0; ++ id3v2->medxa_type.tag_present = 0; ++ id3v2->original_album_movie_show_title.tag_present = 0; ++ id3v2->original_filename.tag_present = 0; ++ id3v2->original_lyricist_text_writer.tag_present = 0; ++ id3v2->original_artist_performer.tag_present = 0; ++ id3v2->file_owner_licensee.tag_present = 0; ++ id3v2->lead_performer_soloist.tag_present = 0; ++ id3v2->publisher.tag_present = 0; ++ id3v2->private_frame.tag_present = 0; ++ id3v2->other_info.tag_present = 0; ++ ++ /* resetting the flag which indicates that size of the frame has ++ * exceeded the max buffer size ++ */ ++ id3v2->album_movie_show_title.exceeds_buffer_size = 0; ++ id3v2->composer_name.exceeds_buffer_size = 0; ++ id3v2->content_type.exceeds_buffer_size = 0; ++ id3v2->encoded_by.exceeds_buffer_size = 0; ++ id3v2->lyricist_text_writer.exceeds_buffer_size = 0; ++ id3v2->content_group_description.exceeds_buffer_size = 0; ++ id3v2->title_songname_content_description.exceeds_buffer_size = 0; ++ id3v2->medxa_type.exceeds_buffer_size = 0; ++ id3v2->original_album_movie_show_title.exceeds_buffer_size = 0; ++ id3v2->original_filename.exceeds_buffer_size = 0; ++ id3v2->original_lyricist_text_writer.exceeds_buffer_size = 0; ++ id3v2->original_artist_performer.exceeds_buffer_size = 0; ++ id3v2->file_owner_licensee.exceeds_buffer_size = 0; ++ id3v2->lead_performer_soloist.exceeds_buffer_size = 0; ++ id3v2->publisher.exceeds_buffer_size = 0; ++ id3v2->private_frame.exceeds_buffer_size = 0; ++ id3v2->other_info.exceeds_buffer_size = 0; ++ ++ id3v2->bytes_consumed = 0; ++ id3v2->header_end = 0; ++} ++ ++/*************************************************************** ++ * function name : search_id3_v2 ++ * ++ * description : finds if ID3V2 starts at the start of given buffer. ++ * ++ * arguments : input parameters ++ * buffer input buffer ++ * ++ * values returned : FLAG 1: ID3 found 0: ID3 not found ++ ***************************************************************/ ++WORD32 search_id3_v2(UWORD8 *buffer) ++{ ++ UWORD32 temp; ++ ++ temp = buffer[0] << 16; ++ temp |= buffer[1] << 8; ++ temp |= buffer[2]; ++ ++ if (temp == ID3V2) ++ return 1; /* ID3 found */ ++ ++ return 0; /* ID3 not found */ ++} ++ ++/************************************************************** ++ * function name : search_id3_v1 ++ * ++ * description : finds if ID3V1 starts at the start of given buffer. ++ * ++ * arguments : input parameters ++ * buffer input buffer ++ * ++ * values returned : FLAG 1: ID3 found 0: ID3 not found ++ **************************************************************/ ++WORD32 search_id3_v1(UWORD8 *buffer) ++{ ++ UWORD32 temp; ++ ++ temp = buffer[0] << 16; ++ temp |= buffer[1] << 8; ++ temp |= buffer[2]; ++ ++ if (temp == ID3V1) ++ return 1; /* ID3 found */ ++ ++ return 0; /* ID3 not found */ ++} ++ ++/*************************************************************** ++ * function name : decode_id3_v1 ++ * ++ * description : decodes ID3V1 tag. ++ * ++ * arguments : input parameters ++ * buffer input buffer ++ * id3v1 structure ++ * ++ * values returned : bytes consumed ++ **************************************************************/ ++WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1) ++{ ++ WORD32 bytes_consumed = 0; ++ short tag_type; ++ ++ /* setting the tag type */ ++ tag_type = 1; ++ ++ bytes_consumed = get_v1_info(buffer, id3v1); ++ ++ return bytes_consumed; ++} ++ ++/*********************************************************** ++ * function name : get_v1_info ++ * ++ * description : gets ID3V1 information fields. ++ * ++ * arguments : input parameters ++ * buffer input buffer ++ * id3v1 structure ++ * ++ * values returned : bytes consumed ++ ***********************************************************/ ++WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1) ++{ ++ WORD32 i; ++ WORD32 bytes_consumed = 0; ++ ++ /* get song_title */ ++ for (i = 0; i < 30; i++) ++ id3v1->song_title[i] = buffer[i]; ++ ++ buffer += 30; ++ bytes_consumed += 30; ++ display1(id3v1->song_title, 30, (WORD8 *)"song_title : "); ++ ++ /* get artist */ ++ for (i = 0; i < 30; i++) ++ id3v1->artist[i] = buffer[i]; ++ ++ buffer += 30; ++ bytes_consumed += 30; ++ display1(id3v1->artist, 30, (WORD8 *)"artist : "); ++ ++ /* get album */ ++ for (i = 0; i < 30; i++) ++ id3v1->album[i] = buffer[i]; ++ ++ buffer += 30; ++ bytes_consumed += 30; ++ display1(id3v1->album, 30, (WORD8 *)"album : "); ++ ++ /* get year */ ++ for (i = 0; i < 4; i++) ++ id3v1->year[i] = buffer[i]; ++ ++ buffer += 4; ++ bytes_consumed += 4; ++ display1(id3v1->year, 4, (WORD8 *)"year : "); ++ ++ /* get comment */ ++ for (i = 0; i < 30; i++) ++ id3v1->comment[i] = buffer[i]; ++ ++ buffer += 30; ++ bytes_consumed += 30; ++ display1(id3v1->comment, 30, (WORD8 *)"comment : "); ++ ++ /* get genre */ ++ for (i = 0; i < 1; i++) ++ id3v1->genre[i] = buffer[i]; ++ ++ buffer += 1; ++ bytes_consumed += 1; ++ ++ return bytes_consumed; ++} ++ ++/***************************************************** ++ * function name : decode_id3_v2 ++ * ++ * description : decodes ID3V2 tag. ++ * ++ * arguments : input parameters ++ * buffer input buffer ++ * id3v2 structure ++ * continue_flag FLAG to indicate whether ++ * it is first call or not ++ * insize input buffer size ++ * ++ * values returned : bytes consumed ++ ******************************************************/ ++WORD32 decode_id3_v2(const char *const buffer, ++ id3v2_struct *const id3v2, ++ WORD32 continue_flag, ++ WORD32 insize) ++{ ++ UWORD32 size = 0, flag; ++ WORD32 i, buf_update_val; ++ UWORD8 buf[4], frame_header[10], id3_buffer[10]; ++ WORD8 *bitstream_ptr; ++ short tag_type; ++ ++ WORD32 bytes_consumed = 0; ++ ++ if (id3v2->header_end == 1) { ++ id3v2->bytes_consumed += insize; ++ if (id3v2->bytes_consumed < id3v2->id3_v2_header.size) ++ return 0; ++ ++ id3v2->bytes_consumed = (id3v2->id3_v2_header.size + 10); ++ return 1; ++ } ++ ++ bitstream_ptr = (WORD8 *)id3_buffer; ++ ++ if (!continue_flag) { ++ bytes_consumed += 3; ++ /* setting the tag type */ ++ tag_type = 2; ++ id3v2->id3_v2_header.version = buffer[bytes_consumed + 0] << 8; ++ id3v2->id3_v2_header.version |= buffer[bytes_consumed + 1]; ++ id3v2->id3_v2_header.flag = buffer[bytes_consumed + 2]; ++ ++ /* making the msb of each byte zero */ ++ buf[0] = buffer[bytes_consumed + 6] & 0x7f; ++ buf[1] = buffer[bytes_consumed + 5] & 0x7f; ++ buf[2] = buffer[bytes_consumed + 4] & 0x7f; ++ buf[3] = buffer[bytes_consumed + 3] & 0x7f; ++ ++ bytes_consumed += 7; ++ ++ /* concatenation the bytes after making ++ * 7th bit zero to get 28 bits size ++ */ ++ size = buf[0]; ++ size |= (buf[1] << 7); ++ size |= (buf[2] << 14); ++ size |= (buf[3] << 21); ++ /* storing the size */ ++ id3v2->id3_v2_header.size = size; ++ ++ /* check for extended header */ ++ if (id3v2->id3_v2_header.flag & 0x20) { ++ for (i = 0; i < 10; i++) ++ bitstream_ptr[i] = buffer[bytes_consumed + i]; ++ ++ i = 0; ++ bytes_consumed += 10; ++ ++ size = bitstream_ptr[i++] << 24; ++ size |= bitstream_ptr[i++] << 16; ++ size |= bitstream_ptr[i++] << 8; ++ size |= bitstream_ptr[i++]; ++ ++ /* two bytes for flag */ ++ i += 2; ++ { ++ UWORD32 padding_size; ++ ++ padding_size = bitstream_ptr[i++] << 24; ++ padding_size |= bitstream_ptr[i++] << 16; ++ padding_size |= bitstream_ptr[i++] << 8; ++ padding_size |= bitstream_ptr[i++]; ++ ++ /* skipping the padding and frame size ++ * number of bytes ++ */ ++ bytes_consumed += (padding_size + size); ++ } ++ } ++ } ++ ++ while (id3v2->header_end != 1) { ++ char *key; ++ id3_v2_frame_struct *value; ++ unsigned int avail_inp; ++ ++ /* reading the 10 bytes to get the frame header */ ++ ++ for (i = 0; i < 10; i++) ++ frame_header[i] = buffer[bytes_consumed + i]; ++ bytes_consumed += 10; ++ ++ /* getting the size from the header */ ++ size = frame_header[4] << 24; ++ size |= frame_header[5] << 16; ++ size |= frame_header[6] << 8; ++ size |= frame_header[7]; ++ ++ /* decoding the flag, currently not used */ ++ flag = frame_header[8] << 8; ++ flag |= frame_header[9]; ++ ++ avail_inp = insize - bytes_consumed; ++ ++ /* switching to the frame type */ ++ switch (CHAR4(frame_header[0], ++ frame_header[1], ++ frame_header[2], ++ frame_header[3])) { ++ case CHAR4('A', 'E', 'N', 'C'): ++ case CHAR4('A', 'P', 'I', 'C'): ++ case CHAR4('C', 'O', 'M', 'M'): ++ case CHAR4('C', 'O', 'M', 'R'): ++ case CHAR4('E', 'N', 'C', 'R'): ++ case CHAR4('E', 'Q', 'U', 'A'): ++ case CHAR4('E', 'T', 'C', 'O'): ++ case CHAR4('G', 'E', 'O', 'B'): ++ case CHAR4('G', 'R', 'I', 'D'): ++ case CHAR4('I', 'P', 'L', 'S'): ++ case CHAR4('L', 'I', 'N', 'K'): ++ case CHAR4('M', 'C', 'D', 'I'): ++ case CHAR4('M', 'L', 'L', 'T'): ++ case CHAR4('O', 'W', 'N', 'E'): ++ case CHAR4('P', 'C', 'N', 'T'): ++ case CHAR4('P', 'O', 'P', 'M'): ++ case CHAR4('P', 'O', 'S', 'S'): ++ case CHAR4('R', 'B', 'U', 'F'): ++ case CHAR4('R', 'V', 'A', 'D'): ++ case CHAR4('R', 'V', 'R', 'B'): ++ case CHAR4('S', 'Y', 'L', 'T'): ++ case CHAR4('S', 'Y', 'T', 'C'): ++ case CHAR4('T', 'B', 'P', 'M'): ++ case CHAR4('T', 'C', 'O', 'P'): ++ case CHAR4('T', 'D', 'A', 'T'): ++ case CHAR4('T', 'D', 'L', 'Y'): ++ case CHAR4('T', 'F', 'L', 'T'): ++ case CHAR4('T', 'I', 'M', 'E'): ++ case CHAR4('T', 'K', 'E', 'Y'): ++ case CHAR4('T', 'L', 'A', 'N'): ++ case CHAR4('T', 'L', 'E', 'N'): ++ case CHAR4('T', 'M', 'E', 'D'): ++ case CHAR4('T', 'O', 'F', 'N'): ++ case CHAR4('T', 'O', 'L', 'Y'): ++ case CHAR4('T', 'O', 'R', 'Y'): ++ case CHAR4('T', 'P', 'E', '2'): ++ case CHAR4('T', 'P', 'E', '3'): ++ case CHAR4('T', 'P', 'E', '4'): ++ case CHAR4('T', 'P', 'O', 'S'): ++ case CHAR4('T', 'R', 'C', 'K'): ++ case CHAR4('T', 'R', 'D', 'A'): ++ case CHAR4('T', 'R', 'S', 'N'): ++ case CHAR4('T', 'R', 'S', 'O'): ++ case CHAR4('T', 'S', 'I', 'Z'): ++ case CHAR4('T', 'S', 'R', 'C'): ++ case CHAR4('T', 'S', 'S', 'E'): ++ case CHAR4('T', 'Y', 'E', 'R'): ++ case CHAR4('T', 'X', 'X', 'X'): ++ case CHAR4('U', 'F', 'I', 'D'): ++ case CHAR4('U', 'S', 'E', 'R'): ++ case CHAR4('U', 'S', 'L', 'T'): ++ case CHAR4('W', 'C', 'O', 'M'): ++ case CHAR4('W', 'C', 'O', 'P'): ++ case CHAR4('W', 'O', 'A', 'F'): ++ case CHAR4('W', 'O', 'A', 'R'): ++ case CHAR4('W', 'O', 'A', 'S'): ++ case CHAR4('W', 'O', 'R', 'S'): ++ case CHAR4('W', 'P', 'A', 'Y'): ++ case CHAR4('W', 'P', 'U', 'B'): ++ case CHAR4('W', 'X', 'X', 'X'): ++ case CHAR4('T', 'I', 'T', '3'): ++ key = "other_info : "; ++ value = &id3v2->other_info; ++ break; ++ case CHAR4('P', 'R', 'I', 'V'): ++ key = "private_frame : "; ++ value = &id3v2->private_frame; ++ break; ++ case CHAR4('T', 'A', 'L', 'B'): ++ key = "album_movie_show_title : "; ++ value = &id3v2->album_movie_show_title; ++ break; ++ case CHAR4('T', 'C', 'O', 'M'): ++ key = "composer_name : "; ++ value = &id3v2->composer_name; ++ break; ++ case CHAR4('T', 'C', 'O', 'N'): ++ key = "content_type : "; ++ value = &id3v2->content_type; ++ break; ++ case CHAR4('T', 'E', 'N', 'C'): ++ key = "encoded_by : "; ++ value = &id3v2->encoded_by; ++ break; ++ case CHAR4('T', 'E', 'X', 'T'): ++ key = "lyricist_text_writer : "; ++ value = &id3v2->lyricist_text_writer; ++ break; ++ case CHAR4('T', 'I', 'T', '1'): ++ key = "content_group_description : "; ++ value = &id3v2->content_group_description; ++ break; ++ case CHAR4('T', 'I', 'T', '2'): ++ key = "title_songname_content_description : "; ++ value = &id3v2->title_songname_content_description; ++ break; ++ case CHAR4('T', 'O', 'A', 'L'): ++ key = "original_album_movie_show_title : "; ++ value = &id3v2->original_album_movie_show_title; ++ break; ++ case CHAR4('T', 'O', 'P', 'E'): ++ key = "original_artist_performer : "; ++ value = &id3v2->original_artist_performer; ++ break; ++ case CHAR4('T', 'O', 'W', 'N'): ++ key = "file_owner_licensee : "; ++ value = &id3v2->file_owner_licensee; ++ break; ++ case CHAR4('T', 'P', 'E', '1'): ++ key = "lead_performer_soloist : "; ++ value = &id3v2->lead_performer_soloist; ++ break; ++ case CHAR4('T', 'P', 'U', 'B'): ++ key = "publisher : "; ++ value = &id3v2->publisher; ++ break; ++ default: ++ /* skipping the read 10 bytes */ ++ buf_update_val = -10; ++ id3v2->header_end = 1; ++ value = 0; ++ key = 0; ++ break; ++ } ++ ++ if (value != 0) ++ buf_update_val = get_info(&buffer[bytes_consumed], ++ avail_inp, size, value); ++ ++ /* Negative value for buf_update_val means one of two things: ++ * 1. The default case happened and we're done with ID3V2 tag ++ * frames, or ++ * 2. get_info() returned -1 to indicate that more input is ++ * required to decode this frame of the tag. ++ */ ++ if (buf_update_val >= 0) ++ display2(value, ++ umin(value->max_size, buf_update_val), key); ++ ++ if (buf_update_val == -1) { ++ id3v2->bytes_consumed += bytes_consumed; ++ return 1; ++ } ++ ++ bytes_consumed += buf_update_val; ++ ++ /* Is there enough input left (10 bytes) to begin ++ * decoding another frame? If not, bag out temporarily ++ * now. The caller will refill our input buffer and ++ * call us again with continue_flag == 1. ++ */ ++ if (insize - bytes_consumed < 10) { ++ id3v2->bytes_consumed += bytes_consumed; ++ return 0; /* not completely decoded */ ++ } ++ } ++ ++ id3v2->bytes_consumed += bytes_consumed; ++ if ((id3v2->bytes_consumed + 10) < id3v2->id3_v2_header.size) ++ return 0; /* not completely decoded */ ++ ++ return 1; /* completely decoded */ ++} ++ ++/******************************************************* ++ * function name : get_id3_v2_bytes ++ * ++ * description : tells the size of ID3V2 tag. ++ * ++ * arguments : input parameters ++ * buffer input buffer ++ * ++ * values returned : bytes consumed ++ ********************************************************/ ++WORD32 get_id3_v2_bytes(UWORD8 *buffer) ++{ ++ WORD32 size; ++ ++ /* making the msb of each byte zero */ ++ size = (buffer[9] & 0x7f); ++ size |= ((buffer[8] & 0x7f) << 7); ++ size |= ((buffer[7] & 0x7f) << 14); ++ size |= ((buffer[6] & 0x7f) << 21); ++ ++ return (size + 10); ++} ++ ++/**************************************************** ++ * function name : get_info ++ * ++ * description : read the frame information from the input buffer. ++ * ++ * arguments : input parameters ++ * ++ * values returned : update value for buffer ++ ****************************************************/ ++WORD32 get_info(const char *inp_buffer, ++ unsigned int avail_inp, ++ WORD32 tag_size, ++ id3_v2_frame_struct *dest) ++{ ++ WORD32 j; ++ ++ /* setting the tag to indicate the presence of frame */ ++ dest->tag_present = 1; ++ /* If there isn't enough input available, we punt back to the top ++ * level and ask for more. ++ */ ++ if (avail_inp < umin(tag_size, dest->max_size)) ++ return -1; ++ ++ if (dest->max_size >= tag_size) { ++ for (j = 0; j < tag_size ; j++) ++ dest->frame_data[j] = inp_buffer[j]; ++ } else { ++ dest->exceeds_buffer_size = 1; ++ for (j = 0; j < dest->max_size ; j++) ++ dest->frame_data[j] = inp_buffer[j]; ++ } ++ return tag_size; ++} +-- +2.7.4 + diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch new file mode 100755 index 000000000..9189bc0ed --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch @@ -0,0 +1,221 @@ +From 4d4bc0a958fe254531920095fbabc241aad88113 Mon Sep 17 00:00:00 2001 +From: Shengjiu Wang +Date: Tue, 28 Jul 2020 13:00:36 +0800 +Subject: [PATCH] cplay: Support wave file + +The supported format is mono/stereo, S16_LE/S32_LE, 8kHz-192kHz. +Command is: +cplay -c x -I PCM test.wav + +Upstream-Status: Inappropriate [i.MX specific] +Signed-off-by: Shengjiu Wang +--- + include/tinycompress/wave_formats.h | 51 +++++++++++++ + src/utils/cplay.c | 107 ++++++++++++++++++++++++++++ + 2 files changed, 158 insertions(+) + create mode 100644 include/tinycompress/wave_formats.h + +diff --git a/include/tinycompress/wave_formats.h b/include/tinycompress/wave_formats.h +new file mode 100644 +index 000000000000..4e2e009206cf +--- /dev/null ++++ b/include/tinycompress/wave_formats.h +@@ -0,0 +1,51 @@ ++#ifndef WAVE_FORMATS_H ++#define WAVE_FORMATS_H 1 ++ ++#define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) ++ ++#define WAV_RIFF COMPOSE_ID('R','I','F','F') ++#define WAV_RIFX COMPOSE_ID('R','I','F','X') ++#define WAV_WAVE COMPOSE_ID('W','A','V','E') ++#define WAV_FMT COMPOSE_ID('f','m','t',' ') ++#define WAV_DATA COMPOSE_ID('d','a','t','a') ++ ++/* WAVE fmt block constants from Microsoft mmreg.h header */ ++#define WAV_FMT_PCM 0x0001 ++#define WAV_FMT_IEEE_FLOAT 0x0003 ++#define WAV_FMT_DOLBY_AC3_SPDIF 0x0092 ++#define WAV_FMT_EXTENSIBLE 0xfffe ++ ++/* Used with WAV_FMT_EXTENSIBLE format */ ++#define WAV_GUID_TAG "\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71" ++ ++typedef struct { ++ u_int magic; /* 'RIFF' */ ++ u_int length; /* filelen */ ++ u_int type; /* 'WAVE' */ ++} WaveHeader; ++ ++typedef struct { ++ u_short format; /* see WAV_FMT_* */ ++ u_short channels; ++ u_int sample_fq; /* frequence of sample */ ++ u_int byte_p_sec; ++ u_short byte_p_spl; /* samplesize; 1 or 2 bytes */ ++ u_short bit_p_spl; /* 8, 12 or 16 bit */ ++} WaveFmtBody; ++ ++typedef struct { ++ WaveFmtBody format; ++ u_short ext_size; ++ u_short bit_p_spl; ++ u_int channel_mask; ++ u_short guid_format; /* WAV_FMT_* */ ++ u_char guid_tag[14]; /* WAV_GUID_TAG */ ++} WaveFmtExtensibleBody; ++ ++typedef struct { ++ u_int type; /* 'data' */ ++ u_int length; /* samplecount */ ++} WaveChunkHeader; ++ ++ ++#endif /* FORMATS */ +diff --git a/src/utils/cplay.c b/src/utils/cplay.c +index 5b749419e731..8882f4d9746d 100644 +--- a/src/utils/cplay.c ++++ b/src/utils/cplay.c +@@ -1,4 +1,6 @@ + /* ++ * Copyright 2020 NXP ++ * + * This file is provided under a dual BSD/LGPLv2.1 license. When using or + * redistributing this file, you may do so under either license. + * +@@ -73,6 +75,8 @@ + #include "tinycompress/tinycompress.h" + #include "tinycompress/tinymp3.h" + #include "tinycompress/id3_tag_decode.h" ++#include "tinycompress/wave_formats.h" ++#include + + static int verbose; + static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM; +@@ -166,6 +170,77 @@ static int parse_mp3_header(struct mp3_header *header, unsigned int *num_channel + return 0; + } + ++static int parse_wav_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, ++ unsigned int *format) { ++ WaveHeader wave_header; ++ WaveChunkHeader chunk_header; ++ WaveFmtBody fmt_body; ++ int more_chunks = 1; ++ ++ fread(&wave_header, sizeof(WaveHeader), 1, file); ++ if ((wave_header.magic != WAV_RIFF) || ++ (wave_header.type != WAV_WAVE)) { ++ fprintf(stderr, "Error: it is not a riff/wave file\n"); ++ return -1; ++ } ++ ++ do { ++ fread(&chunk_header, sizeof(WaveChunkHeader), 1, file); ++ switch (chunk_header.type) { ++ case WAV_FMT: ++ fread(&fmt_body, sizeof(WaveFmtBody), 1, file); ++ /* If the format header is larger, skip the rest */ ++ if (chunk_header.length > sizeof(WaveFmtBody)) ++ fseek(file, chunk_header.length - sizeof(WaveFmtBody), SEEK_CUR); ++ ++ *num_channels = fmt_body.channels; ++ *sample_rate = fmt_body.sample_fq; ++ ++ switch (fmt_body.bit_p_spl) { ++ case 8: ++ *format = SND_PCM_FORMAT_U8; ++ break; ++ case 16: ++ *format = SND_PCM_FORMAT_S16_LE; ++ break; ++ case 24: ++ switch (fmt_body.byte_p_spl / fmt_body.channels) { ++ case 3: ++ *format = SND_PCM_FORMAT_S24_3LE; ++ break; ++ case 4: ++ *format = SND_PCM_FORMAT_S24_LE; ++ break; ++ default: ++ fprintf(stderr, "format error\n"); ++ return -1; ++ } ++ break; ++ case 32: ++ if (fmt_body.format == WAV_FMT_PCM) { ++ *format = SND_PCM_FORMAT_S32_LE; ++ } else if (fmt_body.format == WAV_FMT_IEEE_FLOAT) { ++ *format = SND_PCM_FORMAT_FLOAT_LE; ++ } ++ break; ++ default: ++ fprintf(stderr, "format error\n"); ++ return -1; ++ } ++ break; ++ case WAV_DATA: ++ /* Stop looking for chunks */ ++ more_chunks = 0; ++ break; ++ default: ++ /* Unknown chunk, skip bytes */ ++ fseek(file, chunk_header.length, SEEK_CUR); ++ } ++ } while (more_chunks); ++ ++ return 0; ++} ++ + static int print_time(struct compress *compress) + { + unsigned int avail; +@@ -385,6 +460,35 @@ void get_codec_iec(FILE *file, struct compr_config *config, + codec->format = 0; + } + ++void get_codec_pcm(FILE *file, struct compr_config *config, ++ struct snd_codec *codec) ++{ ++ unsigned int channels, rate, format; ++ ++ if (parse_wav_header(file, &channels, &rate, &format) == -1) { ++ fclose(file); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (channels > 2 || (format != SND_PCM_FORMAT_S16_LE && format != SND_PCM_FORMAT_S32_LE) || ++ rate > 192000) { ++ fprintf(stderr, "unsupported wave file\n"); ++ fclose(file); ++ exit(EXIT_FAILURE); ++ } ++ ++ codec->id = SND_AUDIOCODEC_PCM; ++ codec->ch_in = channels; ++ codec->ch_out = channels; ++ codec->sample_rate = rate; ++ codec->bit_rate = 0; ++ codec->rate_control = 0; ++ codec->profile = SND_AUDIOPROFILE_PCM; ++ codec->level = 0; ++ codec->ch_mode = 0; ++ codec->format = format; ++} ++ + void play_samples(char *name, unsigned int card, unsigned int device, + unsigned long buffer_size, unsigned int frag, + unsigned long codec_id) +@@ -411,6 +515,9 @@ void play_samples(char *name, unsigned int card, unsigned int device, + case SND_AUDIOCODEC_IEC61937: + get_codec_iec(file, &config, &codec); + break; ++ case SND_AUDIOCODEC_PCM: ++ get_codec_pcm(file, &config, &codec); ++ break; + default: + fprintf(stderr, "codec ID %ld is not supported\n", codec_id); + exit(EXIT_FAILURE); +-- +2.27.0 + diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch new file mode 100755 index 000000000..045714aa9 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch @@ -0,0 +1,147 @@ +From 6f778c21ee357a662cdd758cff578a3e4b85eedf Mon Sep 17 00:00:00 2001 +From: Zhang Peng +Date: Tue, 4 Aug 2020 15:29:29 +0800 +Subject: [PATCH] cplay: Add pause feature + +Add option: -p pause + +Upstream-Status: Inappropriate [i.MX specific] + +Signed-off-by: Zhang Peng +--- + src/utils/cplay.c | 56 +++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 52 insertions(+), 4 deletions(-) + +diff --git a/src/utils/cplay.c b/src/utils/cplay.c +index 8882f4d..8e3dcbb 100644 +--- a/src/utils/cplay.c ++++ b/src/utils/cplay.c +@@ -117,6 +117,9 @@ static void usage(void) + "-f\tfragments\n\n" + "-v\tverbose mode\n" + "-h\tPrints this help list\n\n" ++ "-p\tpause\n" ++ "-m\tpause blocks\n" ++ "-n\tpause time duration\n" + "Example:\n" + "\tcplay -c 1 -d 2 test.mp3\n" + "\tcplay -f 5 test.mp3\n\n" +@@ -133,7 +136,8 @@ static void usage(void) + + void play_samples(char *name, unsigned int card, unsigned int device, + unsigned long buffer_size, unsigned int frag, +- unsigned long codec_id); ++ unsigned long codec_id, int pause_count, int pause_block, ++ int pause_duration); + + struct mp3_header { + uint16_t sync; +@@ -262,12 +266,15 @@ int main(int argc, char **argv) + int c, i; + unsigned int card = 0, device = 0, frag = 0; + unsigned int codec_id = SND_AUDIOCODEC_MP3; ++ int pause_count = 0; ++ int pause_block = 6; ++ int pause_duration = 10; + + if (argc < 2) + usage(); + + verbose = 0; +- while ((c = getopt(argc, argv, "hvb:f:c:d:I:")) != -1) { ++ while ((c = getopt(argc, argv, "hvb:f:c:d:I:p:m:n:")) != -1) { + switch (c) { + case 'h': + usage(); +@@ -306,6 +313,23 @@ int main(int argc, char **argv) + case 'v': + verbose = 1; + break; ++ case 'p': ++ pause_count = strtol(optarg, NULL, 10); ++ break; ++ case 'm': ++ pause_block = strtol(optarg, NULL, 10); ++ if (pause_duration < 0) { ++ printf("Set wrong paramter! Set duration default 6.\n"); ++ pause_duration = 6; ++ } ++ break; ++ case 'n': ++ pause_duration = strtol(optarg, NULL, 10); ++ if (pause_duration < 0) { ++ printf("Set wrong paramter! Set duration default 10.\n"); ++ pause_duration = 10; ++ } ++ break; + default: + exit(EXIT_FAILURE); + } +@@ -315,7 +339,7 @@ int main(int argc, char **argv) + + file = argv[optind]; + +- play_samples(file, card, device, buffer_size, frag, codec_id); ++ play_samples(file, card, device, buffer_size, frag, codec_id, pause_count, pause_block, pause_duration); + + fprintf(stderr, "Finish Playing.... Close Normally\n"); + exit(EXIT_SUCCESS); +@@ -491,7 +515,8 @@ void get_codec_pcm(FILE *file, struct compr_config *config, + + void play_samples(char *name, unsigned int card, unsigned int device, + unsigned long buffer_size, unsigned int frag, +- unsigned long codec_id) ++ unsigned long codec_id, int pause_count, int pause_block, ++ int pause_duration) + { + struct compr_config config; + struct snd_codec codec; +@@ -499,6 +524,7 @@ void play_samples(char *name, unsigned int card, unsigned int device, + FILE *file; + char *buffer; + int size, num_read, wrote; ++ int write_count = 0; + + if (verbose) + printf("%s: entry\n", __func__); +@@ -574,6 +600,13 @@ void play_samples(char *name, unsigned int card, unsigned int device, + if (verbose) + printf("%s: You should hear audio NOW!!!\n", __func__); + ++ if (pause_count > 0) { ++ printf("sleep...\n"); ++ compress_pause(compress); ++ sleep(pause_duration); ++ compress_resume(compress); ++ } ++ + do { + num_read = fread(buffer, 1, size, file); + if (num_read > 0) { +@@ -592,8 +625,23 @@ void play_samples(char *name, unsigned int card, unsigned int device, + printf("%s: wrote %d\n", __func__, wrote); + } + } ++ write_count++; ++ if ((pause_count > 0) && (write_count % pause_block == 0)) { ++ printf("pause...\n"); ++ compress_pause(compress); ++ sleep(pause_duration); ++ printf("pause release...\n"); ++ compress_resume(compress); ++ pause_count--; ++ } + } while (num_read > 0); + ++ if (pause_count > 0) { ++ compress_pause(compress); ++ sleep(5); ++ compress_resume(compress); ++ } ++ + if (verbose) + printf("%s: exit success\n", __func__); + /* issue drain if it supports */ +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch new file mode 100755 index 000000000..994fc14e2 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch @@ -0,0 +1,41 @@ +From a2892bf5db7520689fa9cb1d1589fa804bd9dc1a Mon Sep 17 00:00:00 2001 +From: Bing Song +Date: Tue, 18 Aug 2020 15:26:51 +0800 +Subject: [PATCH] tinycompress: pass NULL buffer with 0 size to driver. + +The NULL buffer with 0 size to indecate driver drain input data with +non-block mode. The defaul drain is block mode. + +upstream status: imx specific + +Signed-off-by: Bing Song +--- + src/lib/compress.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/lib/compress.c b/src/lib/compress.c +index bba4fcf..d66df0b 100644 +--- a/src/lib/compress.c ++++ b/src/lib/compress.c +@@ -315,7 +315,8 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size + fds.events = POLLOUT; + + /*TODO: treat auto start here first */ +- while (size) { ++ /* NULL buffer with 0 size for non-block drain */ ++ do { + if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail)) + return oops(compress, errno, "cannot get avail"); + +@@ -357,7 +358,7 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size + size -= written; + cbuf += written; + total += written; +- } ++ } while (size); + return total; + } + +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch new file mode 100755 index 000000000..216426885 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch @@ -0,0 +1,252 @@ +From 2912f8573cea25fbd38ac7a8b68af2ea6a05e599 Mon Sep 17 00:00:00 2001 +From: Zhang Peng +Date: Wed, 28 Oct 2020 19:08:53 +0800 +Subject: [PATCH] cplay: Support aac streams + +Support run aac format streams for cplay. + +upstream status: imx specific + +Signed-off-by: Zhang Peng +--- + src/utils/cplay.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 210 insertions(+) + +diff --git a/src/utils/cplay.c b/src/utils/cplay.c +index 8e3dcbb..2a1464a 100644 +--- a/src/utils/cplay.c ++++ b/src/utils/cplay.c +@@ -245,6 +245,190 @@ static int parse_wav_header(FILE *file, unsigned int *num_channels, unsigned int + return 0; + } + ++int find_adts_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, unsigned int *format) ++{ ++ int ret; ++ unsigned char buf[5]; ++ ++ ret = fread(buf, sizeof(buf), 1, file); ++ if (ret < 0) { ++ fprintf(stderr, "open file error: %d\n", ret); ++ return 0; ++ } ++ fseek(file, 0, SEEK_SET); ++ ++ if ((buf[0] != 0xff) || (buf[1] & 0xf0 != 0xf0)) ++ return 0; ++ /* mpeg id */ ++ switch (buf[1]>>3 & 0x1) { ++ case 0x0: ++ *format = SND_AUDIOSTREAMFORMAT_MP4ADTS; ++ break; ++ case 0x1: ++ *format = SND_AUDIOSTREAMFORMAT_MP2ADTS; ++ break; ++ default: ++ fprintf(stderr, "can't find stream format\n"); ++ break; ++ } ++ /* sample_rate */ ++ switch (buf[2]>>2 & 0xf) { ++ case 0x0: ++ *sample_rate = 96000; ++ break; ++ case 0x1: ++ *sample_rate = 88200; ++ break; ++ case 0x2: ++ *sample_rate = 64000; ++ break; ++ case 0x3: ++ *sample_rate = 48000; ++ break; ++ case 0x4: ++ *sample_rate = 44100; ++ break; ++ case 0x5: ++ *sample_rate = 32000; ++ break; ++ case 0x6: ++ *sample_rate = 24000; ++ break; ++ case 0x7: ++ *sample_rate = 22050; ++ break; ++ case 0x8: ++ *sample_rate = 16000; ++ break; ++ case 0x9: ++ *sample_rate = 12000; ++ break; ++ case 0xa: ++ *sample_rate = 11025; ++ break; ++ case 0xb: ++ *sample_rate = 8000; ++ break; ++ case 0xc: ++ *sample_rate = 7350; ++ break; ++ default: ++ break; ++ } ++ /* channel */ ++ switch (((buf[2]&0x1) << 2) | (buf[3]>>6)) { ++ case 1: ++ *num_channels = 1; ++ break; ++ case 2: ++ *num_channels = 2; ++ break; ++ case 3: ++ *num_channels = 3; ++ break; ++ case 4: ++ *num_channels = 4; ++ break; ++ case 5: ++ *num_channels = 5; ++ break; ++ case 6: ++ *num_channels = 6; ++ break; ++ case 7: ++ *num_channels = 7; ++ break; ++ default: ++ break; ++ } ++ return 1; ++} ++ ++static const int aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100, ++ 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 ++}; ++ ++#define MAX_SR_NUM sizeof(aac_sample_rates)/sizeof(aac_sample_rates[0]) ++ ++static int get_sample_rate_from_index(int sr_index) ++{ ++ if (sr_index >= 0 && sr_index < MAX_SR_NUM) ++ return aac_sample_rates[sr_index]; ++ ++ return 0; ++} ++ ++int find_adif_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, unsigned int *format) ++{ ++ int ret; ++ unsigned char adif_id[4]; ++ unsigned char adif_header[20]; ++ int bitstream_type; ++ int bitrate; ++ int object_type; ++ int sr_index; ++ int skip_size = 0; ++ ++ ret = fread(adif_id, sizeof(unsigned char), 4, file); ++ if (ret < 0) { ++ fprintf(stderr, "read data from file err: %d\n", ret); ++ return 0; ++ } ++ /* adif id */ ++ if ((adif_id[0] != 0x41) || (adif_id[1] != 0x44) || ++ (adif_id[2] != 0x49) || (adif_id[3] != 0x46)) ++ return 0; ++ ++ fread(adif_header, sizeof(unsigned char), 20, file); ++ ++ /* copyright string */ ++ if (adif_header[0] & 0x80) ++ skip_size = 9; ++ ++ bitstream_type = adif_header[0 + skip_size] & 0x10; ++ bitrate = ++ ((unsigned int) (adif_header[0 + skip_size] & 0x0f) << 19) | ++ ((unsigned int) adif_header[1 + skip_size] << 11) | ++ ((unsigned int) adif_header[2 + skip_size] << 3) | ++ ((unsigned int) adif_header[3 + skip_size] & 0xe0); ++ ++ if (bitstream_type == 0) { ++ object_type = ((adif_header[6 + skip_size] & 0x01) << 1) | ++ ((adif_header[7 + skip_size] & 0x80) >> 7); ++ sr_index = (adif_header[7 + skip_size] & 0x78) >> 3; ++ } ++ /* VBR */ ++ else { ++ object_type = (adif_header[4 + skip_size] & 0x18) >> 3; ++ sr_index = ((adif_header[4 + skip_size] & 0x07) << 1) | ++ ((adif_header[5 + skip_size] & 0x80) >> 7); ++ } ++ ++ /* sample rate */ ++ *sample_rate = get_sample_rate_from_index(sr_index); ++ ++ /* FIXME: assume channels is 2 */ ++ *num_channels = 2; ++ ++ *format = SND_AUDIOSTREAMFORMAT_ADIF; ++ fseek(file, 0, SEEK_SET); ++ return 1; ++} ++ ++static int parse_aac_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, unsigned int *format) ++{ ++ if (find_adts_header(file, num_channels, sample_rate, format)) ++ return 1; ++ else if (find_adif_header(file, num_channels, sample_rate, format)) ++ return 1; ++ else { ++ fprintf(stderr, "can't find streams format\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ + static int print_time(struct compress *compress) + { + unsigned int avail; +@@ -513,6 +697,29 @@ void get_codec_pcm(FILE *file, struct compr_config *config, + codec->format = format; + } + ++void get_codec_aac(FILE *file, struct compr_config *config, ++ struct snd_codec *codec) ++{ ++ unsigned int channels, rate, format; ++ ++ if (parse_aac_header(file, &channels, &rate, &format) == 0) { ++ fclose(file); ++ exit(EXIT_FAILURE); ++ }; ++ fseek(file, 0, SEEK_SET); ++ ++ codec->id = SND_AUDIOCODEC_AAC; ++ codec->ch_in = channels; ++ codec->ch_out = channels; ++ codec->sample_rate = rate; ++ codec->bit_rate = 0; ++ codec->rate_control = 0; ++ codec->profile = SND_AUDIOPROFILE_AAC; ++ codec->level = 0; ++ codec->ch_mode = 0; ++ codec->format = format; ++ ++} + void play_samples(char *name, unsigned int card, unsigned int device, + unsigned long buffer_size, unsigned int frag, + unsigned long codec_id, int pause_count, int pause_block, +@@ -544,6 +751,9 @@ void play_samples(char *name, unsigned int card, unsigned int device, + case SND_AUDIOCODEC_PCM: + get_codec_pcm(file, &config, &codec); + break; ++ case SND_AUDIOCODEC_AAC: ++ get_codec_aac(file, &config, &codec); ++ break; + default: + fprintf(stderr, "codec ID %ld is not supported\n", codec_id); + exit(EXIT_FAILURE); +-- +2.17.1 + diff --git a/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress_1.1.6.bb b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress_1.1.6.bb new file mode 100644 index 000000000..de580dfb6 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/pulseaudio/tinycompress/tinycompress_1.1.6.bb @@ -0,0 +1,19 @@ +SUMMARY = "tinycompress library for compress audio offload in alsa" +DESCRIPTION = "A library to handle compressed formats like MP3 etc" +LICENSE = "BSD-3-Clause" + +inherit autotools pkgconfig +LIC_FILES_CHKSUM = "file://COPYING;md5=cf9105c1a2d4405cbe04bbe3367373a0" + +DEPENDS_append = " alsa-lib" + +SRC_URI = "git://git.alsa-project.org/tinycompress.git;protocol=git;branch=master \ + file://0001-tinycompress-Add-id3-decoding.patch \ + file://0002-cplay-Support-wave-file.patch \ + file://0003-cplay-Add-pause-feature.patch \ + file://0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch \ + file://0005-cplay-Support-aac-streams.patch \ +" +SRCREV = "995f2ed91045dad8c20485ab1a64727d22cd92e5" + +S = "${WORKDIR}/git"