Merge "hal: accumulate written frames when error occurred during write"
diff --git a/configs/msm8998/audio_platform_info.xml b/configs/msm8998/audio_platform_info.xml
index 56ac9bb..3e8ff0e 100644
--- a/configs/msm8998/audio_platform_info.xml
+++ b/configs/msm8998/audio_platform_info.xml
@@ -49,7 +49,6 @@
<usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD6" type="out" id="30"/>
<usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD7" type="out" id="31"/>
<usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD8" type="out" id="32"/>
- <usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD9" type="out" id="33"/>
<usecase name="USECASE_VOICEMMODE1_CALL" type="in" id="2"/>
<usecase name="USECASE_VOICEMMODE1_CALL" type="out" id="2"/>
<usecase name="USECASE_VOICEMMODE2_CALL" type="in" id="19"/>
@@ -65,6 +64,8 @@
<usecase name="USECASE_AUDIO_RECORD_LOW_LATENCY" type="in" id="17" />
<usecase name="USECASE_AUDIO_PLAYBACK_ULL" type="out" id="17" />
<usecase name="USECASE_AUDIO_PLAYBACK_EXT_DISP_SILENCE" type="out" id="27" />
+ <usecase name="USECASE_AUDIO_PLAYBACK_MMAP" type="out" id="33" />
+ <usecase name="USECASE_AUDIO_RECORD_MMAP" type="in" id="33" />
</pcm_ids>
<config_params>
<param key="spkr_1_tz_name" value="wsatz.13"/>
diff --git a/configs/msm8998/audio_policy_configuration.xml b/configs/msm8998/audio_policy_configuration.xml
index 09a4bb9..ff0820e 100644
--- a/configs/msm8998/audio_policy_configuration.xml
+++ b/configs/msm8998/audio_policy_configuration.xml
@@ -68,6 +68,10 @@
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
<mixPort name="deep_buffer" role="source"
flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
@@ -191,6 +195,11 @@
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000,48000" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
</mixPort>
+ <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3"/>
+ </mixPort>
</mixPorts>
<devicePorts>
@@ -302,15 +311,15 @@
<!-- route declaration, i.e. list all available sources for a given sink -->
<routes>
<route type="mix" sink="Earpiece"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Speaker"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Wired Headset"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Wired Headphones"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Line"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="HDMI"
sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,compress_passthrough"/>
<route type="mix" sink="Proxy"
@@ -318,9 +327,9 @@
<route type="mix" sink="FM"
sources="primary output"/>
<route type="mix" sink="BT SCO All"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="USB Device Out"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Telephony Tx"
sources="voice_tx"/>
<route type="mix" sink="voice_rx"
@@ -331,6 +340,8 @@
sources="Built-In Mic,Built-In Back Mic"/>
<route type="mix" sink="record_24"
sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic"/>
+ <route type="mix" sink="mmap_no_irq_in"
+ sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,USB Device In"/>
<route type="mix" sink="BT A2DP Out"
sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload"/>
<route type="mix" sink="BT A2DP Headphones"
diff --git a/configs/msm8998/mixer_paths_tavil.xml b/configs/msm8998/mixer_paths_tavil.xml
index 51a3083..87223d6 100644
--- a/configs/msm8998/mixer_paths_tavil.xml
+++ b/configs/msm8998/mixer_paths_tavil.xml
@@ -297,6 +297,7 @@
<ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia4" value="0" />
<ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia5" value="0" />
<ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia6" value="0" />
+ <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia16" value="0" />
<ctl name="MultiMedia1 Mixer SLIM_7_TX" value="0" />
<!-- audio record compress-->
<ctl name="MultiMedia8 Mixer SLIM_0_TX" value="0" />
@@ -2593,4 +2594,83 @@
<path name="audio-ull-playback bt-a2dp" />
<path name="audio-ull-playback" />
</path>
+
+ <path name="mmap-playback">
+ <ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback headphones">
+ <ctl name="SLIMBUS_6_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-headphones">
+ <path name="mmap-playback" />
+ <path name="mmap-playback headphones" />
+ </path>
+
+ <path name="mmap-playback bt-sco">
+ <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback bt-sco-wb">
+ <ctl name="BT SampleRate" value="KHZ_16" />
+ <path name="mmap-playback bt-sco" />
+ </path>
+
+ <path name="mmap-playback afe-proxy">
+ <ctl name="AFE_PCM_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headphones">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headset">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback display-port">
+ <ctl name="DISPLAY_PORT Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-buffer-playback hdmi">
+ <ctl name="HDMI Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-hdmi">
+ <path name="mmap-playback hdmi" />
+ <path name="mmap-playback" />
+ </path>
+
+ <path name="mmap-playback speaker-and-display-port">
+ <path name="mmap-playback display-port" />
+ <path name="mmap-playback" />
+ </path>
+
+ <path name="mmap-playback speaker-and-usb-headphones">
+ <path name="mmap-playback usb-headphones" />
+ <path name="mmap-playback" />
+ </path>
+
+ <path name="mmap-record">
+ <ctl name="MultiMedia16 Mixer SLIM_0_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco">
+ <ctl name="MultiMedia16 Mixer SLIM_7_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco-wb">
+ <ctl name="BT SampleRate" value="KHZ_16" />
+ <path name="mmap-record bt-sco" />
+ </path>
+
+ <path name="mmap-record capture-fm">
+ <ctl name="MultiMedia16 Mixer SLIM_8_TX" value="1" />
+ </path>
+
+ <path name="mmap-record usb-headset-mic">
+ <ctl name="MultiMedia16 Mixer USB_AUDIO_TX" value="1" />
+ </path>
+
</mixer>
diff --git a/configs/sdm660/mixer_paths.xml b/configs/sdm660/mixer_paths.xml
index 75082c7..459ffa1 100644
--- a/configs/sdm660/mixer_paths.xml
+++ b/configs/sdm660/mixer_paths.xml
@@ -67,6 +67,7 @@
<ctl name="MultiMedia1 Mixer SLIM_7_TX" value="0" />
<ctl name="MultiMedia8 Mixer INT3_MI2S_TX" value="0" />
<ctl name="MultiMedia8 Mixer SLIM_7_TX" value="0" />
+ <ctl name="MultiMedia16 Mixer SLIM_7_TX" value="0" />
<ctl name="HDMI Mixer MultiMedia1" value="0" />
<ctl name="HDMI Mixer MultiMedia2" value="0" />
<ctl name="HDMI Mixer MultiMedia3" value="0" />
@@ -2256,4 +2257,59 @@
<path name="audio-ull-playback bt-a2dp" />
<path name="audio-ull-playback" />
</path>
+
+ <path name="mmap-playback">
+ <ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback headphones">
+ <ctl name="SLIMBUS_6_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-headphones">
+ <path name="mmap-playback" />
+ <path name="mmap-playback headphones" />
+ </path>
+
+ <path name="mmap-playback bt-sco">
+ <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback bt-sco-wb">
+ <ctl name="BT SampleRate" value="16000" />
+ <path name="mmap-playback bt-sco" />
+ </path>
+
+ <path name="mmap-playback afe-proxy">
+ <ctl name="AFE_PCM_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headphones">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headset">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-record">
+ <ctl name="MultiMedia16 Mixer SLIM_0_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco">
+ <ctl name="MultiMedia16 Mixer SLIM_7_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco-wb">
+ <ctl name="AUX PCM SampleRate" value="16000" />
+ <path name="mmap-record bt-sco" />
+ </path>
+
+ <path name="mmap-record capture-fm">
+ <ctl name="MultiMedia16 Mixer TERT_MI2S_TX" value="1" />
+ </path>
+
+ <path name="mmap-record usb-headset-mic">
+ <ctl name="MultiMedia16 Mixer USB_AUDIO_TX" value="1" />
+ </path>
</mixer>
diff --git a/configs/sdm660/mixer_paths_wcd9335.xml b/configs/sdm660/mixer_paths_wcd9335.xml
index 964c5bc..8cc6f65 100644
--- a/configs/sdm660/mixer_paths_wcd9335.xml
+++ b/configs/sdm660/mixer_paths_wcd9335.xml
@@ -2817,4 +2817,58 @@
<path name="audio-ull-playback" />
</path>
+ <path name="mmap-playback">
+ <ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback headphones">
+ <ctl name="SLIMBUS_6_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-headphones">
+ <path name="mmap-playback" />
+ <path name="mmap-playback headphones" />
+ </path>
+
+ <path name="mmap-playback bt-sco">
+ <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback bt-sco-wb">
+ <ctl name="BT SampleRate" value="16000" />
+ <path name="mmap-playback bt-sco" />
+ </path>
+
+ <path name="mmap-playback afe-proxy">
+ <ctl name="AFE_PCM_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headphones">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headset">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-record">
+ <ctl name="MultiMedia16 Mixer SLIM_0_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco">
+ <ctl name="MultiMedia16 Mixer SLIM_7_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco-wb">
+ <ctl name="BT SampleRate" value="KHZ_16" />
+ <path name="mmap-record bt-sco" />
+ </path>
+
+ <path name="mmap-record capture-fm">
+ <ctl name="MultiMedia16 Mixer SLIM_8_TX" value="1" />
+ </path>
+
+ <path name="mmap-record usb-headset-mic">
+ <ctl name="MultiMedia16 Mixer USB_AUDIO_TX" value="1" />
+ </path>
</mixer>
diff --git a/configs/sdm660/mixer_paths_wcd9340.xml b/configs/sdm660/mixer_paths_wcd9340.xml
index 2b7f422..213f5c3 100644
--- a/configs/sdm660/mixer_paths_wcd9340.xml
+++ b/configs/sdm660/mixer_paths_wcd9340.xml
@@ -2564,4 +2564,59 @@
<path name="audio-ull-playback" />
</path>
+ <path name="mmap-playback">
+ <ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback headphones">
+ <ctl name="SLIMBUS_6_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-headphones">
+ <path name="mmap-playback" />
+ <path name="mmap-playback headphones" />
+ </path>
+
+ <path name="mmap-playback bt-sco">
+ <ctl name="AUX_PCM_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback bt-sco-wb">
+ <ctl name="AUX PCM SampleRate" value="16000" />
+ <path name="mmap-playback bt-sco" />
+ </path>
+
+ <path name="mmap-playback afe-proxy">
+ <ctl name="AFE_PCM_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headphones">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headset">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-record">
+ <ctl name="MultiMedia16 Mixer SLIM_0_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco">
+ <ctl name="MultiMedia16 Mixer AUX_PCM_UL_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco-wb">
+ <ctl name="AUX PCM SampleRate" value="16000" />
+ <path name="mmap-record bt-sco" />
+ </path>
+
+ <path name="mmap-record capture-fm">
+ <ctl name="MultiMedia16 Mixer TERT_MI2S_TX" value="1" />
+ </path>
+
+ <path name="mmap-record usb-headset-mic">
+ <ctl name="MultiMedia16 Mixer USB_AUDIO_TX" value="1" />
+ </path>
+
</mixer>
diff --git a/configs/sdm845/audio_platform_info.xml b/configs/sdm845/audio_platform_info.xml
index abbb294..2ebf284 100644
--- a/configs/sdm845/audio_platform_info.xml
+++ b/configs/sdm845/audio_platform_info.xml
@@ -49,7 +49,6 @@
<usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD6" type="out" id="30"/>
<usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD7" type="out" id="31"/>
<usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD8" type="out" id="32"/>
- <usecase name="USECASE_AUDIO_PLAYBACK_OFFLOAD9" type="out" id="33"/>
<usecase name="USECASE_VOICEMMODE1_CALL" type="in" id="2"/>
<usecase name="USECASE_VOICEMMODE1_CALL" type="out" id="2"/>
<usecase name="USECASE_VOICEMMODE2_CALL" type="in" id="19"/>
@@ -67,6 +66,8 @@
<usecase name="USECASE_AUDIO_PLAYBACK_EXT_DISP_SILENCE" type="out" id="27" />
<usecase name="USECASE_AUDIO_PLAYBACK_VOIP" type="out" id="16" />
<usecase name="USECASE_AUDIO_RECORD_VOIP" type="in" id="16" />
+ <usecase name="USECASE_AUDIO_PLAYBACK_MMAP" type="out" id="33" />
+ <usecase name="USECASE_AUDIO_RECORD_MMAP" type="in" id="33" />
</pcm_ids>
<config_params>
<param key="spkr_1_tz_name" value="wsatz.13"/>
diff --git a/configs/sdm845/audio_policy_configuration.xml b/configs/sdm845/audio_policy_configuration.xml
index 09a4bb9..655919b 100644
--- a/configs/sdm845/audio_policy_configuration.xml
+++ b/configs/sdm845/audio_policy_configuration.xml
@@ -73,6 +73,10 @@
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
<mixPort name="compress_passthrough" role="source"
flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
<profile name="" format="dynamic"
@@ -191,6 +195,11 @@
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000,48000" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
</mixPort>
+ <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3"/>
+ </mixPort>
</mixPorts>
<devicePorts>
@@ -302,15 +311,15 @@
<!-- route declaration, i.e. list all available sources for a given sink -->
<routes>
<route type="mix" sink="Earpiece"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Speaker"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Wired Headset"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Wired Headphones"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Line"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,dsd_compress_passthrough,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="HDMI"
sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,compress_passthrough"/>
<route type="mix" sink="Proxy"
@@ -320,7 +329,7 @@
<route type="mix" sink="BT SCO All"
sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
<route type="mix" sink="USB Device Out"
- sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx"/>
+ sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out"/>
<route type="mix" sink="Telephony Tx"
sources="voice_tx"/>
<route type="mix" sink="voice_rx"
@@ -331,6 +340,8 @@
sources="Built-In Mic,Built-In Back Mic"/>
<route type="mix" sink="record_24"
sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic"/>
+ <route type="mix" sink="mmap_no_irq_in"
+ sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,USB Device In"/>
<route type="mix" sink="BT A2DP Out"
sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload"/>
<route type="mix" sink="BT A2DP Headphones"
diff --git a/configs/sdm845/mixer_paths_tavil.xml b/configs/sdm845/mixer_paths_tavil.xml
index 41d980b..dda402f 100644
--- a/configs/sdm845/mixer_paths_tavil.xml
+++ b/configs/sdm845/mixer_paths_tavil.xml
@@ -2454,4 +2454,83 @@
<path name="audio-ull-playback bt-a2dp" />
<path name="audio-ull-playback" />
</path>
+
+ <path name="mmap-playback">
+ <ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback headphones">
+ <ctl name="SLIMBUS_6_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-headphones">
+ <path name="mmap-playback" />
+ <path name="mmap-playback headphones" />
+ </path>
+
+ <path name="mmap-playback bt-sco">
+ <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback bt-sco-wb">
+ <ctl name="BT SampleRate" value="16000" />
+ <path name="mmap-playback bt-sco" />
+ </path>
+
+ <path name="mmap-playback afe-proxy">
+ <ctl name="AFE_PCM_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headphones">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback usb-headset">
+ <ctl name="USB_AUDIO_RX Audio Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback display-port">
+ <ctl name="DISPLAY_PORT Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-buffer-playback hdmi">
+ <ctl name="HDMI Mixer MultiMedia16" value="1" />
+ </path>
+
+ <path name="mmap-playback speaker-and-hdmi">
+ <path name="mmap-playback hdmi" />
+ <path name="mmap-playback" />
+ </path>
+
+ <path name="mmap-playback speaker-and-display-port">
+ <path name="mmap-playback display-port" />
+ <path name="mmap-playback" />
+ </path>
+
+ <path name="mmap-playback speaker-and-usb-headphones">
+ <path name="mmap-playback usb-headphones" />
+ <path name="mmap-playback" />
+ </path>
+
+ <path name="mmap-record">
+ <ctl name="MultiMedia16 Mixer SLIM_0_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco">
+ <ctl name="MultiMedia16 Mixer SLIM_7_TX" value="1" />
+ </path>
+
+ <path name="mmap-record bt-sco-wb">
+ <ctl name="BT SampleRate" value="KHZ_16" />
+ <path name="mmap-record bt-sco" />
+ </path>
+
+ <path name="mmap-record capture-fm">
+ <ctl name="MultiMedia16 Mixer SLIM_8_TX" value="1" />
+ </path>
+
+ <path name="mmap-record usb-headset-mic">
+ <ctl name="MultiMedia16 Mixer USB_AUDIO_TX" value="1" />
+ </path>
+
</mixer>
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 4aad5f0..2103930 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -929,7 +929,8 @@
a2dp.a2dp_suspended = true;
list_for_each(node, &a2dp.adev->usecase_list) {
uc_info = node_to_item(node, struct audio_usecase, list);
- if (uc_info->type == PCM_PLAYBACK) {
+ if (uc_info->type == PCM_PLAYBACK &&
+ (uc_info->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
pthread_mutex_unlock(&a2dp.adev->lock);
check_a2dp_restore(a2dp.adev, uc_info->stream.out, false);
pthread_mutex_lock(&a2dp.adev->lock);
@@ -968,7 +969,8 @@
}
list_for_each(node, &a2dp.adev->usecase_list) {
uc_info = node_to_item(node, struct audio_usecase, list);
- if (uc_info->type == PCM_PLAYBACK) {
+ if (uc_info->type == PCM_PLAYBACK &&
+ (uc_info->stream.out->devices & AUDIO_DEVICE_OUT_ALL_A2DP)) {
pthread_mutex_unlock(&a2dp.adev->lock);
check_a2dp_restore(a2dp.adev, uc_info->stream.out, true);
pthread_mutex_lock(&a2dp.adev->lock);
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index dfe8c61..4e5f4d8 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -236,6 +236,17 @@
struct audio_device_cfg_param dev_cfg_params;
};
+typedef struct mix_matrix_params {
+ uint16_t num_output_channels;
+ uint16_t num_input_channels;
+ uint8_t has_output_channel_map;
+ uint32_t output_channel_map[AUDIO_CHANNEL_COUNT_MAX];
+ uint8_t has_input_channel_map;
+ uint32_t input_channel_map[AUDIO_CHANNEL_COUNT_MAX];
+ uint8_t has_mixer_coeffs;
+ float mixer_coeffs[AUDIO_CHANNEL_COUNT_MAX][AUDIO_CHANNEL_COUNT_MAX];
+} mix_matrix_params_t;
+
typedef union {
struct source_tracking_param st_params;
struct sound_focus_param sf_params;
@@ -248,6 +259,7 @@
struct audio_adsp_event adsp_event_params;
struct audio_out_channel_map_param channel_map_param;
struct audio_device_cfg_param device_cfg;
+ struct mix_matrix_params mm_params;
} audio_extn_param_payload;
typedef enum {
@@ -264,7 +276,11 @@
AUDIO_EXTN_PARAM_ADSP_STREAM_CMD,
/* param to set input channel map for playback stream */
AUDIO_EXTN_PARAM_OUT_CHANNEL_MAP,
- AUDIO_EXTN_PARAM_DEVICE_CONFIG
+ AUDIO_EXTN_PARAM_DEVICE_CONFIG,
+ /* Pan/scale params to be set on ASM */
+ AUDIO_EXTN_PARAM_OUT_MIX_MATRIX_PARAMS,
+ /* Downmix params to be set on ADM */
+ AUDIO_EXTN_PARAM_CH_MIX_MATRIX_PARAMS
} audio_extn_param_id;
#endif /* AUDIO_DEFS_H */
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 804027b..84de66f 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1161,6 +1161,7 @@
"perf_lock_acq");
if (perf_lock_acq == NULL) {
ALOGE("%s: Perf lock Acquire NULL \n", __func__);
+ dlclose(qcopt_handle);
ret = -EINVAL;
goto err;
}
@@ -1168,6 +1169,7 @@
"perf_lock_rel");
if (perf_lock_rel == NULL) {
ALOGE("%s: Perf lock Release NULL \n", __func__);
+ dlclose(qcopt_handle);
ret = -EINVAL;
goto err;
}
@@ -1377,6 +1379,14 @@
ret = audio_extn_utils_set_channel_map(out,
(struct audio_out_channel_map_param *)(payload));
break;
+ case AUDIO_EXTN_PARAM_OUT_MIX_MATRIX_PARAMS:
+ ret = audio_extn_utils_set_pan_scale_params(out,
+ (struct mix_matrix_params *)(payload));
+ break;
+ case AUDIO_EXTN_PARAM_CH_MIX_MATRIX_PARAMS:
+ ret = audio_extn_utils_set_downmix_params(out,
+ (struct mix_matrix_params *)(payload));
+ break;
default:
ALOGE("%s:: unsupported param_id %d", __func__, param_id);
break;
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 4f0106d..5707742 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -103,6 +103,10 @@
#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x10000
#endif
+#ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#endif
+
#ifndef COMPRESS_METADATA_NEEDED
#define audio_extn_parse_compress_metadata(out, parms) (0)
#else
@@ -893,6 +897,12 @@
int audio_extn_utils_set_channel_map(
struct stream_out *out,
struct audio_out_channel_map_param *channel_map_param);
+int audio_extn_utils_set_pan_scale_params(
+ struct stream_out *out,
+ struct mix_matrix_params *mm_params);
+int audio_extn_utils_set_downmix_params(
+ struct stream_out *out,
+ struct mix_matrix_params *mm_params);
#ifdef AUDIO_HW_LOOPBACK_ENABLED
/* API to create audio patch */
int audio_extn_hw_loopback_create_audio_patch(struct audio_hw_device *dev,
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index b7af5f5..48d20ee 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -102,6 +102,10 @@
/* ToDo: Check and update a proper value in msec */
#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
+#ifndef MAX_CHANNELS_SUPPORTED
+#define MAX_CHANNELS_SUPPORTED 8
+#endif
+
struct string_to_enum {
const char *name;
uint32_t value;
@@ -122,6 +126,7 @@
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TIMESTAMP),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INTERACTIVE),
STRING_TO_ENUM(AUDIO_INPUT_FLAG_NONE),
STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
@@ -857,6 +862,9 @@
int snd_device = split_snd_device, snd_device_be_idx = -1;
int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
char value[PROPERTY_VALUE_MAX] = {0};
+ struct streams_io_cfg *s_info = NULL;
+ struct listnode *node = NULL;
+ int direct_app_type = 0;
ALOGV("%s: usecase->out_snd_device %s, usecase->in_snd_device %s, split_snd_device %s",
__func__, platform_get_snd_device_name(usecase->out_snd_device),
@@ -873,6 +881,7 @@
(usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
(usecase->id != USECASE_AUDIO_PLAYBACK_ULL) &&
(usecase->id != USECASE_AUDIO_PLAYBACK_VOIP) &&
+ (!is_interactive_usecase(usecase->id)) &&
(!is_offload_usecase(usecase->id)) &&
(usecase->type != PCM_CAPTURE)) {
ALOGV("%s: a rx/tx/loopback path where app type cfg is not required %d", __func__, usecase->id);
@@ -953,7 +962,18 @@
}
sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
- app_type = usecase->stream.out->app_type_cfg.app_type;
+ /* Interactive streams are supported with only direct app type id.
+ * Get Direct profile app type and use it for interactive streams
+ */
+ list_for_each(node, &adev->streams_output_cfg_list) {
+ s_info = node_to_item(node, struct streams_io_cfg, list);
+ if (s_info->flags.out_flags == AUDIO_OUTPUT_FLAG_DIRECT)
+ direct_app_type = s_info->app_type_cfg.app_type;
+ }
+ if (usecase->stream.out->flags == AUDIO_OUTPUT_FLAG_INTERACTIVE)
+ app_type = direct_app_type;
+ else
+ app_type = usecase->stream.out->app_type_cfg.app_type;
app_type_cfg[len++] = app_type;
app_type_cfg[len++] = acdb_dev_id;
if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
@@ -2196,3 +2216,100 @@
exit:
return ret;
}
+
+int audio_extn_utils_set_pan_scale_params(
+ struct stream_out *out,
+ struct mix_matrix_params *mm_params)
+{
+ int ret = -EINVAL, i = 0, j = 0;
+
+ if (mm_params == NULL && out != NULL) {
+ ALOGE("%s:: Invalid mix matrix params", __func__);
+ goto exit;
+ }
+
+ if (mm_params->num_output_channels > MAX_CHANNELS_SUPPORTED ||
+ mm_params->num_output_channels <= 0 ||
+ mm_params->num_input_channels > MAX_CHANNELS_SUPPORTED ||
+ mm_params->num_input_channels <= 0)
+ goto exit;
+
+ out->pan_scale_params.num_output_channels = mm_params->num_output_channels;
+ out->pan_scale_params.num_input_channels = mm_params->num_input_channels;
+ out->pan_scale_params.has_output_channel_map =
+ mm_params->has_output_channel_map;
+ for (i = 0; i < mm_params->num_output_channels; i++)
+ out->pan_scale_params.output_channel_map[i] =
+ mm_params->output_channel_map[i];
+
+ out->pan_scale_params.has_input_channel_map =
+ mm_params->has_input_channel_map;
+ for (i = 0; i < mm_params->num_input_channels; i++)
+ out->pan_scale_params.input_channel_map[i] =
+ mm_params->input_channel_map[i];
+
+ out->pan_scale_params.has_mixer_coeffs = mm_params->has_mixer_coeffs;
+ for (i = 0; i < mm_params->num_output_channels; i++)
+ for (j = 0; j < mm_params->num_input_channels; j++) {
+ //Convert the channel coefficient gains in Q14 format
+ out->pan_scale_params.mixer_coeffs[i][j] =
+ mm_params->mixer_coeffs[i][j] * (2 << 13);
+ }
+
+ ret = platform_set_stream_pan_scale_params(out->dev->platform,
+ out->pcm_device_id,
+ out->pan_scale_params);
+
+exit:
+ return ret;
+}
+
+int audio_extn_utils_set_downmix_params(
+ struct stream_out *out,
+ struct mix_matrix_params *mm_params)
+{
+ int ret = -EINVAL, i = 0, j = 0;
+ struct audio_usecase *usecase = NULL;
+
+ if (mm_params == NULL && out != NULL) {
+ ALOGE("%s:: Invalid mix matrix params", __func__);
+ goto exit;
+ }
+
+ if (mm_params->num_output_channels > MAX_CHANNELS_SUPPORTED ||
+ mm_params->num_output_channels <= 0 ||
+ mm_params->num_input_channels > MAX_CHANNELS_SUPPORTED ||
+ mm_params->num_input_channels <= 0)
+ goto exit;
+
+ usecase = get_usecase_from_list(out->dev, out->usecase);
+ out->downmix_params.num_output_channels = mm_params->num_output_channels;
+ out->downmix_params.num_input_channels = mm_params->num_input_channels;
+
+ out->downmix_params.has_output_channel_map =
+ mm_params->has_output_channel_map;
+ for (i = 0; i < mm_params->num_output_channels; i++) {
+ out->downmix_params.output_channel_map[i] =
+ mm_params->output_channel_map[i];
+ }
+
+ out->downmix_params.has_input_channel_map =
+ mm_params->has_input_channel_map;
+ for (i = 0; i < mm_params->num_input_channels; i++)
+ out->downmix_params.input_channel_map[i] =
+ mm_params->input_channel_map[i];
+
+ out->downmix_params.has_mixer_coeffs = mm_params->has_mixer_coeffs;
+ for (i = 0; i < mm_params->num_output_channels; i++)
+ for (j = 0; j < mm_params->num_input_channels; j++)
+ out->downmix_params.mixer_coeffs[i][j] =
+ mm_params->mixer_coeffs[i][j];
+
+ ret = platform_set_stream_downmix_params(out->dev->platform,
+ out->pcm_device_id,
+ usecase->out_snd_device,
+ out->downmix_params);
+
+exit:
+ return ret;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9d14ec3..6029c4a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -64,6 +64,7 @@
#include <hardware/audio_effect.h>
#include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_ns.h>
#include <audio_utils/format.h>
@@ -118,6 +119,11 @@
static unsigned int configured_low_latency_capture_period_size =
LOW_LATENCY_CAPTURE_PERIOD_SIZE;
+#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
+#define MMAP_PERIOD_COUNT_MIN 32
+#define MMAP_PERIOD_COUNT_MAX 512
+#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
+
struct pcm_config pcm_config_deep_buffer = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
@@ -165,6 +171,19 @@
.avail_min = 0,
};
+struct pcm_config pcm_config_mmap_playback = {
+ .channels = 2,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = MMAP_PERIOD_SIZE,
+ .period_count = MMAP_PERIOD_COUNT_DEFAULT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = MMAP_PERIOD_SIZE*8,
+ .stop_threshold = INT32_MAX,
+ .silence_threshold = 0,
+ .silence_size = 0,
+ .avail_min = MMAP_PERIOD_SIZE, //1 ms
+};
+
struct pcm_config pcm_config_audio_capture = {
.channels = 2,
.period_count = AUDIO_CAPTURE_PERIOD_COUNT,
@@ -184,6 +203,19 @@
.avail_min = ULL_PERIOD_SIZE, //1 ms
};
+struct pcm_config pcm_config_mmap_capture = {
+ .channels = 2,
+ .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+ .period_size = MMAP_PERIOD_SIZE,
+ .period_count = MMAP_PERIOD_COUNT_DEFAULT,
+ .format = PCM_FORMAT_S16_LE,
+ .start_threshold = 0,
+ .stop_threshold = INT_MAX,
+ .silence_threshold = 0,
+ .silence_size = 0,
+ .avail_min = MMAP_PERIOD_SIZE, //1 ms
+};
+
#define AFE_PROXY_CHANNEL_COUNT 2
#define AFE_PROXY_SAMPLING_RATE 48000
@@ -242,6 +274,8 @@
[USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
[USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
[USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
+ [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
+ [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
[USECASE_AUDIO_RECORD] = "audio-record",
[USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
@@ -250,7 +284,8 @@
[USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
[USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
- [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
+ [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
+
[USECASE_AUDIO_HFP_SCO] = "hfp-sco",
[USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
[USECASE_VOICE_CALL] = "voice-call",
@@ -283,6 +318,15 @@
[USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
[USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
+ /* For Interactive Audio Streams */
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
};
static const audio_usecase_t offload_usecases[] = {
@@ -297,6 +341,17 @@
USECASE_AUDIO_PLAYBACK_OFFLOAD9,
};
+static const audio_usecase_t interactive_usecases[] = {
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
+};
+
#define STRING_TO_ENUM(string) { #string, string }
struct string_to_enum {
@@ -1809,10 +1864,10 @@
voice_check_and_update_aanc_path(adev, usecase->out_snd_device, false);
}
- if ((usecase->out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP) &&
+ if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP) &&
(!audio_extn_a2dp_is_ready())) {
ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
- usecase->out_snd_device = SND_DEVICE_OUT_SPEAKER;
+ out_snd_device = SND_DEVICE_OUT_SPEAKER;
}
/* Disable current sound devices */
@@ -2054,60 +2109,75 @@
adev->perf_lock_opts_size);
select_devices(adev, in->usecase);
- ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d format %d",
- __func__, adev->snd_card, in->pcm_device_id, in->config.channels, in->config.format);
-
- if (audio_extn_cin_attached_usecase(in->usecase)) {
+ if (audio_extn_cin_attached_usecase(in->usecase)) {
ret = audio_extn_cin_start_input_stream(in);
if (ret)
goto error_open;
else
goto done_open;
- }
-
- unsigned int flags = PCM_IN;
- unsigned int pcm_open_retry_count = 0;
-
- if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
- flags |= PCM_MMAP | PCM_NOIRQ;
- pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
- } else if (in->realtime) {
- flags |= PCM_MMAP | PCM_NOIRQ;
}
- while (1) {
- in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
- flags, &in->config);
+ if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
- ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
- if (in->pcm != NULL) {
+ ALOGE("%s: pcm stream not ready", __func__);
+ goto error_open;
+ }
+ ret = pcm_start(in->pcm);
+ if (ret < 0) {
+ ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
+ goto error_open;
+ }
+ } else {
+ unsigned int flags = PCM_IN | PCM_MONOTONIC;
+ unsigned int pcm_open_retry_count = 0;
+
+ if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+ flags |= PCM_MMAP | PCM_NOIRQ;
+ pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+ } else if (in->realtime) {
+ flags |= PCM_MMAP | PCM_NOIRQ;
+ }
+
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+ __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+
+ while (1) {
+ in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+ flags, &in->config);
+ if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+ ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+ if (in->pcm != NULL) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ }
+ if (pcm_open_retry_count-- == 0) {
+ ret = -EIO;
+ goto error_open;
+ }
+ usleep(PROXY_OPEN_WAIT_TIME * 1000);
+ continue;
+ }
+ break;
+ }
+
+ ALOGV("%s: pcm_prepare", __func__);
+ ret = pcm_prepare(in->pcm);
+ if (ret < 0) {
+ ALOGE("%s: pcm_prepare returned %d", __func__, ret);
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ goto error_open;
+ }
+ register_in_stream(in);
+ if (in->realtime) {
+ ret = pcm_start(in->pcm);
+ if (ret < 0) {
+ ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
pcm_close(in->pcm);
in->pcm = NULL;
- }
- if (pcm_open_retry_count-- == 0) {
- ret = -EIO;
goto error_open;
}
- usleep(PROXY_OPEN_WAIT_TIME * 1000);
- continue;
}
- break;
- }
-
- ALOGV("%s: pcm_prepare", __func__);
- ret = pcm_prepare(in->pcm);
- if (ret < 0) {
- ALOGE("%s: pcm_prepare returned %d", __func__, ret);
- pcm_close(in->pcm);
- in->pcm = NULL;
- goto error_open;
- }
-
- register_in_stream(in);
- if (in->realtime) {
- ret = pcm_start(in->pcm);
- if (ret < 0)
- goto error_open;
}
done_open:
@@ -2177,6 +2247,50 @@
}
}
+bool is_interactive_usecase(audio_usecase_t uc_id)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
+ if (uc_id == interactive_usecases[i])
+ return true;
+ }
+ return false;
+}
+
+static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
+{
+ audio_usecase_t ret_uc = USECASE_INVALID;
+ unsigned int intract_uc_index;
+ unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
+
+ ALOGV("%s: num_usecase: %d", __func__, num_usecase);
+ for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
+ if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
+ adev->interactive_usecase_state |= 0x1 << intract_uc_index;
+ ret_uc = interactive_usecases[intract_uc_index];
+ break;
+ }
+ }
+
+ ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
+ return ret_uc;
+}
+
+static void free_interactive_usecase(struct audio_device *adev,
+ audio_usecase_t uc_id)
+{
+ unsigned int interact_uc_index;
+ unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
+
+ for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
+ if (interactive_usecases[interact_uc_index] == uc_id) {
+ adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
+ break;
+ }
+ }
+ ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
+}
+
bool is_offload_usecase(audio_usecase_t uc_id)
{
unsigned int i;
@@ -2544,7 +2658,18 @@
ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
__func__, adev->snd_card, out->pcm_device_id, out->config.format);
- if (!is_offload_usecase(out->usecase)) {
+
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+ if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+ ALOGE("%s: pcm stream not ready", __func__);
+ goto error_open;
+ }
+ ret = pcm_start(out->pcm);
+ if (ret < 0) {
+ ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
+ goto error_open;
+ }
+ } else if (!is_offload_usecase(out->usecase)) {
unsigned int flags = PCM_OUT;
unsigned int pcm_open_retry_count = 0;
if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
@@ -2840,7 +2965,9 @@
{
struct stream_out *out = (struct stream_out *)stream;
- if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (is_interactive_usecase(out->usecase)) {
+ return out->config.period_size;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
else
@@ -2883,6 +3010,7 @@
struct audio_device *adev = out->dev;
struct audio_usecase *uc_info;
struct listnode *node;
+ bool do_stop = true;
ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
stream, out->usecase, use_case_table[out->usecase]);
@@ -2909,6 +3037,10 @@
pcm_close(out->pcm);
out->pcm = NULL;
}
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+ do_stop = out->playback_started;
+ out->playback_started = false;
+ }
} else {
ALOGD("copl(%p):standby", out);
out->send_next_track_params = false;
@@ -2920,7 +3052,9 @@
out->compr = NULL;
}
}
- stop_output_stream(out);
+ if (do_stop) {
+ stop_output_stream(out);
+ }
//restore output device for active usecase when current snd device and output device mismatch
list_for_each(node, &adev->usecase_list) {
uc_info = node_to_item(node, struct audio_usecase, list);
@@ -3200,7 +3334,7 @@
audio_extn_perf_lock_release(&adev->perf_lock_handle);
if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
out->a2dp_compress_mute &&
- (!(out->devices & AUDIO_DEVICE_OUT_ALL_A2DP))) {
+ (!(out->devices & AUDIO_DEVICE_OUT_ALL_A2DP) || audio_extn_a2dp_is_ready())) {
pthread_mutex_lock(&out->compr_mute_lock);
out->a2dp_compress_mute = false;
out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
@@ -3421,7 +3555,8 @@
lock_output_stream(out);
latency = audio_extn_utils_compress_get_dsp_latency(out);
pthread_mutex_unlock(&out->lock);
- } else if (out->realtime) {
+ } else if ((out->realtime) ||
+ (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
// since the buffer won't be filled up faster than realtime,
// return a smaller number
if (out->config.rate)
@@ -3549,6 +3684,20 @@
return -ENOSYS;
}
+static void update_frames_written(struct stream_out *out, size_t bytes)
+{
+ size_t bpf = 0;
+
+ if (is_offload_usecase(out->usecase) && !out->non_blocking &&
+ !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
+ bpf = 1;
+ else if (!is_offload_usecase(out->usecase))
+ bpf = audio_bytes_per_sample(out->format) *
+ audio_channel_count_from_out_mask(out->channel_mask);
+ if (bpf != 0)
+ out->written += bytes / bpf;
+}
+
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
@@ -3566,14 +3715,6 @@
pthread_mutex_unlock(&out->lock);
return -ENETRESET;
} else {
- /* increase written size during SSR to avoid mismatch
- * with the written frames count in AF
- */
- // bytes per frame
- size_t bpf = audio_bytes_per_sample(out->format) *
- audio_channel_count_from_out_mask(out->channel_mask);
- if (bpf != 0)
- out->written += bytes / bpf;
ALOGD(" %s: sound card is not active/SSR state", __func__);
ret= -EIO;
goto exit;
@@ -3582,12 +3723,15 @@
if (audio_extn_passthru_should_drop_data(out)) {
ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
- if ((audio_bytes_per_sample(out->format) != 0) && (out->config.channels != 0))
- out->written += bytes / (out->config.channels * audio_bytes_per_sample(out->format));
ret = -EIO;
goto exit;
}
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
/*ADD audio_extn_passthru_is_passthrough_stream(out) check*/
if ((audio_extn_passthru_is_enabled()) &&
@@ -3602,10 +3746,6 @@
(audio_extn_a2dp_is_suspended())) {
if (!(out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
- size_t bpf = audio_bytes_per_sample(out->format) *
- audio_channel_count_from_out_mask(out->channel_mask);
- if (bpf != 0)
- out->written += bytes / bpf;
ret = -EIO;
goto exit;
}
@@ -3683,6 +3823,9 @@
} else
ret = compress_write(out->compr, buffer, bytes);
+ if ((ret < 0 || ret == (ssize_t)bytes) && !out->non_blocking)
+ update_frames_written(out, bytes);
+
if (ret < 0)
ret = -errno;
ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %zd", __func__, bytes, ret);
@@ -3697,8 +3840,6 @@
out_on_error(&out->stream.common);
return ret;
}
- if ( ret == (ssize_t)bytes && !out->non_blocking)
- out->written += bytes;
/* Call compr start only when non-zero bytes of data is there to be rendered */
if (!out->playback_started && ret > 0) {
@@ -3777,14 +3918,13 @@
if (ret < 0)
ret = -errno;
- else if (ret == 0 && (audio_bytes_per_sample(out->format) != 0))
- out->written += bytes / (out->config.channels * audio_bytes_per_sample(out->format));
- else
+ else if (ret > 0)
ret = -EINVAL;
}
}
exit:
+ update_frames_written(out, bytes);
if (-ENETRESET == ret) {
out->card_status = CARD_STATUS_OFFLINE;
}
@@ -4074,6 +4214,177 @@
return -ENOSYS;
}
+static int out_stop(const struct audio_stream_out* stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ int ret = -ENOSYS;
+
+ ALOGV("%s", __func__);
+ pthread_mutex_lock(&adev->lock);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
+ out->playback_started && out->pcm != NULL) {
+ pcm_stop(out->pcm);
+ ret = stop_output_stream(out);
+ out->playback_started = false;
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return ret;
+}
+
+static int out_start(const struct audio_stream_out* stream)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ int ret = -ENOSYS;
+
+ ALOGV("%s", __func__);
+ pthread_mutex_lock(&adev->lock);
+ if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
+ !out->playback_started && out->pcm != NULL) {
+ ret = start_output_stream(out);
+ if (ret == 0) {
+ out->playback_started = true;
+ }
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return ret;
+}
+
+/*
+ * Modify config->period_count based on min_size_frames
+ */
+static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
+{
+ int periodCountRequested = (min_size_frames + config->period_size - 1)
+ / config->period_size;
+ int periodCount = MMAP_PERIOD_COUNT_MIN;
+
+ ALOGV("%s original config.period_size = %d config.period_count = %d",
+ __func__, config->period_size, config->period_count);
+
+ while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
+ periodCount *= 2;
+ }
+ config->period_count = periodCount;
+
+ ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
+}
+
+static int out_create_mmap_buffer(const struct audio_stream_out *stream,
+ int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ struct audio_device *adev = out->dev;
+ int ret = 0;
+ unsigned int offset1;
+ unsigned int frames1;
+ const char *step = "";
+ uint32_t mmap_size;
+
+ ALOGV("%s", __func__);
+ pthread_mutex_lock(&adev->lock);
+
+ if (info == NULL || min_size_frames == 0) {
+ ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
+ ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
+ ret = -ENOSYS;
+ goto exit;
+ }
+ out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+ if (out->pcm_device_id < 0) {
+ ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
+ __func__, out->pcm_device_id, out->usecase);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ adjust_mmap_period_count(&out->config, min_size_frames);
+
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+ __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
+ out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
+ (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
+ if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+ step = "open";
+ ret = -ENODEV;
+ goto exit;
+ }
+ ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
+ if (ret < 0) {
+ step = "begin";
+ goto exit;
+ }
+ info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
+ info->burst_size_frames = out->config.period_size;
+ ret = platform_get_mmap_data_fd(adev->platform,
+ out->pcm_device_id, 0 /*playback*/,
+ &info->shared_memory_fd,
+ &mmap_size);
+ if (ret < 0) {
+ step = "get_mmap_fd";
+ goto exit;
+ }
+ memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
+ info->buffer_size_frames));
+
+ ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
+ if (ret < 0) {
+ step = "commit";
+ goto exit;
+ }
+
+ out->standby = false;
+ ret = 0;
+
+ ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
+ __func__, info->shared_memory_address, info->buffer_size_frames);
+
+exit:
+ if (ret != 0) {
+ if (out->pcm == NULL) {
+ ALOGE("%s: %s - %d", __func__, step, ret);
+ } else {
+ ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
+ pcm_close(out->pcm);
+ out->pcm = NULL;
+ }
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return ret;
+}
+
+static int out_get_mmap_position(const struct audio_stream_out *stream,
+ struct audio_mmap_position *position)
+{
+ struct stream_out *out = (struct stream_out *)stream;
+ ALOGVV("%s", __func__);
+ if (position == NULL) {
+ return -EINVAL;
+ }
+ if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
+ return -ENOSYS;
+ }
+ if (out->pcm == NULL) {
+ return -ENOSYS;
+ }
+
+ struct timespec ts = { 0, 0 };
+ int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
+ if (ret < 0) {
+ ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+ return ret;
+ }
+ position->time_nanoseconds = ts.tv_sec*1000000000L + ts.tv_nsec;
+ return 0;
+}
+
+
/** audio_stream_in implementation **/
static uint32_t in_get_sample_rate(const struct audio_stream *stream)
{
@@ -4132,6 +4443,7 @@
int status = 0;
ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
stream, in->usecase, use_case_table[in->usecase]);
+ bool do_stop = true;
lock_input_stream(in);
if (!in->standby && in->is_st_session) {
@@ -4149,6 +4461,9 @@
if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
voice_extn_compress_voip_close_input_stream(stream);
ALOGD("VOIP input entered standby");
+ } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
+ do_stop = in->capture_started;
+ in->capture_started = false;
} else {
if (audio_extn_cin_attached_usecase(in->usecase))
audio_extn_cin_stop_input_stream(in);
@@ -4158,6 +4473,14 @@
}
status = stop_input_stream(in);
}
+ if (in->pcm) {
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ }
+
+ if (do_stop) {
+ status = stop_input_stream(in);
+ }
pthread_mutex_unlock(&adev->lock);
}
pthread_mutex_unlock(&in->lock);
@@ -4336,6 +4659,11 @@
return bytes;
}
+ if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
+ ret = -ENOSYS;
+ goto exit;
+ }
+
if (in->standby) {
pthread_mutex_lock(&adev->lock);
if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
@@ -4471,13 +4799,159 @@
return add_remove_audio_effect(stream, effect, false);
}
+static int in_stop(const struct audio_stream_in* stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+
+ int ret = -ENOSYS;
+ ALOGV("%s", __func__);
+ pthread_mutex_lock(&adev->lock);
+ if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
+ in->capture_started && in->pcm != NULL) {
+ pcm_stop(in->pcm);
+ ret = stop_input_stream(in);
+ in->capture_started = false;
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return ret;
+}
+
+static int in_start(const struct audio_stream_in* stream)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ int ret = -ENOSYS;
+
+ ALOGV("%s in %p", __func__, in);
+ pthread_mutex_lock(&adev->lock);
+ if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
+ !in->capture_started && in->pcm != NULL) {
+ if (!in->capture_started) {
+ ret = start_input_stream(in);
+ if (ret == 0) {
+ in->capture_started = true;
+ }
+ }
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return ret;
+}
+
+static int in_create_mmap_buffer(const struct audio_stream_in *stream,
+ int32_t min_size_frames,
+ struct audio_mmap_buffer_info *info)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ struct audio_device *adev = in->dev;
+ int ret = 0;
+ unsigned int offset1;
+ unsigned int frames1;
+ const char *step = "";
+
+ pthread_mutex_lock(&adev->lock);
+ ALOGV("%s in %p", __func__, in);
+
+ if (info == NULL || min_size_frames == 0) {
+ ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
+ ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
+ ALOGV("%s in %p", __func__, in);
+ ret = -ENOSYS;
+ goto exit;
+ }
+ in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
+ if (in->pcm_device_id < 0) {
+ ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
+ __func__, in->pcm_device_id, in->usecase);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ adjust_mmap_period_count(&in->config, min_size_frames);
+
+ ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+ __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+ in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+ (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
+ if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+ step = "open";
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
+ if (ret < 0) {
+ step = "begin";
+ goto exit;
+ }
+ info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
+ info->burst_size_frames = in->config.period_size;
+ info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
+
+ memset(info->shared_memory_address, 0, pcm_frames_to_bytes(in->pcm,
+ info->buffer_size_frames));
+
+ ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
+ if (ret < 0) {
+ step = "commit";
+ goto exit;
+ }
+
+ in->standby = false;
+ ret = 0;
+
+ ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
+ __func__, info->shared_memory_address, info->buffer_size_frames);
+
+exit:
+ if (ret != 0) {
+ if (in->pcm == NULL) {
+ ALOGE("%s: %s - %d", __func__, step, ret);
+ } else {
+ ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
+ pcm_close(in->pcm);
+ in->pcm = NULL;
+ }
+ }
+ pthread_mutex_unlock(&adev->lock);
+ return ret;
+}
+
+static int in_get_mmap_position(const struct audio_stream_in *stream,
+ struct audio_mmap_position *position)
+{
+ struct stream_in *in = (struct stream_in *)stream;
+ ALOGVV("%s", __func__);
+ if (position == NULL) {
+ return -EINVAL;
+ }
+ if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
+ return -ENOSYS;
+ }
+ if (in->pcm == NULL) {
+ return -ENOSYS;
+ }
+ struct timespec ts = { 0, 0 };
+ int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
+ if (ret < 0) {
+ ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+ return ret;
+ }
+ position->time_nanoseconds = ts.tv_sec*1000000000L + ts.tv_nsec;
+ return 0;
+}
+
int adev_open_output_stream(struct audio_hw_device *dev,
- audio_io_handle_t handle,
- audio_devices_t devices,
- audio_output_flags_t flags,
- struct audio_config *config,
- struct audio_stream_out **stream_out,
- const char *address __unused)
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config *config,
+ struct audio_stream_out **stream_out,
+ const char *address __unused)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_out *out;
@@ -4859,11 +5333,21 @@
channels = audio_channel_count_from_out_mask(out->channel_mask);
- if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
+ if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
+ out->usecase = get_interactive_usecase(adev);
+ out->config = pcm_config_low_latency;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
out->flags);
out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
+ } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+ out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
+ out->config = pcm_config_mmap_playback;
+ out->stream.start = out_start;
+ out->stream.stop = out_stop;
+ out->stream.create_mmap_buffer = out_create_mmap_buffer;
+ out->stream.get_mmap_position = out_get_mmap_position;
} else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
out->dynamic_pm_qos_enabled = property_get_bool("vendor.audio.dynamic.qos.enable", false);
@@ -4970,7 +5454,11 @@
out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
out->stream.get_presentation_position = out_get_presentation_position;
- out->af_period_multiplier = out->realtime ? af_period_multiplier : 1;
+ if (out->realtime)
+ out->af_period_multiplier = af_period_multiplier;
+ else
+ out->af_period_multiplier = 1;
+
out->standby = 1;
/* out->muted = false; by calloc() */
/* out->written = 0; by calloc() */
@@ -5079,6 +5567,9 @@
out->a2dp_compress_mute = false;
+ if (is_interactive_usecase(out->usecase))
+ free_interactive_usecase(adev, out->usecase);
+
if (out->convert_buffer != NULL) {
free(out->convert_buffer);
out->convert_buffer = NULL;
@@ -5496,16 +5987,26 @@
in->usecase = USECASE_AUDIO_RECORD;
if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
- (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+ (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
is_low_latency = true;
#if LOW_LATENCY_CAPTURE_USE_CASE
in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
#endif
in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
}
-
in->format = config->format;
- if (in->realtime) {
+ if ((config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) &&
+ ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
+ in->realtime = 0;
+ in->usecase = USECASE_AUDIO_RECORD_MMAP;
+ in->config = pcm_config_mmap_capture;
+ in->stream.start = in_start;
+ in->stream.stop = in_stop;
+ in->stream.create_mmap_buffer = in_create_mmap_buffer;
+ in->stream.get_mmap_position = in_get_mmap_position;
+ in->af_period_multiplier = 1;
+ ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
+ } else if (in->realtime) {
in->config = pcm_config_audio_capture_rt;
in->sample_rate = in->config.rate;
in->af_period_multiplier = af_period_multiplier;
@@ -5629,7 +6130,8 @@
in->config.rate = in->sample_rate;
#else
if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
- (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION || voice_extn_compress_voip_is_active(in->dev)) &&
+ (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
+ voice_extn_compress_voip_is_active(in->dev)) &&
(voice_extn_compress_voip_is_format_supported(in->format)) &&
(in->config.rate == 8000 || in->config.rate == 16000 ||
in->config.rate == 32000 || in->config.rate == 48000) &&
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 6ec61b4..0a6d85b 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -118,6 +118,7 @@
USECASE_AUDIO_PLAYBACK_OFFLOAD8,
USECASE_AUDIO_PLAYBACK_OFFLOAD9,
USECASE_AUDIO_PLAYBACK_ULL,
+ USECASE_AUDIO_PLAYBACK_MMAP,
/* FM usecase */
USECASE_AUDIO_PLAYBACK_FM,
@@ -139,6 +140,7 @@
USECASE_AUDIO_RECORD_VOIP,
/* Voice usecase */
USECASE_VOICE_CALL,
+ USECASE_AUDIO_RECORD_MMAP,
/* Voice extension usecases */
USECASE_VOICE2_CALL,
@@ -168,6 +170,15 @@
USECASE_AUDIO_PLAYBACK_EXT_DISP_SILENCE,
USECASE_AUDIO_TRANSCODE_LOOPBACK,
+
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
+ USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
AUDIO_USECASE_MAX
};
@@ -310,6 +321,8 @@
char pm_qos_mixer_path[MAX_MIXER_PATH_LEN];
int dynamic_pm_qos_enabled;
+ mix_matrix_params_t pan_scale_params;
+ mix_matrix_params_t downmix_params;
};
struct stream_in {
@@ -342,6 +355,7 @@
struct audio_device *dev;
card_status_t card_status;
+ int capture_started;
};
typedef enum {
@@ -482,6 +496,7 @@
uint32_t dsp_bit_width_enforce_mode;
bool bt_sco_on;
struct audio_device_config_param *device_cfg_params;
+ unsigned int interactive_usecase_state;
};
int select_devices(struct audio_device *adev,
@@ -526,6 +541,8 @@
void adev_close_output_stream(struct audio_hw_device *dev __unused,
struct audio_stream_out *stream);
+bool is_interactive_usecase(audio_usecase_t uc_id);
+
#define LITERAL_TO_STRING(x) #x
#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
__FILE__ ":" LITERAL_TO_STRING(__LINE__)\
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 44ffcf0..52e3138 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -40,6 +40,10 @@
#include <dirent.h>
#include <linux/msm_audio.h>
+#if defined(PLATFORM_MSMFALCON)
+#include <sound/devdep_params.h>
+#endif
+
#ifdef DYNAMIC_LOG_ENABLED
#include <log_xml_parser.h>
#define LOG_MASK HAL_MOD_FILE_PLATFORM
@@ -336,6 +340,10 @@
[USECASE_AUDIO_HFP_SCO_WB] = {HFP_PCM_RX, HFP_SCO_RX},
[USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
[USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_MMAP] = {MMAP_PLAYBACK_PCM_DEVICE,
+ MMAP_PLAYBACK_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE,
+ MMAP_RECORD_PCM_DEVICE},
[USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
[USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
[USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
@@ -369,6 +377,23 @@
[USECASE_AUDIO_PLAYBACK_VOIP] = {AUDIO_PLAYBACK_VOIP_PCM_DEVICE, AUDIO_PLAYBACK_VOIP_PCM_DEVICE},
[USECASE_AUDIO_RECORD_VOIP] = {AUDIO_RECORD_VOIP_PCM_DEVICE, AUDIO_RECORD_VOIP_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE1, PLAYBACK_INTERACTIVE_STRM_DEVICE1},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE2, PLAYBACK_INTERACTIVE_STRM_DEVICE2},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE3, PLAYBACK_INTERACTIVE_STRM_DEVICE3},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE4, PLAYBACK_INTERACTIVE_STRM_DEVICE4},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE5, PLAYBACK_INTERACTIVE_STRM_DEVICE5},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE6, PLAYBACK_INTERACTIVE_STRM_DEVICE6},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE7, PLAYBACK_INTERACTIVE_STRM_DEVICE7},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE8, PLAYBACK_INTERACTIVE_STRM_DEVICE8},
+
};
/* Array to store sound devices */
@@ -812,6 +837,7 @@
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MMAP)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS)},
@@ -819,6 +845,7 @@
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS3)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS4)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+ {TO_NAME_INDEX(USECASE_AUDIO_RECORD_MMAP)},
{TO_NAME_INDEX(USECASE_VOICE_CALL)},
{TO_NAME_INDEX(USECASE_VOICE2_CALL)},
{TO_NAME_INDEX(USECASE_VOLTE_CALL)},
@@ -902,6 +929,7 @@
#define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
#define ULL_PLATFORM_DELAY (6*1000LL)
+#define MMAP_PLATFORM_DELAY (3*1000LL)
static void update_interface(const char *snd_card_name) {
if (!strncmp(snd_card_name, "apq8009-tashalite-snd-card",
@@ -5024,6 +5052,8 @@
return PCM_OFFLOAD_PLATFORM_DELAY;
case USECASE_AUDIO_PLAYBACK_ULL:
return ULL_PLATFORM_DELAY;
+ case USECASE_AUDIO_PLAYBACK_MMAP:
+ return MMAP_PLATFORM_DELAY;
default:
return 0;
}
@@ -6165,6 +6195,147 @@
*length = msm_be_id_array_len;
}
+int platform_set_stream_pan_scale_params(void *platform,
+ int snd_id,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl = NULL;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int pan_scale_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+
+ if (sizeof(mm_params) > MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Stream %d Pan Scale Control", snd_id);
+ ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ goto end;
+ }
+ pan_scale_data[length++] = mm_params.num_output_channels;
+ pan_scale_data[length++] = mm_params.num_input_channels;
+
+ pan_scale_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pan_scale_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pan_scale_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ pan_scale_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, pan_scale_data, length);
+end:
+ return ret;
+}
+
+int platform_set_stream_downmix_params(void *platform,
+ int snd_id,
+ snd_device_t snd_device,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int downmix_param_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int be_idx = 0;
+
+ if ((sizeof(mm_params) +
+ sizeof(be_idx)) >
+ MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Device %d Downmix Control", snd_id);
+ ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ be_idx = platform_get_snd_device_backend_index(snd_device);
+ downmix_param_data[length] = be_idx;
+ downmix_param_data[length++] = mm_params.num_output_channels;
+ downmix_param_data[length++] = mm_params.num_input_channels;
+
+ downmix_param_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ downmix_param_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, downmix_param_data, length);
+end:
+ return ret;
+}
+
int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask,
int snd_id, uint8_t *input_channel_map)
{
@@ -7224,3 +7395,40 @@
return MAX_CODEC_BACKENDS;
}
+
+#if defined(PLATFORM_MSMFALCON)
+int platform_get_mmap_data_fd(void *platform, int fe_dev, int dir, int *fd,
+ uint32_t *size)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ int hw_fd = -1;
+ char dev_name[128];
+ struct snd_pcm_mmap_fd mmap_fd;
+ memset(&mmap_fd, 0, sizeof(mmap_fd));
+ mmap_fd.dir = dir;
+ snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+ adev->snd_card, HWDEP_FE_BASE+fe_dev);
+ hw_fd = open(dev_name, O_RDONLY);
+ if (hw_fd < 0) {
+ ALOGE("fe hw dep node open %d/%d failed", adev->snd_card, fe_dev);
+ return -1;
+ }
+ if (ioctl(hw_fd, SNDRV_PCM_IOCTL_MMAP_DATA_FD, &mmap_fd) < 0) {
+ ALOGE("fe hw dep node ioctl failed");
+ close(hw_fd);
+ return -1;
+ }
+ *fd = mmap_fd.fd;
+ *size = mmap_fd.size;
+ close(hw_fd); // mmap_fd should still be valid
+ return 0;
+}
+#else
+int platform_get_mmap_data_fd(void *platform __unused, int fe_dev __unused,
+ int dir __unused, int *fd __unused,
+ uint32_t *size __unused)
+{
+ return -1;
+}
+#endif
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 6aa4dc1..30ae2c7 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -350,6 +350,8 @@
#define VOLTE_CALL_PCM_DEVICE 15
#define QCHAT_CALL_PCM_DEVICE 37
#define VOWLAN_CALL_PCM_DEVICE 16
+#define MMAP_PLAYBACK_PCM_DEVICE 2 // XXX: This must be overwritten
+#define MMAP_RECORD_PCM_DEVICE 2 // XXX: This must be overwritten
#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
#define AFE_PROXY_RECORD_PCM_DEVICE 8
@@ -357,6 +359,15 @@
#define TRANSCODE_LOOPBACK_RX_DEV_ID 43
#define TRANSCODE_LOOPBACK_TX_DEV_ID 44
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE1 0
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE2 1
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE3 27
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE4 45
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE5 46
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE6 47
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE7 48
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE8 49
+
#define PLATFORM_MAX_MIC_COUNT "input_mic_max_count"
#define PLATFORM_DEFAULT_MIC_COUNT 2
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index f2201db..43aeaed 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1368,3 +1368,9 @@
{
return 0;
}
+
+int platform_get_mmap_data_fd(void *platform, int fe_dev, int dir, int *fd,
+ uint32_t *size)
+{
+ return -ENOSYS;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 830ea0c..e88673b 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -75,6 +75,9 @@
#endif
#include <linux/msm_audio.h>
+#if defined (PLATFORM_MSM8998) || (PLATFORM_SDM845)
+#include <sound/devdep_params.h>
+#endif
#define LIB_ACDB_LOADER "libacdbloader.so"
#define CVD_VERSION_MIXER_CTL "CVD Version"
@@ -311,6 +314,10 @@
[USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
[USECASE_AUDIO_HFP_SCO_WB] = {HFP_PCM_RX, HFP_SCO_RX},
[USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_MMAP] = {MMAP_PLAYBACK_PCM_DEVICE,
+ MMAP_PLAYBACK_PCM_DEVICE},
+ [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE,
+ MMAP_RECORD_PCM_DEVICE},
[USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
[USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
[USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
@@ -348,6 +355,22 @@
[USECASE_AUDIO_PLAYBACK_VOIP] = {AUDIO_PLAYBACK_VOIP_PCM_DEVICE, AUDIO_PLAYBACK_VOIP_PCM_DEVICE},
[USECASE_AUDIO_RECORD_VOIP] = {AUDIO_RECORD_VOIP_PCM_DEVICE, AUDIO_RECORD_VOIP_PCM_DEVICE},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE1, PLAYBACK_INTERACTIVE_STRM_DEVICE1},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE2, PLAYBACK_INTERACTIVE_STRM_DEVICE2},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE3, PLAYBACK_INTERACTIVE_STRM_DEVICE3},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE4, PLAYBACK_INTERACTIVE_STRM_DEVICE4},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE5, PLAYBACK_INTERACTIVE_STRM_DEVICE5},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE6, PLAYBACK_INTERACTIVE_STRM_DEVICE6},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE7, PLAYBACK_INTERACTIVE_STRM_DEVICE7},
+ [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] =
+ {PLAYBACK_INTERACTIVE_STRM_DEVICE8, PLAYBACK_INTERACTIVE_STRM_DEVICE8},
};
@@ -790,12 +813,14 @@
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
{TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
+ {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MMAP)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS2)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS3)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_COMPRESS4)},
{TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+ {TO_NAME_INDEX(USECASE_AUDIO_RECORD_MMAP)},
{TO_NAME_INDEX(USECASE_VOICE_CALL)},
{TO_NAME_INDEX(USECASE_VOICE2_CALL)},
{TO_NAME_INDEX(USECASE_VOLTE_CALL)},
@@ -929,11 +954,11 @@
static int msm_be_id_array_len =
sizeof(msm_device_to_be_id) / sizeof(msm_device_to_be_id[0]);
-
#define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
#define PCM_OFFLOAD_PLATFORM_DELAY (30*1000LL)
#define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
#define ULL_PLATFORM_DELAY (6*1000LL)
+#define MMAP_PLATFORM_DELAY (3*1000LL)
static void update_codec_type_and_interface(struct platform_data * my_data, const char *snd_card_name) {
@@ -4954,6 +4979,8 @@
return PCM_OFFLOAD_PLATFORM_DELAY;
case USECASE_AUDIO_PLAYBACK_ULL:
return ULL_PLATFORM_DELAY;
+ case USECASE_AUDIO_PLAYBACK_MMAP:
+ return MMAP_PLATFORM_DELAY;
default:
return 0;
}
@@ -6010,6 +6037,145 @@
*length = msm_be_id_array_len;
}
+int platform_set_stream_pan_scale_params(void *platform,
+ int snd_id,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl = NULL;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int pan_scale_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+
+ if (sizeof(mm_params) > MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Stream %d Pan Scale Control", snd_id);
+ ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ goto end;
+ }
+ pan_scale_data[length++] = mm_params.num_output_channels;
+ pan_scale_data[length++] = mm_params.num_input_channels;
+
+ pan_scale_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ pan_scale_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ pan_scale_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+ pan_scale_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ pan_scale_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, pan_scale_data, length);
+end:
+ return ret;
+}
+
+int platform_set_stream_downmix_params(void *platform,
+ int snd_id,
+ snd_device_t snd_device,
+ struct mix_matrix_params mm_params)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
+ int downmix_param_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+ int ret = 0;
+ int iter_i = 0;
+ int iter_j = 0;
+ int length = 0;
+ int be_idx = 0;
+
+ if ((sizeof(mm_params) +
+ sizeof(be_idx)) >
+ MAX_LENGTH_MIXER_CONTROL_IN_INT) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+ "Audio Device %d Downmix Control", snd_id);
+ ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = -EINVAL;
+ }
+
+ be_idx = platform_get_snd_device_backend_index(snd_device);
+ downmix_param_data[length] = be_idx;
+ downmix_param_data[length++] = mm_params.num_output_channels;
+ downmix_param_data[length++] = mm_params.num_input_channels;
+
+ downmix_param_data[length++] = mm_params.has_output_channel_map;
+ if (mm_params.has_output_channel_map &&
+ mm_params.num_output_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_output_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.output_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_input_channel_map;
+ if (mm_params.has_input_channel_map &&
+ mm_params.num_input_channels <= MAX_CHANNELS_SUPPORTED &&
+ mm_params.num_input_channels > 0)
+ for (iter_i = 0; iter_i < mm_params.num_input_channels; iter_i++)
+ downmix_param_data[length++] = mm_params.input_channel_map[iter_i];
+ else {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ downmix_param_data[length++] = mm_params.has_mixer_coeffs;
+ if (mm_params.has_mixer_coeffs)
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++)
+ downmix_param_data[length++] =
+ mm_params.mixer_coeffs[iter_i][iter_j];
+
+ ret = mixer_ctl_set_array(ctl, downmix_param_data, length);
+end:
+ return ret;
+}
+
int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask,
int snd_id, uint8_t *input_channel_map)
{
@@ -7003,3 +7169,40 @@
return MAX_CODEC_BACKENDS;
}
+
+#if defined (PLATFORM_MSM8998) || (PLATFORM_SDM845)
+int platform_get_mmap_data_fd(void *platform, int fe_dev, int dir, int *fd,
+ uint32_t *size)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ int hw_fd = -1;
+ char dev_name[128];
+ struct snd_pcm_mmap_fd mmap_fd;
+ memset(&mmap_fd, 0, sizeof(mmap_fd));
+ mmap_fd.dir = dir;
+ snprintf(dev_name, sizeof(dev_name), "/dev/snd/hwC%uD%u",
+ adev->snd_card, HWDEP_FE_BASE+fe_dev);
+ hw_fd = open(dev_name, O_RDONLY);
+ if (hw_fd < 0) {
+ ALOGE("fe hw dep node open %d/%d failed", adev->snd_card, fe_dev);
+ return -1;
+ }
+ if (ioctl(hw_fd, SNDRV_PCM_IOCTL_MMAP_DATA_FD, &mmap_fd) < 0) {
+ ALOGE("fe hw dep node ioctl failed");
+ close(hw_fd);
+ return -1;
+ }
+ *fd = mmap_fd.fd;
+ *size = mmap_fd.size;
+ close(hw_fd); // mmap_fd should still be valid
+ return 0;
+}
+#else
+int platform_get_mmap_data_fd(void *platform __unused, int fe_dev __unused,
+ int dir __unused, int *fd __unused,
+ uint32_t *size __unused)
+{
+ return -1;
+}
+#endif
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 06f2cdc..f4d60c2 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -385,6 +385,8 @@
#define EC_REF_RX "I2S_RX"
#else
#define LOWLATENCY_PCM_DEVICE 15
+#define MMAP_PLAYBACK_PCM_DEVICE 18
+#define MMAP_RECORD_PCM_DEVICE 18
#define EC_REF_RX "SLIM_RX"
#endif
@@ -463,6 +465,15 @@
#define TRANSCODE_LOOPBACK_RX_DEV_ID 43
#define TRANSCODE_LOOPBACK_TX_DEV_ID 44
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE1 0
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE2 1
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE3 27
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE4 45
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE5 46
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE6 47
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE7 48
+#define PLAYBACK_INTERACTIVE_STRM_DEVICE8 49
+
#ifdef PLATFORM_APQ8084
#define FM_RX_VOLUME "Quat MI2S FM RX Volume"
#elif PLATFORM_MSM8994
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 3c31c56..6f8cf7e 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -169,6 +169,13 @@
int snd_id);
int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask,
int snd_id, uint8_t *input_channel_map);
+int platform_set_stream_pan_scale_params(void *platform,
+ int snd_id,
+ struct mix_matrix_params mm_params);
+int platform_set_stream_downmix_params(void *platform,
+ int snd_id,
+ snd_device_t snd_device,
+ struct mix_matrix_params mm_params);
int platform_set_edid_channels_configuration(void *platform, int channels);
unsigned char platform_map_to_edid_format(int format);
bool platform_is_edid_supported_format(void *platform, int format);
@@ -230,4 +237,6 @@
void platform_check_and_update_copp_sample_rate(void *platform, snd_device_t snd_device,
unsigned int stream_sr,int *sample_rate);
int platform_get_max_codec_backend();
+int platform_get_mmap_data_fd(void *platform, int dev, int dir,
+ int *fd, uint32_t *size);
#endif // AUDIO_PLATFORM_API_H
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index 635fe23..a8c2c53 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -677,7 +677,7 @@
// check system property to see if dumping is required
char check_dump_val[PROPERTY_VALUE_MAX];
- property_get("audio.volume.listener.dump", check_dump_val, "0");
+ property_get("vendor.audio.volume.listener.dump", check_dump_val, "0");
if (atoi(check_dump_val)) {
dumping_enabled = true;
}
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index 23e51cb..fa780bd 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -177,6 +177,9 @@
/* Query if a2dp is supported */
#define QAHW_PARAMETER_KEY_HANDLE_A2DP_DEVICE "isA2dpDeviceSupported"
+#define MAX_OUT_CHANNELS 8
+#define MAX_INP_CHANNELS 8
+
/* type of asynchronous write callback events. Mutually exclusive */
typedef enum {
QAHW_STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
@@ -323,6 +326,17 @@
uint16_t channel_allocation;
};
+typedef struct qahw_mix_matrix_params {
+ uint16_t num_output_channels;
+ uint16_t num_input_channels;
+ uint8_t has_output_channel_map;
+ uint32_t output_channel_map[AUDIO_CHANNEL_COUNT_MAX];
+ uint8_t has_input_channel_map;
+ uint32_t input_channel_map[AUDIO_CHANNEL_COUNT_MAX];
+ uint8_t has_mixer_coeffs;
+ float mixer_coeffs[AUDIO_CHANNEL_COUNT_MAX][AUDIO_CHANNEL_COUNT_MAX];
+} qahw_mix_matrix_params_t;
+
typedef union {
struct qahw_source_tracking_param st_params;
struct qahw_sound_focus_param sf_params;
@@ -335,6 +349,7 @@
struct qahw_adsp_event adsp_event_params;
struct qahw_out_channel_map_param channel_map_params;
struct qahw_device_cfg_param device_cfg_params;
+ struct qahw_mix_matrix_params mix_matrix_params;
} qahw_param_payload;
typedef enum {
@@ -350,7 +365,9 @@
QAHW_PARAM_OUT_CORRECT_DRIFT,
QAHW_PARAM_ADSP_STREAM_CMD,
QAHW_PARAM_OUT_CHANNEL_MAP, /* PARAM to set i/p channel map */
- QAHW_PARAM_DEVICE_CONFIG /* PARAM to set device config */
+ QAHW_PARAM_DEVICE_CONFIG, /* PARAM to set device config */
+ QAHW_PARAM_OUT_MIX_MATRIX_PARAMS,
+ QAHW_PARAM_CH_MIX_MATRIX_PARAMS,
} qahw_param_id;
__END_DECLS
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index db189eb..3c986bd 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -22,6 +22,7 @@
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -52,7 +53,7 @@
#define FORMAT_PCM 1
#define WAV_HEADER_LENGTH_MAX 46
-#define MAX_PLAYBACK_STREAMS 3
+#define MAX_PLAYBACK_STREAMS 9
#define PRIMARY_STREAM_INDEX 0
#define KVPAIRS_MAX 100
@@ -194,6 +195,7 @@
pthread_mutex_t write_lock;
pthread_cond_t drain_cond;
pthread_mutex_t drain_lock;
+ bool interactive_strm;
}stream_config;
/* Lock for dual main usecase */
@@ -263,6 +265,9 @@
#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x8000
#endif
+#ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#endif
static bool request_wake_lock(bool wakelock_acquired, bool enable)
{
@@ -683,6 +688,12 @@
fprintf(log_file, "stream %d: after the dual main signal\n", params->stream_index);
pthread_mutex_unlock(&dual_main_lock);
}
+
+ if (params->interactive_strm) {
+ params->flags = AUDIO_OUTPUT_FLAG_INTERACTIVE;
+ fprintf(stderr, "stream %s %d: Interactive stream\n", __func__, params->stream_index);
+ }
+
rc = qahw_open_output_stream(params->qahw_out_hal_handle,
params->handle,
params->output_device,
@@ -1066,7 +1077,10 @@
int rc = 0;
if (!(stream_info->flags_set)) {
- stream_info->flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ if (stream_info->interactive_strm)
+ stream_info->flags = AUDIO_OUTPUT_FLAG_INTERACTIVE;
+ else
+ stream_info->flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
stream_info->flags |= AUDIO_OUTPUT_FLAG_DIRECT;
}
@@ -1458,6 +1472,10 @@
else
direction = PCM_OUT;
+ if (direction == PCM_OUT && stream->interactive_strm) {
+ stream->flags = AUDIO_OUTPUT_FLAG_INTERACTIVE;
+ fprintf(stderr, "stream %d: Interactive stream\n", stream->stream_index);
+ }
fprintf(log_file, "%s: opening %s stream\n", __func__, ((direction == PCM_IN)? "input":"output"));
if (PCM_IN == direction)
@@ -1595,6 +1613,10 @@
printf(" -m --mode - usb operating mode(Device Mode is default)\n");
printf(" 0:Device Mode(host drives the stream and its params and so no need to give params as input)\n");
printf(" 1:Host Mode(user can give stream and stream params via a stream(SD card file) or setup loopback with given params\n");
+ printf(" -O --output-ch-map - output channel map");
+ printf(" -I --input-ch-map - input channel map");
+ printf(" -M --mixer-coeffs - mixer coefficient matrix");
+ printf(" -i --intr-strm - interactive stream indicator");
printf(" \n Examples \n");
printf(" hal_play_test -f /data/Anukoledenadu.wav -> plays Wav stream with default params\n\n");
printf(" hal_play_test -f /data/MateRani.mp3 -t 2 -d 2 -v 0.01 -r 44100 -c 2 \n");
@@ -1852,15 +1874,146 @@
return 1;
}
+audio_channel_mask_t get_channel_mask_for_name(char *name) {
+ audio_channel_mask_t channel_type = AUDIO_CHANNEL_INVALID;
+ if (NULL == name)
+ return channel_type;
+ else if (strncmp(name, "fl", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT;
+ else if (strncmp(name, "fr", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+ else if (strncmp(name, "fc", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_CENTER;
+ else if (strncmp(name, "lfe", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_LOW_FREQUENCY;
+ else if (strncmp(name, "bl", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_BACK_LEFT;
+ else if (strncmp(name, "br", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_BACK_RIGHT;
+ else if (strncmp(name, "flc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER;
+ else if (strncmp(name, "frc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER;
+ else if (strncmp(name, "bc", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_BACK_CENTER;
+ else if (strncmp(name, "sl", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_SIDE_LEFT;
+ else if (strncmp(name, "sr", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_SIDE_RIGHT;
+ else if (strncmp(name, "tc", 2) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_CENTER;
+ else if (strncmp(name, "tfl", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT;
+ else if (strncmp(name, "tfc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER;
+ else if (strncmp(name, "tfr", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT;
+ else if (strncmp(name, "tbl", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_LEFT;
+ else if (strncmp(name, "tbc", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_CENTER;
+ else if (strncmp(name, "tbr", 3) == 0)
+ channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT;
+
+ return channel_type;
+}
+
+int extract_channel_mapping(uint32_t *channel_map, const char * arg_string){
+
+ char *token_string = NULL;
+ char *init_ptr = NULL;
+ char *token = NULL;
+ char *saveptr = NULL;
+
+ if (NULL == channel_map)
+ return -EINVAL;
+
+ if (NULL == arg_string)
+ return EINVAL;
+
+ token_string = strdup(arg_string);
+
+ if(token_string != NULL) {
+ init_ptr = token_string;
+ token = strtok_r(token_string, ",", &saveptr);
+ int index = 0;
+ if (NULL == token)
+ return -EINVAL;
+ else
+ channel_map[index++] = get_channel_mask_for_name(token);
+
+ while(NULL !=(token = strtok_r(NULL,",",&saveptr)))
+ channel_map[index++] = get_channel_mask_for_name(token);
+
+ free(init_ptr);
+ init_ptr = NULL;
+ token_string = NULL;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+int extract_mixer_coeffs(qahw_mix_matrix_params_t * mm_params, const char * arg_string){
+
+ char *token_string = NULL;
+ char *init_ptr = NULL;
+ char *token = NULL;
+ char *saveptr = NULL;
+ int i = 0;
+ int j = 0;
+
+ if (NULL == mm_params)
+ return -EINVAL;
+
+ if (NULL == arg_string)
+ return -EINVAL;
+
+ token_string = strdup(arg_string);
+
+ if(token_string != NULL) {
+ init_ptr = token_string;
+ token = strtok_r(token_string, ",", &saveptr);
+ int index = 0;
+ if (NULL == token)
+ return -EINVAL;
+ else {
+ mm_params->mixer_coeffs[i][j] = atof(token);
+ j++;
+ }
+
+ while(NULL !=(token = strtok_r(NULL,",",&saveptr))) {
+ if(j == mm_params->num_input_channels) {
+ j=0;
+ i++;
+ }
+ if(i == mm_params->num_output_channels)
+ break;
+ mm_params->mixer_coeffs[i][j++] = atof(token);
+ }
+ free(init_ptr);
+ init_ptr = NULL;
+ token_string = NULL;
+ } else
+ return -EINVAL;
+ return 0;
+}
int main(int argc, char* argv[]) {
char *ba = NULL;
+ char *temp_input_channel_map = NULL;
+ char *temp_output_channel_map = NULL;
+ char *temp_mixer_coeffs = NULL;
qahw_param_payload payload;
qahw_param_id param_id;
struct qahw_aptx_dec_param aptx_params;
+ qahw_mix_matrix_params_t mm_params;
int rc = 0;
int i = 0;
+ int iter_i = 0;
+ int iter_j = 0;
kpi_mode = false;
+ char mixer_ctrl_name[64] = {0};
+ int mixer_ctrl_type = 0;
event_trigger = false;
bool wakelock_acquired = false;
@@ -1899,6 +2052,11 @@
{"effect-preset", required_argument, 0, 'p'},
{"effect-strength", required_argument, 0, 'S'},
{"help", no_argument, 0, 'h'},
+ {"output-ch-map", required_argument, 0, 'O'},
+ {"input-ch-map", required_argument, 0, 'I'},
+ {"mixer-coeffs", required_argument, 0, 'M'},
+ {"num-out-ch", required_argument, 0, 'o'},
+ {"intr-strm", required_argument, 0, 'i'},
{0, 0, 0, 0}
};
@@ -1921,7 +2079,7 @@
while ((opt = getopt_long(argc,
argv,
- "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:S:p:qQh",
+ "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:S:p:qQhI:O:M:o:i:",
long_options,
&option_index)) != -1) {
@@ -1938,6 +2096,7 @@
case 'c':
stream_param[i].channels = atoi(optarg);
stream_param[i].config.channel_mask = audio_channel_out_mask_from_count(atoi(optarg));
+ mm_params.num_input_channels = stream_param[i].channels;
break;
case 'b':
stream_param[i].config.offload_info.bit_width = atoi(optarg);
@@ -1962,6 +2121,9 @@
log_file = stdout;
}
break;
+ case 'i':
+ stream_param[i].interactive_strm = atoi(optarg);
+ break;
case 't':
stream_param[i].filetype = atoi(optarg);
break;
@@ -1972,7 +2134,15 @@
stream_param[i].wma_fmt_type = atoi(optarg);
break;
case 'k':
- stream_param[i].kvpair_values = optarg;
+ get_kvpairs_string(optarg, "mixer_ctrl", mixer_ctrl_name);
+ if(strncmp(mixer_ctrl_name, "downmix", 7) == 0) {
+ mixer_ctrl_type = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+ } else if(strncmp(mixer_ctrl_name, "pan_scale", 9) == 0) {
+ mixer_ctrl_type = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+ } else {
+ mixer_ctrl_type = 0;
+ stream_param[i].kvpair_values = optarg;
+ }
break;
case 'D':
proxy_params.acp.file_name = optarg;
@@ -2033,6 +2203,18 @@
case 'm':
stream_param[i].usb_mode = atoi(optarg);
break;
+ case 'O':
+ temp_output_channel_map = strdup(optarg);
+ break;
+ case 'I':
+ temp_input_channel_map = strdup(optarg);
+ break;
+ case 'M':
+ temp_mixer_coeffs = strdup(optarg);
+ break;
+ case 'o':
+ mm_params.num_output_channels = atoi(optarg);
+ break;
case 'h':
usage();
return 0;
@@ -2041,6 +2223,49 @@
}
}
+ /*
+ * Process Input channel map's input
+ */
+ if (NULL != temp_input_channel_map) {
+ extract_channel_mapping(mm_params.input_channel_map, temp_input_channel_map);
+ mm_params.has_input_channel_map = 1;
+ fprintf(log_file, "\nInput channel mapping: ");
+ for (iter_i= 0; iter_i < mm_params.num_input_channels; iter_i++) {
+ fprintf(log_file, "0x%x, ", mm_params.input_channel_map[iter_i]);
+ }
+ free(temp_input_channel_map);
+ temp_input_channel_map = NULL;
+ }
+
+ /*
+ * Process Output channel map's input
+ */
+ if (NULL != temp_output_channel_map) {
+ extract_channel_mapping(mm_params.output_channel_map, temp_output_channel_map);
+ mm_params.has_output_channel_map = 1;
+ fprintf(log_file, "\nOutput channel mapping: ");
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
+ fprintf(log_file, "0x%x, ", mm_params.output_channel_map[iter_i]);
+
+ free(temp_output_channel_map);
+ temp_output_channel_map = NULL;
+ }
+
+ /*
+ * Process mixer-coeffs input
+ */
+ if (NULL != temp_mixer_coeffs) {
+ extract_mixer_coeffs(&mm_params, temp_mixer_coeffs);
+ mm_params.has_mixer_coeffs = 1;
+ fprintf(log_file, "\nmixer coeffs:\n");
+ for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++){
+ for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++){
+ fprintf(log_file, "%.2f ",mm_params.mixer_coeffs[iter_i][iter_j]);
+ }
+ fprintf(log_file, "\n");
+ }
+ }
+
wakelock_acquired = request_wake_lock(wakelock_acquired, true);
num_of_streams = i+1;
/* Caution: Below ADL log shouldnt be altered without notifying automation APT since it used
@@ -2085,7 +2310,7 @@
for (i = 0; i < num_of_streams; i++) {
stream = &stream_param[i];
- if ((kpi_mode == false) &&
+ if ((kpi_mode == false) &&
(AUDIO_DEVICE_NONE == stream->input_device)){
if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
fprintf(log_file, "Primary file name is must for non kpi-mode\n");
@@ -2189,7 +2414,6 @@
fprintf(log_file, "stream %d: play_later = %d\n", i, stream_param[i].play_later);
}
-
rc = pthread_create(&playback_thread[i], NULL, start_stream_playback, (void *)&stream_param[i]);
if (rc) {
fprintf(log_file, "stream %d: failed to create thread\n", stream->stream_index);
@@ -2198,7 +2422,23 @@
}
thread_active[i] = true;
-
+ usleep(500000); //Wait until stream is created
+ if(mixer_ctrl_type == QAHW_PARAM_OUT_MIX_MATRIX_PARAMS) {
+ payload = (qahw_param_payload) mm_params;
+ param_id = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+ rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
+ if (rc != 0) {
+ fprintf(log_file, "QAHW_PARAM_OUT_MIX_MATRIX_PARAMS could not be sent!\n");
+ }
+ }
+ if(mixer_ctrl_type == QAHW_PARAM_CH_MIX_MATRIX_PARAMS) {
+ payload = (qahw_param_payload) mm_params;
+ param_id = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+ rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
+ if (rc != 0) {
+ fprintf(log_file, "QAHW_PARAM_CH_MIX_MATRIX_PARAMS could not be sent!\n");
+ }
+ }
}
exit: