Merge tag 'upstream/14.2.93' into feature/bookworm/upgrade-14.2.93
This commit is contained in:
commit
0886d509fc
10 changed files with 600 additions and 313 deletions
|
|
@ -2,20 +2,21 @@ PulseAudio Droid modules
|
|||
========================
|
||||
|
||||
Building of droid modules is split to two packages
|
||||
* common (and common-devel) which contains shared library code for use in
|
||||
PulseAudio modules in this package and for inclusion in other projects
|
||||
* droid with actual PulseAudio modules
|
||||
* **common** (and **common-devel**) which contains shared library code for use in
|
||||
PulseAudio modules in this package and for inclusion in other projects
|
||||
* **droid** with actual PulseAudio modules
|
||||
|
||||
Supported Android versions:
|
||||
|
||||
* 4.1.x with Qualcomm extensions (tested with 4.1.2)
|
||||
* 4.2.x
|
||||
* 4.4.x
|
||||
* 5.x
|
||||
* 6.0.x
|
||||
* 7.x
|
||||
* 8.x
|
||||
* 9.x
|
||||
* 4.1.x with Qualcomm extensions (tested with 4.1.2)
|
||||
* 4.2.x
|
||||
* 4.4.x
|
||||
* 5.x
|
||||
* 6.0.x
|
||||
* 7.x
|
||||
* 8.x
|
||||
* 9.x
|
||||
* 10.x
|
||||
|
||||
Headers for defining devices and strings for different droid versions are in
|
||||
src/common/droid-util-audio.h (legacy headers for Jolla 1 in droid-util-41qc.h).
|
||||
|
|
@ -26,11 +27,11 @@ and FANCY_ENTRY_IF_FOO if enum FOO exists in HAL audio.h.
|
|||
|
||||
For example:
|
||||
|
||||
# configure.ac:
|
||||
# configure.ac:
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_IP])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_OTHER_NEW])
|
||||
|
||||
# and then in droid-util-audio.h add macros to proper tables:
|
||||
# and then in droid-util-audio.h add macros to proper tables:
|
||||
/* string_conversion_table_output_device[] */
|
||||
STRING_ENTRY_IF_OUT_IP
|
||||
STRING_ENTRY_IF_OUT_OTHER_NEW
|
||||
|
|
@ -141,18 +142,18 @@ routes audio to internal handsfree (ihf - "handsfree speaker"):
|
|||
(Before starting, droid_card.primary is using profile primary-primary and
|
||||
sink.primary port output-speaker)
|
||||
|
||||
pactl set-card-profile droid_card.primary voicecall
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
pactl set-card-profile droid_card.primary voicecall
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
|
||||
After this, when there is an active voicecall (created by ofono for example),
|
||||
voice audio starts to flow between modem and audio chip.
|
||||
|
||||
To disable voicecall and return to media audio:
|
||||
|
||||
pactl set-card-profile droid_card.primary primary-primary
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
pactl set-card-profile droid_card.primary primary-primary
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
|
||||
With this example sequence sinks and sources are the ones from primary-primary
|
||||
card profile, and they are maintained for the whole duration of the voicecall
|
||||
|
|
@ -165,10 +166,10 @@ active port is a no-op (output/input-parking doesn't do any real routing
|
|||
changes).
|
||||
|
||||
Current virtual profiles are:
|
||||
* voicecall
|
||||
* voicecall-record
|
||||
* communication
|
||||
* ringtone
|
||||
* voicecall
|
||||
* voicecall-record
|
||||
* communication
|
||||
* ringtone
|
||||
|
||||
Communication profile is used for VoIP-like applications, to enable some
|
||||
voicecall related algorithms without being in voicecall. Ringtone profile
|
||||
|
|
@ -201,7 +202,7 @@ to PulseAudio card profiles. For example configuration with
|
|||
}
|
||||
}
|
||||
|
||||
Would map to card profiles (<output>-<input>) primary-primary and lpa-primary.
|
||||
Would map to card profiles ([output]-[input]) primary-primary and lpa-primary.
|
||||
|
||||
module-droid-sink and module-droid-source
|
||||
-----------------------------------------
|
||||
|
|
@ -211,7 +212,8 @@ hand, but droid-card loads appropriate modules based on the active card
|
|||
profile.
|
||||
|
||||
Output and input ports for droid-sink and droid-source are generated from the
|
||||
audio_policy.conf, where each device generates (usually) one port, for example:
|
||||
audio_policy_configuration.xml (where available) or audio_policy.conf (legacy),
|
||||
where each device generates (usually) one port, for example:
|
||||
|
||||
audio_hw_modules {
|
||||
primary {
|
||||
|
|
@ -245,7 +247,7 @@ droid-util-XXX.h
|
|||
|
||||
Changing output routing is then as simple as
|
||||
|
||||
pactl set-sink-port sink.primary output-wired_headphone
|
||||
pactl set-sink-port sink.primary output-wired_headphone
|
||||
|
||||
Sink or source do not track possible headphone/other wired accessory plugging,
|
||||
but this needs to be handled elsewhere and then that other entity needs to
|
||||
|
|
@ -273,20 +275,20 @@ to read from the source but through resampler.
|
|||
|
||||
For example,
|
||||
|
||||
1) source-output 44100Hz, stereo connects (so1)
|
||||
a) source is configured with 44100Hz, stereo
|
||||
b) so1 connects to the source without resampler
|
||||
2) source-output 16000Hz, mono connects (so2)
|
||||
a) so1 is detached from the source
|
||||
b) source is configured with 16000Hz, mono
|
||||
c) so2 connects to the source without resampler
|
||||
d) resampler is created for so1, 16000Hz, mono -> 44100Hz stereo
|
||||
f) so1 is re-attached to the source through resampler
|
||||
3) source-output 16000Hz, mono connects (so3)
|
||||
a) so1 and so2 are detached from the source
|
||||
b) so3 connects to the source without resampler
|
||||
c) so1 is re-attached to the source through resampler
|
||||
d) so2 is attached to the source
|
||||
1) source-output 44100Hz, stereo connects (so1)
|
||||
1) source is configured with 44100Hz, stereo
|
||||
2) so1 connects to the source without resampler
|
||||
2) source-output 16000Hz, mono connects (so2)
|
||||
1) so1 is detached from the source
|
||||
2) source is configured with 16000Hz, mono
|
||||
3) so2 connects to the source without resampler
|
||||
4) resampler is created for so1, 16000Hz, mono -> 44100Hz stereo
|
||||
5) so1 is re-attached to the source through resampler
|
||||
3) source-output 16000Hz, mono connects (so3)
|
||||
1) so1 and so2 are detached from the source
|
||||
2) so3 connects to the source without resampler
|
||||
3) so1 is re-attached to the source through resampler
|
||||
4) so2 is attached to the source
|
||||
|
||||
Classifying sinks and sources
|
||||
-----------------------------
|
||||
|
|
@ -296,14 +298,14 @@ functionality to ease device classification.
|
|||
|
||||
Currently following properties are set:
|
||||
|
||||
* For droid sinks
|
||||
* droid.output.primary
|
||||
* droid.output.low_latency
|
||||
* droid.output.media_latency
|
||||
* droid.output.offload
|
||||
* For droid sources
|
||||
* droid.input.builtin
|
||||
* droid.input.external
|
||||
* For droid sinks
|
||||
* droid.output.primary
|
||||
* droid.output.low_latency
|
||||
* droid.output.media_latency
|
||||
* droid.output.offload
|
||||
* For droid sources
|
||||
* droid.input.builtin
|
||||
* droid.input.external
|
||||
|
||||
If the property is set and with value "true", the sink or source should be
|
||||
used for the property type. If the property is not defined or contains
|
||||
|
|
@ -312,11 +314,11 @@ value "false" it shouldn't be used for the property type.
|
|||
For example, we might have sink.primary and sink.low_latency with following
|
||||
properties:
|
||||
|
||||
* sink.primary
|
||||
* droid.output.primary "true"
|
||||
* droid.output.media_latency "true"
|
||||
* sink.low_latency
|
||||
* droid.output.low_latency "true"
|
||||
* sink.primary
|
||||
* droid.output.primary "true"
|
||||
* droid.output.media_latency "true"
|
||||
* sink.low_latency
|
||||
* droid.output.low_latency "true"
|
||||
|
||||
There also may be just one sink, with all the properties defined as "true"
|
||||
and so on.
|
||||
|
|
@ -333,53 +335,73 @@ are enabled by default with some adaptations etc.
|
|||
|
||||
Currently there are following quirks:
|
||||
|
||||
* input_atoi
|
||||
* Enabled by default with Android versions 5 and up.
|
||||
* Due to how atoi works in bionic vs libc we need to pass the input
|
||||
route a bit funny. If input routing doesn't work switch this on or off.
|
||||
* set_parameters
|
||||
* Disabled by default.
|
||||
* Some adaptations need to use hw module's generic set_parameters call
|
||||
to change input routing. If input routing doesn't work switch this
|
||||
on or off. (mostly just older adaptations)
|
||||
* close_input
|
||||
* Enabled by default.
|
||||
* Close input stream when not in use instead of suspending the stream.
|
||||
Cannot be changed when multiple inputs are merged to single source.
|
||||
* unload_no_close
|
||||
* Disabled by default.
|
||||
* Don't call audio_hw_device_close() for the hw module when unloading.
|
||||
Mostly useful for tracking module unload issues.
|
||||
* no_hw_volume
|
||||
* Disabled by default.
|
||||
* Some broken implementations are incorrectly probed for supporting hw
|
||||
volume control. This is manifested by always full volume with volume
|
||||
control not affecting volume level. To fix this enable this quirk.
|
||||
* output_make_writable
|
||||
* Disabled by default.
|
||||
* Some implementations modify write buffer in-place when this should
|
||||
not be done. This can result in random segfaults when playing audio.
|
||||
As a workaround make the buffer memchunk writable before passing to
|
||||
audio HAL.
|
||||
* realcall
|
||||
* Disabled by default.
|
||||
* Some vendors apply custom realcall parameter to HAL device when
|
||||
doing voicecall routing. If there is no voicecall audio you can
|
||||
try enabling this quirk so that the realcall parameter is applied
|
||||
when switching to voicecall profile.
|
||||
* unload_call_exit
|
||||
* Disabled by default.
|
||||
* Some HAL module implementations get stuck in mutex or segfault when
|
||||
trying to unload the module. To avoid confusing segfaults call
|
||||
exit(0) instead of calling unload for the module.
|
||||
* output_fast
|
||||
* Enabled by default.
|
||||
* Create separate sink if AUDIO_OUTPUT_FLAG_FAST is found. If this sink
|
||||
is misbehaving try disabling this quirk.
|
||||
* output_deep_buffer
|
||||
* Enabled by default.
|
||||
* Create separate sink if AUDIO_OUTPUT_FLAG_DEEP_BUFFER is found. If
|
||||
this sink is misbehaving try disabling this quirk.
|
||||
* input_atoi
|
||||
* Enabled by default with Android versions 5 and up.
|
||||
* Due to how atoi works in bionic vs libc we need to pass the input
|
||||
route a bit funny. If input routing doesn't work switch this on or off.
|
||||
* set_parameters
|
||||
* Disabled by default.
|
||||
* Some adaptations need to use hw module's generic set_parameters call
|
||||
to change input routing. If input routing doesn't work switch this
|
||||
on or off. (mostly just older adaptations)
|
||||
* close_input
|
||||
* Enabled by default.
|
||||
* Close input stream when not in use instead of suspending the stream.
|
||||
Cannot be changed when multiple inputs are merged to single source.
|
||||
* unload_no_close
|
||||
* Disabled by default.
|
||||
* Don't call audio_hw_device_close() for the hw module when unloading.
|
||||
Mostly useful for tracking module unload issues.
|
||||
* no_hw_volume
|
||||
* Disabled by default.
|
||||
* Some broken implementations are incorrectly probed for supporting hw
|
||||
volume control. This is manifested by always full volume with volume
|
||||
control not affecting volume level. To fix this enable this quirk.
|
||||
* output_make_writable
|
||||
* Disabled by default.
|
||||
* Some implementations modify write buffer in-place when this should
|
||||
not be done. This can result in random segfaults when playing audio.
|
||||
As a workaround make the buffer memchunk writable before passing to
|
||||
audio HAL.
|
||||
* realcall
|
||||
* Disabled by default.
|
||||
* Some vendors apply custom realcall parameter to HAL device when
|
||||
doing voicecall routing. If there is no voicecall audio you can
|
||||
try enabling this quirk so that the realcall parameter is applied
|
||||
when switching to voicecall profile.
|
||||
* unload_call_exit
|
||||
* Disabled by default.
|
||||
* Some HAL module implementations get stuck in mutex or segfault when
|
||||
trying to unload the module. To avoid confusing segfaults call
|
||||
exit(0) instead of calling unload for the module.
|
||||
* output_fast
|
||||
* Enabled by default.
|
||||
* Create separate sink if AUDIO_OUTPUT_FLAG_FAST is found. If this sink
|
||||
is misbehaving try disabling this quirk.
|
||||
* output_deep_buffer
|
||||
* Enabled by default.
|
||||
* Create separate sink if AUDIO_OUTPUT_FLAG_DEEP_BUFFER is found. If
|
||||
this sink is misbehaving try disabling this quirk.
|
||||
* audio_cal_wait
|
||||
* Disabled by default.
|
||||
* Certain devices do audio calibration during hw module open and
|
||||
writing audio too early will break the calibration. In these cases
|
||||
this quirk can be enabled and 10 seconds of sleep is added after
|
||||
opening hw module.
|
||||
* standby_set_route
|
||||
* Disabled by default.
|
||||
* Some devices don't like to receive set_parameters() call while they
|
||||
are in write(), even if it seems the mutexes are correctly in place.
|
||||
Standby is another synchronization point which seems to work better.
|
||||
If there are hiccups like long delays when setting route during
|
||||
voice call start try enabling this quirk.
|
||||
* speaker_before_voice
|
||||
* Disabled by default.
|
||||
* Set route to speaker before changing audio mode to AUDIO_MODE_IN_CALL.
|
||||
Some devices don't get routing right if the route is something else
|
||||
(like AUDIO_DEVICE_OUT_WIRED_HEADSET) before calling set_mode().
|
||||
If routing is wrong when call starts with wired accessory connected
|
||||
try enabling this quirk.
|
||||
|
||||
For example, to disable input_atoi and enable close_input quirks, use module
|
||||
argument
|
||||
|
|
@ -409,7 +431,7 @@ droid.device.additional-route connects to droid-sink, this extra route is set
|
|||
|
||||
For example, if droid-sink has active port output-wired_headphone:
|
||||
|
||||
paplay --property=droid.device.additional-route=AUDIO_DEVICE_OUT_SPEAKER a.wav
|
||||
paplay --property=droid.device.additional-route=AUDIO_DEVICE_OUT_SPEAKER a.wav
|
||||
|
||||
As long as the new stream is connected to droid-sink, output routing is
|
||||
SPEAKER.
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
Name: pulseaudio-modules-droid-%{device}
|
||||
|
||||
Summary: PulseAudio Droid HAL modules
|
||||
Version: %{pulsemajorminor}.86
|
||||
Version: %{pulsemajorminor}.93
|
||||
Release: 1
|
||||
License: LGPLv2+
|
||||
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Name: pulseaudio-modules-droid
|
||||
|
||||
Summary: PulseAudio Droid HAL modules
|
||||
Version: %{pulsemajorminor}.86
|
||||
Version: %{pulsemajorminor}.93
|
||||
Release: 1
|
||||
License: LGPLv2+
|
||||
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||
|
|
|
|||
|
|
@ -140,6 +140,40 @@ bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, c
|
|||
|
||||
case CONV_STRING_INPUT_FLAG:
|
||||
return string_convert_num_to_str(string_conversion_table_input_flag, value, to_str);
|
||||
|
||||
case CONV_STRING_AUDIO_SOURCE_FANCY:
|
||||
return string_convert_num_to_str(string_conversion_table_audio_source_fancy, value, to_str);
|
||||
}
|
||||
|
||||
pa_assert_not_reached();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pa_string_convert_str_to_num(pa_conversion_string_t type, const char *str, uint32_t *to_value) {
|
||||
switch (type) {
|
||||
case CONV_STRING_FORMAT:
|
||||
return string_convert_str_to_num(string_conversion_table_format, str, to_value);
|
||||
|
||||
case CONV_STRING_OUTPUT_CHANNELS:
|
||||
return string_convert_str_to_num(string_conversion_table_output_channels, str, to_value);
|
||||
|
||||
case CONV_STRING_INPUT_CHANNELS:
|
||||
return string_convert_str_to_num(string_conversion_table_input_channels, str, to_value);
|
||||
|
||||
case CONV_STRING_OUTPUT_DEVICE:
|
||||
return string_convert_str_to_num(string_conversion_table_output_device, str, to_value);
|
||||
|
||||
case CONV_STRING_INPUT_DEVICE:
|
||||
return string_convert_str_to_num(string_conversion_table_input_device, str, to_value);
|
||||
|
||||
case CONV_STRING_OUTPUT_FLAG:
|
||||
return string_convert_str_to_num(string_conversion_table_output_flag, str, to_value);
|
||||
|
||||
case CONV_STRING_INPUT_FLAG:
|
||||
return string_convert_str_to_num(string_conversion_table_input_flag, str, to_value);
|
||||
|
||||
case CONV_STRING_AUDIO_SOURCE_FANCY:
|
||||
return string_convert_str_to_num(string_conversion_table_audio_source_fancy, str, to_value);
|
||||
}
|
||||
|
||||
pa_assert_not_reached();
|
||||
|
|
@ -210,10 +244,6 @@ bool pa_droid_input_port_name(audio_devices_t value, const char **to_str) {
|
|||
return string_convert_num_to_str(string_conversion_table_input_device_fancy, (uint32_t) value, to_str);
|
||||
}
|
||||
|
||||
bool pa_droid_audio_source_name(audio_source_t value, const char **to_str) {
|
||||
return string_convert_num_to_str(string_conversion_table_audio_source_fancy, (uint32_t) value, to_str);
|
||||
}
|
||||
|
||||
static int parse_list(const struct string_conversion *table,
|
||||
const char *separator,
|
||||
const char *str,
|
||||
|
|
@ -280,6 +310,10 @@ int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
|||
|
||||
case CONV_STRING_INPUT_FLAG:
|
||||
return parse_list(string_conversion_table_input_flag, separator, str, dst, unknown_entries);
|
||||
|
||||
/* Not handled in this context */
|
||||
case CONV_STRING_AUDIO_SOURCE_FANCY:
|
||||
return 0;
|
||||
}
|
||||
|
||||
pa_assert_not_reached();
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
#include <valgrind/memcheck.h>
|
||||
|
|
@ -37,6 +41,7 @@
|
|||
#include <pulse/volume.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/direction.h>
|
||||
#include <pulse/util.h>
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
|
|
@ -82,16 +87,36 @@ struct droid_quirk valid_quirks[] = {
|
|||
{ "unload_call_exit", QUIRK_UNLOAD_CALL_EXIT },
|
||||
{ "output_fast", QUIRK_OUTPUT_FAST },
|
||||
{ "output_deep_buffer", QUIRK_OUTPUT_DEEP_BUFFER },
|
||||
{ "audio_cal_wait", QUIRK_AUDIO_CAL_WAIT },
|
||||
{ "standby_set_route", QUIRK_STANDBY_SET_ROUTE },
|
||||
{ "speaker_before_voice", QUIRK_SPEAKER_BEFORE_VOICE },
|
||||
};
|
||||
|
||||
#define QUIRK_AUDIO_CAL_WAIT_S (10)
|
||||
#define QUIRK_AUDIO_CAL_FILE "/data/vendor/audio/cirrus_sony.cal"
|
||||
#define QUIRK_AUDIO_CAL_GROUP "audio"
|
||||
#define QUIRK_AUDIO_CAL_MODE (0664)
|
||||
|
||||
#define DEFAULT_PRIORITY (100)
|
||||
#define DEFAULT_AUDIO_FORMAT (AUDIO_FORMAT_PCM_16_BIT)
|
||||
|
||||
|
||||
#ifndef AUDIO_PARAMETER_VALUE_ON
|
||||
#define AUDIO_PARAMETER_VALUE_ON "on"
|
||||
#endif
|
||||
|
||||
#ifndef AUDIO_PARAMETER_VALUE_OFF
|
||||
#define AUDIO_PARAMETER_VALUE_OFF "off"
|
||||
#endif
|
||||
|
||||
#define AUDIO_PARAMETER_BT_SCO_ON "BT_SCO=" AUDIO_PARAMETER_VALUE_ON
|
||||
#define AUDIO_PARAMETER_BT_SCO_OFF "BT_SCO=" AUDIO_PARAMETER_VALUE_OFF
|
||||
|
||||
static void droid_port_free(pa_droid_port *p);
|
||||
|
||||
static int input_stream_set_route(pa_droid_hw_module *hw_module, pa_droid_stream *s);
|
||||
static int droid_set_parameters(pa_droid_hw_module *hw, const char *parameters);
|
||||
static bool droid_set_audio_source(pa_droid_hw_module *hw_module, audio_source_t audio_source);
|
||||
|
||||
static pa_droid_profile *profile_new(pa_droid_profile_set *ps,
|
||||
const pa_droid_config_hw_module *module,
|
||||
|
|
@ -685,30 +710,20 @@ void pa_droid_quirk_log(pa_droid_hw_module *hw) {
|
|||
|
||||
pa_assert(hw);
|
||||
|
||||
if (hw->quirks) {
|
||||
for (i = 0; i < sizeof(valid_quirks) / sizeof(struct droid_quirk); i++) {
|
||||
if (hw->quirks->enabled[i]) {
|
||||
pa_log_debug("Enabled quirks:");
|
||||
for (i = 0; i < sizeof(valid_quirks) / sizeof(struct droid_quirk); i++)
|
||||
if (hw->quirks->enabled[i])
|
||||
pa_log_debug(" %s", valid_quirks[i].name);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < sizeof(valid_quirks) / sizeof(struct droid_quirk); i++) {
|
||||
if (hw->quirks.enabled[i]) {
|
||||
pa_log_debug("Enabled quirks:");
|
||||
for (i = 0; i < sizeof(valid_quirks) / sizeof(struct droid_quirk); i++)
|
||||
if (hw->quirks.enabled[i])
|
||||
pa_log_debug(" %s", valid_quirks[i].name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static pa_droid_quirks *get_quirks(pa_droid_quirks *q) {
|
||||
if (!q)
|
||||
q = pa_xnew0(pa_droid_quirks, 1);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static pa_droid_quirks *set_default_quirks(pa_droid_quirks *q) {
|
||||
q = NULL;
|
||||
pa_assert(q);
|
||||
|
||||
q = get_quirks(q);
|
||||
q->enabled[QUIRK_CLOSE_INPUT] = true;
|
||||
q->enabled[QUIRK_OUTPUT_FAST] = true;
|
||||
q->enabled[QUIRK_OUTPUT_DEEP_BUFFER] = true;
|
||||
|
|
@ -729,19 +744,23 @@ static pa_droid_quirks *set_default_quirks(pa_droid_quirks *q) {
|
|||
return q;
|
||||
}
|
||||
|
||||
bool pa_droid_quirk_parse(pa_droid_hw_module *hw, const char *quirks) {
|
||||
bool pa_droid_quirk_parse(pa_droid_quirks *quirks, const char *quirks_def) {
|
||||
char *quirk = NULL;
|
||||
char *d;
|
||||
const char *state = NULL;
|
||||
|
||||
pa_assert(hw);
|
||||
pa_assert(quirks);
|
||||
|
||||
hw->quirks = get_quirks(hw->quirks);
|
||||
memset(quirks, 0, sizeof(*quirks));
|
||||
set_default_quirks(quirks);
|
||||
|
||||
while ((quirk = pa_split(quirks, ",", &state))) {
|
||||
if (!quirks_def)
|
||||
return true;
|
||||
|
||||
while ((quirk = pa_split(quirks_def, ",", &state))) {
|
||||
uint32_t i;
|
||||
bool enable = false;
|
||||
bool found = false;
|
||||
|
||||
if (strlen(quirk) < 2)
|
||||
goto error;
|
||||
|
|
@ -756,17 +775,22 @@ bool pa_droid_quirk_parse(pa_droid_hw_module *hw, const char *quirks) {
|
|||
goto error;
|
||||
|
||||
for (i = 0; i < sizeof(valid_quirks) / sizeof(struct droid_quirk); i++) {
|
||||
if (pa_streq(valid_quirks[i].name, d))
|
||||
hw->quirks->enabled[valid_quirks[i].value] = enable;
|
||||
if (pa_streq(valid_quirks[i].name, d)) {
|
||||
quirks->enabled[valid_quirks[i].value] = enable;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto error;
|
||||
|
||||
pa_xfree(quirk);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
pa_log("Incorrect quirk definition \"%s\" (\"%s\")", quirk ? quirk : "<null>", quirks);
|
||||
pa_log("Incorrect quirk definition \"%s\" (\"%s\")", quirk ? quirk : "<null>", quirks_def);
|
||||
pa_xfree(quirk);
|
||||
|
||||
return false;
|
||||
|
|
@ -859,7 +883,68 @@ static char *shared_name_get(const char *module_id) {
|
|||
return pa_sprintf_malloc("droid-hardware-module-%s", module_id);
|
||||
}
|
||||
|
||||
static pa_droid_hw_module *droid_hw_module_open(pa_core *core, const pa_droid_config_audio *config, const char *module_id) {
|
||||
static void quirk_audio_cal(pa_droid_hw_module *hw, uint32_t flags) {
|
||||
struct group *grp;
|
||||
|
||||
pa_assert(hw);
|
||||
|
||||
if (!pa_droid_quirk(hw, QUIRK_AUDIO_CAL_WAIT))
|
||||
return;
|
||||
|
||||
if (access(QUIRK_AUDIO_CAL_FILE, F_OK) == 0) {
|
||||
if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
|
||||
pa_log_info("Waiting for audio calibration to load.");
|
||||
/* 1 second is enough, so let's double that. */
|
||||
pa_msleep(2 * PA_MSEC_PER_SEC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
pa_log_info("Waiting for audio calibration to finish... (%d seconds)", QUIRK_AUDIO_CAL_WAIT_S);
|
||||
|
||||
/* First wait until the calibration file appears on file system. */
|
||||
for (int i = 0; i < QUIRK_AUDIO_CAL_WAIT_S; i++) {
|
||||
pa_log_debug("%d...", QUIRK_AUDIO_CAL_WAIT_S - i);
|
||||
pa_msleep(PA_MSEC_PER_SEC);
|
||||
if (access(QUIRK_AUDIO_CAL_FILE, F_OK) == 0) {
|
||||
pa_log_debug("Calibration file " QUIRK_AUDIO_CAL_FILE " appeared, wait one second more.");
|
||||
/* Then wait for a bit more. */
|
||||
pa_msleep(PA_MSEC_PER_SEC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (access(QUIRK_AUDIO_CAL_FILE, F_OK) != 0)
|
||||
goto fail;
|
||||
|
||||
if (!(grp = getgrnam(QUIRK_AUDIO_CAL_GROUP))) {
|
||||
pa_log("couldn't get gid for " QUIRK_AUDIO_CAL_GROUP);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (chown(QUIRK_AUDIO_CAL_FILE, getuid(), grp->gr_gid) < 0) {
|
||||
pa_log("chown failed for " QUIRK_AUDIO_CAL_FILE);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (chmod(QUIRK_AUDIO_CAL_FILE, QUIRK_AUDIO_CAL_MODE) < 0) {
|
||||
pa_log("chmod failed for " QUIRK_AUDIO_CAL_FILE);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_log_info("Done waiting for audio calibration.");
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (access(QUIRK_AUDIO_CAL_FILE, F_OK) == 0)
|
||||
unlink(QUIRK_AUDIO_CAL_FILE);
|
||||
|
||||
pa_log("Audio calibration file generation failed! (" QUIRK_AUDIO_CAL_FILE " doesn't exist)");
|
||||
}
|
||||
|
||||
static pa_droid_hw_module *droid_hw_module_open(pa_core *core, const pa_droid_config_audio *config,
|
||||
const char *module_id, const pa_droid_quirks *quirks) {
|
||||
const pa_droid_config_hw_module *module;
|
||||
pa_droid_hw_module *hw = NULL;
|
||||
struct hw_module_t *hwmod = NULL;
|
||||
|
|
@ -920,7 +1005,10 @@ static pa_droid_hw_module *droid_hw_module_open(pa_core *core, const pa_droid_co
|
|||
hw->shared_name = shared_name_get(hw->module_id);
|
||||
hw->outputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
|
||||
hw->inputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
|
||||
hw->quirks = set_default_quirks(hw->quirks);
|
||||
if (quirks)
|
||||
memcpy(&hw->quirks, quirks, sizeof(*quirks));
|
||||
else
|
||||
set_default_quirks(&hw->quirks);
|
||||
|
||||
hw->sink_put_hook_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_EARLY-10,
|
||||
sink_put_hook_cb, hw);
|
||||
|
|
@ -941,20 +1029,59 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id) {
|
||||
pa_droid_hw_module *hw;
|
||||
static pa_droid_hw_module *droid_hw_module_shared_get(pa_core *core, const char *module_id) {
|
||||
pa_droid_hw_module *hw = NULL;
|
||||
char *shared_name;
|
||||
|
||||
pa_assert(core);
|
||||
pa_assert(module_id);
|
||||
|
||||
shared_name = shared_name_get(module_id);
|
||||
|
||||
if ((hw = pa_shared_get(core, shared_name)))
|
||||
hw = pa_droid_hw_module_ref(hw);
|
||||
else
|
||||
hw = droid_hw_module_open(core, config, module_id);
|
||||
|
||||
pa_xfree(shared_name);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
pa_droid_hw_module *pa_droid_hw_module_get2(pa_core *core, pa_modargs *ma, const char *module_id) {
|
||||
pa_droid_hw_module *hw = NULL;
|
||||
pa_droid_config_audio *config = NULL;
|
||||
pa_droid_quirks quirks;
|
||||
|
||||
pa_assert(core);
|
||||
pa_assert(ma);
|
||||
pa_assert(module_id);
|
||||
|
||||
/* First let's find out if hw module has already been opened. */
|
||||
|
||||
if ((hw = droid_hw_module_shared_get(core, module_id)))
|
||||
return hw;
|
||||
|
||||
/* No hw module object in shared object db, let's parse quirks and config and
|
||||
* open the module now. */
|
||||
|
||||
if (!pa_droid_quirk_parse(&quirks, pa_modargs_get_value(ma, "quirks", NULL)))
|
||||
return NULL;
|
||||
|
||||
if (!(config = pa_droid_config_load(ma)))
|
||||
return NULL;
|
||||
|
||||
hw = droid_hw_module_open(core, config, module_id, &quirks);
|
||||
|
||||
pa_droid_config_free(config);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id) {
|
||||
pa_droid_hw_module *hw;
|
||||
|
||||
if (!(hw = droid_hw_module_shared_get(core, module_id)))
|
||||
hw = droid_hw_module_open(core, config, module_id, NULL);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
|
|
@ -1008,8 +1135,6 @@ static void droid_hw_module_close(pa_droid_hw_module *hw) {
|
|||
pa_idxset_free(hw->inputs, NULL);
|
||||
}
|
||||
|
||||
pa_xfree(hw->quirks);
|
||||
|
||||
pa_xfree(hw);
|
||||
}
|
||||
|
||||
|
|
@ -1267,6 +1392,8 @@ pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
pa_log_info("Open output stream %s", module_output_name);
|
||||
|
||||
if (!stream_config_fill(module_output, devices, &sample_spec, &channel_map, &config_out))
|
||||
goto fail;
|
||||
|
||||
|
|
@ -1288,7 +1415,7 @@ pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
|||
#if AUDIO_API_VERSION_MAJ >= 3
|
||||
/* Go with empty address, should work
|
||||
* with most devices for now. */
|
||||
, NULL
|
||||
, ""
|
||||
#endif
|
||||
);
|
||||
pa_droid_hw_module_unlock(module);
|
||||
|
|
@ -1298,6 +1425,8 @@ pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
quirk_audio_cal(module, module_output->flags);
|
||||
|
||||
s = droid_stream_new(module, module_output);
|
||||
s->output = output = droid_output_stream_new();
|
||||
output->stream = stream;
|
||||
|
|
@ -1313,7 +1442,7 @@ pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
|||
|
||||
s->buffer_size = output->stream->common.get_buffer_size(&output->stream->common);
|
||||
|
||||
pa_log_info("Opened droid output stream %p with device: %u flags: %u sample rate: %u channels: %u (%u) format: %u (%u) buffer size: %u (%llu usec)",
|
||||
pa_log_info("Opened droid output stream %p with device: %u flags: %u sample rate: %u channels: %u (%u) format: %u (%u) buffer size: %zu (%" PRIu64 " usec)",
|
||||
(void *) s,
|
||||
devices,
|
||||
output->flags,
|
||||
|
|
@ -1510,7 +1639,7 @@ static int input_stream_open(pa_droid_stream *s, bool resume_from_suspend) {
|
|||
&input->stream
|
||||
#if AUDIO_API_VERSION_MAJ >= 3
|
||||
, 0
|
||||
, NULL /* Don't define address */
|
||||
, "" /* Use empty address. */
|
||||
, hw_module->state.audio_source
|
||||
#endif
|
||||
);
|
||||
|
|
@ -1624,7 +1753,11 @@ static void input_stream_close(pa_droid_stream *s) {
|
|||
|
||||
bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
|
||||
const pa_sample_spec *requested_sample_spec,
|
||||
const pa_channel_map *requested_channel_map) {
|
||||
const pa_channel_map *requested_channel_map,
|
||||
const pa_proplist *proplist) {
|
||||
/* Use default audio source by default */
|
||||
audio_source_t audio_source = AUDIO_SOURCE_DEFAULT;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert(s->input);
|
||||
pa_assert(requested_sample_spec);
|
||||
|
|
@ -1635,6 +1768,16 @@ bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
|
|||
s->input->req_sample_spec = *requested_sample_spec;
|
||||
s->input->req_channel_map = *requested_channel_map;
|
||||
|
||||
if (proplist) {
|
||||
const char *source;
|
||||
/* If audio source is defined in source-output proplist use that instead. */
|
||||
if ((source = pa_proplist_gets(proplist, PROP_DROID_INPUT_AUDIO_SOURCE)))
|
||||
pa_string_convert_str_to_num(CONV_STRING_AUDIO_SOURCE_FANCY, source, &audio_source);
|
||||
}
|
||||
|
||||
/* Update audio source */
|
||||
droid_set_audio_source(s->module, audio_source);
|
||||
|
||||
input_stream_close(s);
|
||||
|
||||
if (input_stream_open(s, false) < 0) {
|
||||
|
|
@ -1650,6 +1793,50 @@ bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool pa_droid_stream_reconfigure_input_needed(pa_droid_stream *s,
|
||||
const pa_sample_spec *requested_sample_spec,
|
||||
const pa_channel_map *requested_channel_map,
|
||||
const pa_proplist *proplist) {
|
||||
bool reconfigure_needed = false;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert(s->input);
|
||||
|
||||
if (requested_sample_spec && !pa_sample_spec_equal(&s->input->sample_spec, requested_sample_spec)) {
|
||||
reconfigure_needed = true;
|
||||
pa_log_debug("input reconfigure needed: sample specs not equal");
|
||||
}
|
||||
|
||||
if (requested_channel_map && !pa_channel_map_equal(&s->input->channel_map, requested_channel_map)) {
|
||||
reconfigure_needed = true;
|
||||
pa_log_debug("input reconfigure needed: channel maps not equal");
|
||||
}
|
||||
|
||||
if (proplist) {
|
||||
const char *source;
|
||||
audio_source_t audio_source;
|
||||
|
||||
/* If audio source is defined in source-output proplist use that instead. */
|
||||
if ((source = pa_proplist_gets(proplist, PROP_DROID_INPUT_AUDIO_SOURCE))) {
|
||||
if (pa_string_convert_str_to_num(CONV_STRING_AUDIO_SOURCE_FANCY, source, &audio_source) &&
|
||||
s->module->state.audio_source != audio_source) {
|
||||
|
||||
reconfigure_needed = true;
|
||||
pa_log_debug("input reconfigure needed: " PROP_DROID_INPUT_AUDIO_SOURCE " changes");
|
||||
}
|
||||
} else {
|
||||
if (pa_input_device_default_audio_source(s->module->state.input_device, &audio_source) &&
|
||||
s->module->state.audio_source != audio_source) {
|
||||
|
||||
reconfigure_needed = true;
|
||||
pa_log_debug("input reconfigure needed: audio source changes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reconfigure_needed;
|
||||
}
|
||||
|
||||
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
|
||||
const pa_sample_spec *default_sample_spec,
|
||||
const pa_channel_map *default_channel_map) {
|
||||
|
|
@ -1671,7 +1858,7 @@ pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
|
|||
s->input->default_sample_spec = *default_sample_spec;
|
||||
s->input->default_channel_map = *default_channel_map;
|
||||
|
||||
if (!pa_droid_stream_reconfigure_input(s, default_sample_spec, default_channel_map)) {
|
||||
if (!pa_droid_stream_reconfigure_input(s, default_sample_spec, default_channel_map, NULL)) {
|
||||
pa_droid_stream_unref(s);
|
||||
s = NULL;
|
||||
} else
|
||||
|
|
@ -1747,11 +1934,30 @@ static int droid_output_stream_set_route(pa_droid_stream *s, audio_devices_t dev
|
|||
pa_mutex_lock(s->module->output_mutex);
|
||||
|
||||
if (output->flags & AUDIO_OUTPUT_FLAG_PRIMARY || pa_droid_hw_primary_output_stream(s->module) == NULL) {
|
||||
int set_bt_sco = -1;
|
||||
|
||||
parameters = pa_sprintf_malloc("%s=%u;", AUDIO_PARAMETER_STREAM_ROUTING, device);
|
||||
|
||||
/* Set BT_SCO parameter for Bluetooth voice/voip call routes. */
|
||||
if (device != output->device &&
|
||||
(device | output->device) & (AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
|
||||
|
||||
set_bt_sco = (device & (AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
|
||||
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (set_bt_sco == 1)
|
||||
droid_set_parameters(s->module, AUDIO_PARAMETER_BT_SCO_ON);
|
||||
|
||||
pa_log_debug("output stream %p set_parameters(%s) %#010x", (void *) s, parameters, device);
|
||||
ret = output->stream->common.set_parameters(&output->stream->common, parameters);
|
||||
|
||||
if (set_bt_sco == 0)
|
||||
droid_set_parameters(s->module, AUDIO_PARAMETER_BT_SCO_OFF);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOSYS)
|
||||
pa_log_warn("output set_parameters(%s) not allowed while stream is active", parameters);
|
||||
|
|
@ -1770,6 +1976,13 @@ static int droid_output_stream_set_route(pa_droid_stream *s, audio_devices_t dev
|
|||
if (slave == s)
|
||||
continue;
|
||||
|
||||
if (pa_droid_quirk(s->module, QUIRK_STANDBY_SET_ROUTE)) {
|
||||
/* Some devices don't like to receive set_parameters() call while they
|
||||
* are in write(), even if it seems the mutexes are correctly in place.
|
||||
* Standby is another synchronization point which seems to work better. */
|
||||
slave->output->stream->common.standby(&slave->output->stream->common);
|
||||
}
|
||||
|
||||
pa_log_debug("slave output stream %p set_parameters(%s)", (void *) slave, parameters);
|
||||
ret = slave->output->stream->common.set_parameters(&slave->output->stream->common, parameters);
|
||||
|
||||
|
|
@ -1888,16 +2101,14 @@ int pa_droid_stream_set_parameters(pa_droid_stream *s, const char *parameters) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters) {
|
||||
static int droid_set_parameters(pa_droid_hw_module *hw, const char *parameters) {
|
||||
int ret;
|
||||
|
||||
pa_assert(hw);
|
||||
pa_assert(parameters);
|
||||
|
||||
pa_log_debug("hw %p set_parameters(%s)", (void *) hw, parameters);
|
||||
pa_mutex_lock(hw->hw_mutex);
|
||||
ret = hw->device->set_parameters(hw->device, parameters);
|
||||
pa_mutex_unlock(hw->hw_mutex);
|
||||
|
||||
if (ret < 0)
|
||||
pa_log("hw module %p set_parameters(%s) failed: %d", (void *) hw, parameters, ret);
|
||||
|
|
@ -1905,6 +2116,19 @@ int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters) {
|
||||
int ret;
|
||||
|
||||
pa_assert(hw);
|
||||
pa_assert(parameters);
|
||||
|
||||
pa_mutex_lock(hw->hw_mutex);
|
||||
ret = droid_set_parameters(hw, parameters);
|
||||
pa_mutex_unlock(hw->hw_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pa_droid_stream_is_primary(pa_droid_stream *s) {
|
||||
pa_assert(s);
|
||||
pa_assert(s->output || s->input);
|
||||
|
|
@ -2056,6 +2280,17 @@ bool pa_droid_hw_set_mode(pa_droid_hw_module *hw_module, audio_mode_t mode) {
|
|||
|
||||
pa_log_info("Set mode to %s.", audio_mode_to_string(mode));
|
||||
|
||||
if (pa_droid_quirk(hw_module, QUIRK_SPEAKER_BEFORE_VOICE) &&
|
||||
hw_module->state.mode != mode && mode == AUDIO_MODE_IN_CALL) {
|
||||
pa_droid_stream *primary_output;
|
||||
|
||||
/* Set route to speaker before changing audio mode to AUDIO_MODE_IN_CALL.
|
||||
* Some devices don't get routing right if the route is something else
|
||||
* (like AUDIO_DEVICE_OUT_WIRED_HEADSET) before calling set_mode().*/
|
||||
if ((primary_output = pa_droid_hw_primary_output_stream(hw_module)))
|
||||
pa_droid_stream_set_route(primary_output, AUDIO_DEVICE_OUT_SPEAKER);
|
||||
}
|
||||
|
||||
pa_droid_hw_module_lock(hw_module);
|
||||
if (hw_module->device->set_mode(hw_module->device, mode) < 0) {
|
||||
ret = false;
|
||||
|
|
@ -2081,26 +2316,14 @@ bool pa_droid_hw_set_mode(pa_droid_hw_module *hw_module, audio_mode_t mode) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
|
||||
audio_devices_t device) {
|
||||
audio_source_t audio_source = AUDIO_SOURCE_DEFAULT;
|
||||
/* Return true if audio source changes */
|
||||
static bool droid_set_audio_source(pa_droid_hw_module *hw_module, audio_source_t audio_source) {
|
||||
audio_source_t audio_source_override = AUDIO_SOURCE_DEFAULT;
|
||||
bool device_changed = false;
|
||||
bool source_changed = false;
|
||||
|
||||
pa_assert(hw_module);
|
||||
|
||||
if (hw_module->state.input_device != device) {
|
||||
const char *name = NULL;
|
||||
pa_log_debug("Set global input to %s (%#010x)",
|
||||
pa_string_convert_input_device_num_to_str(device, &name)
|
||||
? name : "<unknown>",
|
||||
device);
|
||||
hw_module->state.input_device = device;
|
||||
device_changed = true;
|
||||
}
|
||||
|
||||
pa_input_device_default_audio_source(hw_module->state.input_device, &audio_source);
|
||||
if (audio_source == AUDIO_SOURCE_DEFAULT)
|
||||
pa_input_device_default_audio_source(hw_module->state.input_device, &audio_source);
|
||||
|
||||
/* Override audio source based on mode. */
|
||||
switch (hw_module->state.mode) {
|
||||
|
|
@ -2116,9 +2339,9 @@ bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
|
|||
}
|
||||
|
||||
if (audio_source != audio_source_override) {
|
||||
const char *from, *to;
|
||||
pa_droid_audio_source_name(audio_source, &from);
|
||||
pa_droid_audio_source_name(audio_source_override, &to);
|
||||
const char *from = NULL, *to = NULL;
|
||||
pa_string_convert_num_to_str(CONV_STRING_AUDIO_SOURCE_FANCY, audio_source, &from);
|
||||
pa_string_convert_num_to_str(CONV_STRING_AUDIO_SOURCE_FANCY, audio_source, &to);
|
||||
pa_log_info("Audio mode %s, overriding audio source %s with %s",
|
||||
audio_mode_to_string(hw_module->state.mode),
|
||||
from ? from : "<unknown>",
|
||||
|
|
@ -2128,14 +2351,39 @@ bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
|
|||
|
||||
if (audio_source != hw_module->state.audio_source) {
|
||||
const char *name = NULL;
|
||||
pa_log_debug("set global audio source to %s (%#010x)",
|
||||
pa_droid_audio_source_name(audio_source, &name)
|
||||
pa_log_debug("Set global audio source to %s (%#010x)",
|
||||
pa_string_convert_num_to_str(CONV_STRING_AUDIO_SOURCE_FANCY, audio_source, &name)
|
||||
? name : "<unknown>",
|
||||
audio_source);
|
||||
hw_module->state.audio_source = audio_source;
|
||||
source_changed = true;
|
||||
|
||||
/* audio source changed */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* audio source did not change */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
|
||||
audio_devices_t device) {
|
||||
bool device_changed = false;
|
||||
bool source_changed = false;
|
||||
|
||||
pa_assert(hw_module);
|
||||
|
||||
if (hw_module->state.input_device != device) {
|
||||
const char *name = NULL;
|
||||
pa_log_debug("Set global input to %s (%#010x)",
|
||||
pa_string_convert_input_device_num_to_str(device, &name)
|
||||
? name : "<unknown>",
|
||||
device);
|
||||
hw_module->state.input_device = device;
|
||||
device_changed = true;
|
||||
}
|
||||
|
||||
source_changed = droid_set_audio_source(hw_module, hw_module->state.audio_source);
|
||||
|
||||
if (hw_module->state.active_input && (device_changed || source_changed))
|
||||
input_stream_set_route(hw_module, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,10 +52,12 @@ typedef enum {
|
|||
CONV_STRING_OUTPUT_DEVICE,
|
||||
CONV_STRING_INPUT_DEVICE,
|
||||
CONV_STRING_OUTPUT_FLAG,
|
||||
CONV_STRING_INPUT_FLAG
|
||||
CONV_STRING_INPUT_FLAG,
|
||||
CONV_STRING_AUDIO_SOURCE_FANCY,
|
||||
} pa_conversion_string_t;
|
||||
|
||||
bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, const char **to_str);
|
||||
bool pa_string_convert_str_to_num(pa_conversion_string_t type, const char *str, uint32_t *to_value);
|
||||
|
||||
bool pa_convert_output_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||
bool pa_convert_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||
|
|
@ -81,9 +83,6 @@ bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_so
|
|||
bool pa_droid_output_port_name(audio_devices_t value, const char **to_str);
|
||||
bool pa_droid_input_port_name(audio_devices_t value, const char **to_str);
|
||||
|
||||
/* Pretty audio source names */
|
||||
bool pa_droid_audio_source_name(audio_source_t value, const char **to_str);
|
||||
|
||||
int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
||||
const char *str, uint32_t *dst, char **unknown_entries);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <pulsecore/mutex.h>
|
||||
#include <pulsecore/strlist.h>
|
||||
#include <pulsecore/atomic.h>
|
||||
#include <pulsecore/modargs.h>
|
||||
|
||||
#include <droid/version.h>
|
||||
#include <droid/droid-config.h>
|
||||
|
|
@ -49,6 +50,7 @@
|
|||
#define PROP_DROID_OUTPUT_OFFLOAD "droid.output.offload"
|
||||
#define PROP_DROID_INPUT_BUILTIN "droid.input.builtin"
|
||||
#define PROP_DROID_INPUT_EXTERNAL "droid.input.external"
|
||||
#define PROP_DROID_INPUT_AUDIO_SOURCE "droid.input.source"
|
||||
|
||||
#define PA_DROID_PRIMARY_DEVICE "primary"
|
||||
|
||||
|
|
@ -67,6 +69,26 @@ typedef enum pa_droid_hook {
|
|||
PA_DROID_HOOK_MAX
|
||||
} pa_droid_hook_t;
|
||||
|
||||
enum pa_droid_quirk_type {
|
||||
QUIRK_INPUT_ATOI,
|
||||
QUIRK_SET_PARAMETERS,
|
||||
QUIRK_CLOSE_INPUT,
|
||||
QUIRK_UNLOAD_NO_CLOSE,
|
||||
QUIRK_NO_HW_VOLUME,
|
||||
QUIRK_OUTPUT_MAKE_WRITABLE,
|
||||
QUIRK_REALCALL,
|
||||
QUIRK_UNLOAD_CALL_EXIT,
|
||||
QUIRK_OUTPUT_FAST,
|
||||
QUIRK_OUTPUT_DEEP_BUFFER,
|
||||
QUIRK_AUDIO_CAL_WAIT,
|
||||
QUIRK_STANDBY_SET_ROUTE,
|
||||
QUIRK_SPEAKER_BEFORE_VOICE,
|
||||
QUIRK_COUNT
|
||||
};
|
||||
|
||||
struct pa_droid_quirks {
|
||||
bool enabled[QUIRK_COUNT];
|
||||
};
|
||||
|
||||
struct pa_droid_hw_module {
|
||||
PA_REFCNT_DECLARE;
|
||||
|
|
@ -95,7 +117,7 @@ struct pa_droid_hw_module {
|
|||
|
||||
pa_atomic_t active_outputs;
|
||||
|
||||
pa_droid_quirks *quirks;
|
||||
pa_droid_quirks quirks;
|
||||
|
||||
/* Mode and input control */
|
||||
struct _state {
|
||||
|
|
@ -217,27 +239,12 @@ struct pa_droid_profile_set {
|
|||
#define PA_DROID_OUTPUT_PARKING "output-parking"
|
||||
#define PA_DROID_INPUT_PARKING "input-parking"
|
||||
|
||||
enum pa_droid_quirk_type {
|
||||
QUIRK_INPUT_ATOI,
|
||||
QUIRK_SET_PARAMETERS,
|
||||
QUIRK_CLOSE_INPUT,
|
||||
QUIRK_UNLOAD_NO_CLOSE,
|
||||
QUIRK_NO_HW_VOLUME,
|
||||
QUIRK_OUTPUT_MAKE_WRITABLE,
|
||||
QUIRK_REALCALL,
|
||||
QUIRK_UNLOAD_CALL_EXIT,
|
||||
QUIRK_OUTPUT_FAST,
|
||||
QUIRK_OUTPUT_DEEP_BUFFER,
|
||||
QUIRK_COUNT
|
||||
};
|
||||
|
||||
struct pa_droid_quirks {
|
||||
bool enabled[QUIRK_COUNT];
|
||||
};
|
||||
|
||||
/* Open hardware module */
|
||||
/* 'config' can be NULL if it is assumed that hw module with module_id already is open. */
|
||||
pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id);
|
||||
/* First try to get already open hw module and if none found parse config and quirks from modargs
|
||||
* and do initial open. */
|
||||
pa_droid_hw_module *pa_droid_hw_module_get2(pa_core *core, pa_modargs *ma, const char *module_id);
|
||||
pa_droid_hw_module *pa_droid_hw_module_ref(pa_droid_hw_module *hw);
|
||||
void pa_droid_hw_module_unref(pa_droid_hw_module *hw);
|
||||
|
||||
|
|
@ -245,11 +252,11 @@ void pa_droid_hw_module_lock(pa_droid_hw_module *hw);
|
|||
bool pa_droid_hw_module_try_lock(pa_droid_hw_module *hw);
|
||||
void pa_droid_hw_module_unlock(pa_droid_hw_module *hw);
|
||||
|
||||
bool pa_droid_quirk_parse(pa_droid_hw_module *hw, const char *quirks);
|
||||
bool pa_droid_quirk_parse(pa_droid_quirks *quirks, const char *quirks_def);
|
||||
void pa_droid_quirk_log(pa_droid_hw_module *hw);
|
||||
|
||||
static inline bool pa_droid_quirk(pa_droid_hw_module *hw, enum pa_droid_quirk_type quirk) {
|
||||
return hw->quirks && hw->quirks->enabled[quirk];
|
||||
return hw && hw->quirks.enabled[quirk];
|
||||
}
|
||||
|
||||
bool pa_droid_hw_set_mode(pa_droid_hw_module *hw_module, audio_mode_t mode);
|
||||
|
|
@ -312,9 +319,15 @@ int pa_droid_stream_set_route(pa_droid_stream *s, audio_devices_t device);
|
|||
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
|
||||
const pa_sample_spec *default_sample_spec,
|
||||
const pa_channel_map *default_channel_map);
|
||||
/* Test if reconfiguring of input stream is needed */
|
||||
bool pa_droid_stream_reconfigure_input_needed(pa_droid_stream *s,
|
||||
const pa_sample_spec *requested_sample_spec,
|
||||
const pa_channel_map *requested_channel_map,
|
||||
const pa_proplist *proplist);
|
||||
bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
|
||||
const pa_sample_spec *requested_sample_spec,
|
||||
const pa_channel_map *requested_channel_map);
|
||||
const pa_channel_map *requested_channel_map,
|
||||
const pa_proplist *proplist);
|
||||
bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
|
||||
audio_devices_t device);
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ struct userdata {
|
|||
pa_usec_t write_time;
|
||||
pa_usec_t write_threshold;
|
||||
audio_devices_t prewrite_devices;
|
||||
bool prewrite_always;
|
||||
uint32_t prewrite_silence;
|
||||
pa_hook_slot *sink_put_hook_slot;
|
||||
pa_hook_slot *sink_unlink_hook_slot;
|
||||
|
|
@ -98,7 +99,6 @@ struct userdata {
|
|||
char *voice_property_key;
|
||||
char *voice_property_value;
|
||||
pa_sink_input *voice_virtual_sink_input;
|
||||
pa_sink_input *voice_control_sink_input;
|
||||
pa_hook_slot *sink_input_volume_changed_hook_slot;
|
||||
|
||||
pa_hook_slot *sink_input_put_hook_slot;
|
||||
|
|
@ -133,6 +133,8 @@ typedef struct droid_parameter_mapping {
|
|||
static void parameter_free(droid_parameter_mapping *m);
|
||||
static void userdata_free(struct userdata *u);
|
||||
static void set_voice_volume(struct userdata *u, pa_sink_input *i);
|
||||
static void apply_volume(pa_sink *s);
|
||||
static pa_sink_input *find_volume_control_sink_input(struct userdata *u);
|
||||
|
||||
static void set_primary_devices(struct userdata *u, audio_devices_t devices) {
|
||||
pa_assert(u);
|
||||
|
|
@ -293,7 +295,7 @@ static int thread_write(struct userdata *u) {
|
|||
pa_memblockq_drop(u->memblockq, c.length);
|
||||
pa_memblock_unref(c.memblock);
|
||||
u->write_time = 0;
|
||||
pa_log("failed to write stream (%d)", wrote);
|
||||
pa_log("failed to write stream (%zd)", wrote);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -395,6 +397,9 @@ static void thread_func(void *userdata) {
|
|||
if (pa_rtpoll_timer_elapsed(u->rtpoll)) {
|
||||
pa_usec_t sleept = 0;
|
||||
|
||||
if (u->use_hw_volume)
|
||||
pa_sink_volume_change_apply(u->sink, NULL);
|
||||
|
||||
thread_render(u);
|
||||
thread_write(u);
|
||||
|
||||
|
|
@ -402,6 +407,9 @@ static void thread_func(void *userdata) {
|
|||
sleept = u->buffer_time;
|
||||
|
||||
pa_rtpoll_set_timer_relative(u->rtpoll, sleept);
|
||||
|
||||
if (u->use_hw_volume)
|
||||
pa_sink_volume_change_apply(u->sink, NULL);
|
||||
}
|
||||
} else
|
||||
pa_rtpoll_set_timer_disabled(u->rtpoll);
|
||||
|
|
@ -459,9 +467,11 @@ static int unsuspend(struct userdata *u) {
|
|||
|
||||
pa_log_info("Resuming...");
|
||||
|
||||
apply_volume(u->sink);
|
||||
|
||||
if (u->prewrite_silence &&
|
||||
(u->primary_devices | u->extra_devices) & u->prewrite_devices &&
|
||||
pa_droid_output_stream_any_active(u->stream) == 0) {
|
||||
(u->prewrite_always || pa_droid_output_stream_any_active(u->stream) == 0)) {
|
||||
for (i = 0; i < u->prewrite_silence; i++)
|
||||
thread_write_silence(u);
|
||||
}
|
||||
|
|
@ -557,30 +567,39 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sink_set_volume_cb(pa_sink *s) {
|
||||
static void apply_volume(pa_sink *s) {
|
||||
struct userdata *u = s->userdata;
|
||||
pa_cvolume r;
|
||||
float val;
|
||||
|
||||
if (u->use_voice_volume)
|
||||
return;
|
||||
|
||||
if (!u->use_hw_volume)
|
||||
return;
|
||||
|
||||
/* Shift up by the base volume */
|
||||
pa_sw_cvolume_divide_scalar(&r, &s->real_volume, s->base_volume);
|
||||
|
||||
if (r.channels == 1) {
|
||||
float val = pa_sw_volume_to_linear(r.values[0]);
|
||||
pa_log_debug("Set %s hw volume %f", s->name, val);
|
||||
pa_droid_hw_module_lock(u->hw_module);
|
||||
if (u->stream->output->stream->set_volume(u->stream->output->stream, val, val) < 0)
|
||||
pa_log_warn("Failed to set hw volume.");
|
||||
pa_droid_hw_module_unlock(u->hw_module);
|
||||
} else if (r.channels == 2) {
|
||||
float val[2];
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
val[i] = pa_sw_volume_to_linear(r.values[i]);
|
||||
pa_log_debug("Set %s hw volume %f : %f", s->name, val[0], val[1]);
|
||||
pa_droid_hw_module_lock(u->hw_module);
|
||||
if (u->stream->output->stream->set_volume(u->stream->output->stream, val[0], val[1]) < 0)
|
||||
pa_log_warn("Failed to set hw volume.");
|
||||
pa_droid_hw_module_unlock(u->hw_module);
|
||||
}
|
||||
/* So far every hal implementation doing volume control expects
|
||||
* both channels to have equal value, so we can just average the value
|
||||
* from all channels. */
|
||||
val = pa_sw_volume_to_linear(pa_cvolume_avg(&r));
|
||||
|
||||
pa_log_debug("Set %s volume -> %f", s->name, val);
|
||||
pa_droid_hw_module_lock(u->hw_module);
|
||||
if (u->stream->output->stream->set_volume(u->stream->output->stream, val, val) < 0)
|
||||
pa_log_warn("Failed to set volume.");
|
||||
pa_droid_hw_module_unlock(u->hw_module);
|
||||
}
|
||||
|
||||
static void sink_set_volume_cb(pa_sink *s) {
|
||||
(void) s;
|
||||
/* noop */
|
||||
}
|
||||
|
||||
static void sink_write_volume_cb(pa_sink *s) {
|
||||
apply_volume(s);
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
|
|
@ -627,8 +646,10 @@ static void update_volumes(struct userdata *u) {
|
|||
u->use_hw_volume ? "hardware" : "software", u->sink->name);
|
||||
}
|
||||
|
||||
if (u->use_hw_volume)
|
||||
if (u->use_hw_volume) {
|
||||
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
||||
pa_sink_set_write_volume_callback(u->sink, sink_write_volume_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_sink_name(pa_modargs *ma, pa_sink_new_data *data, const char *module_id) {
|
||||
|
|
@ -692,13 +713,8 @@ static pa_hook_result_t sink_input_volume_changed_hook_cb(pa_core *c, pa_sink_in
|
|||
if (!u->use_voice_volume)
|
||||
return PA_HOOK_OK;
|
||||
|
||||
if (!u->voice_control_sink_input && sink_input_is_voice_control(u, sink_input))
|
||||
u->voice_control_sink_input = sink_input;
|
||||
|
||||
if (u->voice_control_sink_input != sink_input)
|
||||
return PA_HOOK_OK;
|
||||
|
||||
set_voice_volume(u, sink_input);
|
||||
if (sink_input_is_voice_control(u, sink_input))
|
||||
set_voice_volume(u, sink_input);
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
|
@ -801,14 +817,10 @@ void pa_droid_sink_set_voice_control(pa_sink* sink, bool enable) {
|
|||
if (u->voice_virtual_stream)
|
||||
create_voice_virtual_stream(u);
|
||||
|
||||
if (u->use_hw_volume)
|
||||
pa_sink_set_set_volume_callback(u->sink, NULL);
|
||||
|
||||
u->sink_input_volume_changed_hook_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED],
|
||||
PA_HOOK_LATE+10, (pa_hook_cb_t) sink_input_volume_changed_hook_cb, u);
|
||||
|
||||
if ((i = find_volume_control_sink_input(u))) {
|
||||
u->voice_control_sink_input = i;
|
||||
set_voice_volume(u, i);
|
||||
}
|
||||
|
||||
|
|
@ -818,15 +830,11 @@ void pa_droid_sink_set_voice_control(pa_sink* sink, bool enable) {
|
|||
if (u->voice_virtual_stream)
|
||||
destroy_voice_virtual_stream(u);
|
||||
|
||||
u->voice_control_sink_input = NULL;
|
||||
pa_hook_slot_free(u->sink_input_volume_changed_hook_slot);
|
||||
u->sink_input_volume_changed_hook_slot = NULL;
|
||||
|
||||
pa_log_debug("Using %s volume control with %s",
|
||||
u->use_hw_volume ? "hardware" : "software", u->sink->name);
|
||||
|
||||
if (u->use_hw_volume)
|
||||
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -837,8 +845,7 @@ static pa_hook_result_t sink_input_put_hook_cb(pa_core *c, pa_sink_input *sink_i
|
|||
const char *media_str;
|
||||
audio_devices_t devices;
|
||||
|
||||
if (u->use_voice_volume && !u->voice_control_sink_input && sink_input_is_voice_control(u, sink_input)) {
|
||||
u->voice_control_sink_input = sink_input;
|
||||
if (u->use_voice_volume && sink_input_is_voice_control(u, sink_input)) {
|
||||
set_voice_volume(u, sink_input);
|
||||
}
|
||||
|
||||
|
|
@ -873,9 +880,6 @@ static pa_hook_result_t sink_input_unlink_hook_cb(pa_core *c, pa_sink_input *sin
|
|||
const char *media_str;
|
||||
audio_devices_t devices;
|
||||
|
||||
if (u->voice_control_sink_input == sink_input)
|
||||
u->voice_control_sink_input = NULL;
|
||||
|
||||
/* Dynamic routing changes do not apply during active voice call. */
|
||||
if (u->use_voice_volume)
|
||||
return PA_HOOK_OK;
|
||||
|
|
@ -1061,6 +1065,9 @@ static bool parse_prewrite_on_resume(struct userdata *u, const char *prewrite_re
|
|||
/* Argument is string of for example "deep_buffer=AUDIO_DEVICE_OUT_SPEAKER:1,primary=FOO:5" */
|
||||
|
||||
while ((entry = pa_split(prewrite_resume, ",", &state))) {
|
||||
audio_devices_t prewrite_devices = 0;
|
||||
bool prewrite_always = false;
|
||||
char *tmp;
|
||||
|
||||
entry_len = strlen(entry);
|
||||
devices_index = strcspn(entry, "=");
|
||||
|
|
@ -1081,17 +1088,23 @@ static bool parse_prewrite_on_resume(struct userdata *u, const char *prewrite_re
|
|||
devices[value_index] = '\0';
|
||||
value = devices + value_index + 1;
|
||||
|
||||
if (!parse_device_list(devices, &u->prewrite_devices)) {
|
||||
u->prewrite_devices = 0;
|
||||
if (!parse_device_list(devices, &prewrite_devices))
|
||||
goto error;
|
||||
|
||||
if ((tmp = strstr(value, "/always"))) {
|
||||
prewrite_always = true;
|
||||
*tmp = '\0';
|
||||
}
|
||||
|
||||
if (strlen(value) == 0 || pa_atou(value, &b) < 0)
|
||||
goto error;
|
||||
|
||||
if (pa_streq(stream, name)) {
|
||||
pa_log_info("Using requested prewrite size for %s: %u (%u * %u).",
|
||||
pa_log_info("Using requested prewrite%s size for %s: %zu (%u * %zu).",
|
||||
prewrite_always ? "_always" : "",
|
||||
name, u->buffer_size * b, b, u->buffer_size);
|
||||
u->prewrite_devices = prewrite_devices;
|
||||
u->prewrite_always = prewrite_always;
|
||||
u->prewrite_silence = b;
|
||||
pa_xfree(entry);
|
||||
return true;
|
||||
|
|
@ -1131,7 +1144,6 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
|||
pa_channel_map channel_map;
|
||||
bool namereg_fail = false;
|
||||
pa_usec_t latency;
|
||||
pa_droid_config_audio *config = NULL; /* Only used when sink is created without card */
|
||||
uint32_t sink_buffer = 0;
|
||||
const char *prewrite_resume = NULL;
|
||||
bool mix_route = false;
|
||||
|
|
@ -1244,21 +1256,10 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
|||
}
|
||||
|
||||
/* Sink wasn't created from inside card module, so we'll need to open
|
||||
* hw module ourself.
|
||||
*
|
||||
* First let's find out if hw module has already been opened, or if we need to
|
||||
* do it ourself. */
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
|
||||
/* No hw module object in shared object db, let's open the module now. */
|
||||
if (!(config = pa_droid_config_load(ma)))
|
||||
goto fail;
|
||||
* hw module ourself. */
|
||||
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
|
||||
goto fail;
|
||||
|
||||
pa_droid_config_free(config);
|
||||
config = NULL;
|
||||
}
|
||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Default routing */
|
||||
|
|
@ -1286,9 +1287,9 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
|||
u->buffer_size = pa_droid_stream_buffer_size(u->stream);
|
||||
if (sink_buffer) {
|
||||
u->buffer_size = pa_droid_buffer_size_round_up(sink_buffer, u->buffer_size);
|
||||
pa_log_info("Using buffer size %u (requested %u).", u->buffer_size, sink_buffer);
|
||||
pa_log_info("Using buffer size %zu (requested %u).", u->buffer_size, sink_buffer);
|
||||
} else
|
||||
pa_log_info("Using buffer size %u.", u->buffer_size);
|
||||
pa_log_info("Using buffer size %zu.", u->buffer_size);
|
||||
|
||||
if ((prewrite_resume = pa_modargs_get_value(ma, "prewrite_on_resume", NULL))) {
|
||||
if (!parse_prewrite_on_resume(u, prewrite_resume, output->name)) {
|
||||
|
|
@ -1383,7 +1384,7 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
|||
/* HAL latencies are in milliseconds. */
|
||||
latency = pa_droid_stream_get_latency(u->stream);
|
||||
pa_sink_set_fixed_latency(u->sink, latency);
|
||||
pa_log_debug("Set fixed latency %llu usec", latency);
|
||||
pa_log_debug("Set fixed latency %" PRIu64 " usec", latency);
|
||||
pa_sink_set_max_request(u->sink, u->buffer_size);
|
||||
|
||||
if (u->sink->active_port)
|
||||
|
|
@ -1410,7 +1411,6 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
|||
return u->sink;
|
||||
|
||||
fail:
|
||||
pa_droid_config_free(config);
|
||||
pa_xfree(thread_name);
|
||||
|
||||
if (u)
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ static void unsuspend(struct userdata *u);
|
|||
static void source_reconfigure(struct userdata *u,
|
||||
const pa_sample_spec *reconfigure_sample_spec,
|
||||
const pa_channel_map *reconfigure_channel_map,
|
||||
const pa_proplist *proplist,
|
||||
audio_devices_t update_device);
|
||||
|
||||
/* Our droid source may be left in a state of not having an input stream
|
||||
|
|
@ -174,7 +175,7 @@ static int thread_read(struct userdata *u) {
|
|||
pa_memblock_release(chunk.memblock);
|
||||
|
||||
if (readd < 0) {
|
||||
pa_log("Failed to read from stream. (err %i)", readd);
|
||||
pa_log("Failed to read from stream. (err %zd)", readd);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +348,7 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
|||
if (!PA_SOURCE_IS_OPENED(u->source->state))
|
||||
do_routing(u, data->device);
|
||||
else
|
||||
source_reconfigure(u, NULL, NULL, data->device);
|
||||
source_reconfigure(u, NULL, NULL, NULL, data->device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -414,9 +415,9 @@ static void update_latency(struct userdata *u) {
|
|||
|
||||
if (u->source_buffer_size) {
|
||||
u->buffer_size = pa_droid_buffer_size_round_up(u->source_buffer_size, u->buffer_size);
|
||||
pa_log_info("Using buffer size %u (requested %u).", u->buffer_size, u->source_buffer_size);
|
||||
pa_log_info("Using buffer size %zu (requested %zu).", u->buffer_size, u->source_buffer_size);
|
||||
} else
|
||||
pa_log_info("Using buffer size %u.", u->buffer_size);
|
||||
pa_log_info("Using buffer size %zu.", u->buffer_size);
|
||||
|
||||
if (pa_thread_mq_get())
|
||||
pa_source_set_fixed_latency_within_thread(u->source, pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
|
||||
|
|
@ -429,6 +430,7 @@ static void update_latency(struct userdata *u) {
|
|||
static void source_reconfigure(struct userdata *u,
|
||||
const pa_sample_spec *reconfigure_sample_spec,
|
||||
const pa_channel_map *reconfigure_channel_map,
|
||||
const pa_proplist *proplist,
|
||||
audio_devices_t update_device) {
|
||||
pa_channel_map old_channel_map;
|
||||
pa_sample_spec old_sample_spec;
|
||||
|
|
@ -453,7 +455,7 @@ static void source_reconfigure(struct userdata *u,
|
|||
if (update_device)
|
||||
do_routing(u, update_device);
|
||||
|
||||
if (pa_droid_stream_reconfigure_input(u->stream, &new_sample_spec, &new_channel_map))
|
||||
if (pa_droid_stream_reconfigure_input(u->stream, &new_sample_spec, &new_channel_map, proplist))
|
||||
pa_log_info("Source reconfigured.");
|
||||
else
|
||||
pa_log_info("Failed to reconfigure input stream, no worries, using defaults.");
|
||||
|
|
@ -487,8 +489,10 @@ static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
|
|||
if (new_data->source != u->source)
|
||||
return PA_HOOK_OK;
|
||||
|
||||
if (pa_sample_spec_equal(&new_data->sample_spec, pa_droid_stream_sample_spec(u->stream)) &&
|
||||
pa_channel_map_equal(&new_data->channel_map, pa_droid_stream_channel_map(u->stream)))
|
||||
if (!pa_droid_stream_reconfigure_input_needed(u->stream,
|
||||
&new_data->sample_spec,
|
||||
&new_data->channel_map,
|
||||
new_data->proplist))
|
||||
return PA_HOOK_OK;
|
||||
|
||||
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
|
||||
|
|
@ -500,10 +504,11 @@ static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
|
|||
source_reconfigure(u,
|
||||
pa_droid_stream_sample_spec(primary_output),
|
||||
pa_droid_stream_channel_map(primary_output),
|
||||
new_data->proplist,
|
||||
0);
|
||||
|
||||
} else
|
||||
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, 0);
|
||||
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, new_data->proplist, 0);
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
|
@ -523,12 +528,12 @@ static void source_reconfigure_after_changes(struct userdata *u) {
|
|||
so = so_i;
|
||||
}
|
||||
|
||||
if (so) {
|
||||
if (!pa_sample_spec_equal(&so->sample_spec, pa_droid_stream_sample_spec(u->stream)) ||
|
||||
!pa_channel_map_equal(&so->channel_map, pa_droid_stream_channel_map(u->stream))) {
|
||||
pa_log_info("Source-output disconnected and our source needs to be reconfigured.");
|
||||
source_reconfigure(u, &so->sample_spec, &so->channel_map, 0);
|
||||
}
|
||||
if (so && pa_droid_stream_reconfigure_input_needed(u->stream,
|
||||
&so->sample_spec,
|
||||
&so->channel_map,
|
||||
so->proplist)) {
|
||||
pa_log_info("Source-output disconnected and our source needs to be reconfigured.");
|
||||
source_reconfigure(u, &so->sample_spec, &so->channel_map, so->proplist, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -558,7 +563,6 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
pa_channel_map channel_map;
|
||||
const char *format;
|
||||
bool namereg_fail = false;
|
||||
pa_droid_config_audio *config = NULL; /* Only used when source is created without card */
|
||||
uint32_t source_buffer = 0;
|
||||
|
||||
pa_assert(m);
|
||||
|
|
@ -634,20 +638,10 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
pa_assert_se((u->hw_module = pa_droid_hw_module_get(u->core, NULL, card_data->module_id)));
|
||||
} else {
|
||||
/* Source wasn't created from inside card module, so we'll need to open
|
||||
* hw module ourself.
|
||||
*
|
||||
* First let's find out if hw module has already been opened, or if we need to
|
||||
* do it ourself. */
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
|
||||
if (!(config = pa_droid_config_load(ma)))
|
||||
goto fail;
|
||||
* hw module ourself. */
|
||||
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
|
||||
goto fail;
|
||||
|
||||
pa_droid_config_free(config);
|
||||
config = NULL;
|
||||
}
|
||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Default routing */
|
||||
|
|
@ -770,7 +764,6 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
return u->source;
|
||||
|
||||
fail:
|
||||
pa_droid_config_free(config);
|
||||
pa_xfree(thread_name);
|
||||
|
||||
if (u)
|
||||
|
|
|
|||
|
|
@ -729,11 +729,9 @@ int pa__init(pa_module *m) {
|
|||
struct userdata *u = NULL;
|
||||
pa_modargs *ma = NULL;
|
||||
pa_card_new_data data;
|
||||
pa_droid_config_audio *config = NULL;
|
||||
const char *module_id;
|
||||
bool namereg_fail = false;
|
||||
bool default_profile = true;
|
||||
const char *quirks;
|
||||
pa_card_profile *voicecall = NULL;
|
||||
|
||||
pa_assert(m);
|
||||
|
|
@ -756,26 +754,8 @@ int pa__init(pa_module *m) {
|
|||
|
||||
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||
|
||||
/* First let's find out if hw module has already been opened, or if we need to
|
||||
* do it ourself. */
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
|
||||
/* No hw module object in shared object db, let's open the module now. */
|
||||
if (!(config = pa_droid_config_load(ma)))
|
||||
goto fail;
|
||||
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
|
||||
goto fail;
|
||||
|
||||
pa_droid_config_free(config);
|
||||
config = NULL;
|
||||
}
|
||||
|
||||
if ((quirks = pa_modargs_get_value(ma, "quirks", NULL))) {
|
||||
if (!pa_droid_quirk_parse(u->hw_module, quirks)) {
|
||||
pa_log("Failed to parse quirks.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||
goto fail;
|
||||
|
||||
pa_droid_quirk_log(u->hw_module);
|
||||
|
||||
|
|
@ -884,8 +864,6 @@ int pa__init(pa_module *m) {
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
pa_droid_config_free(config);
|
||||
|
||||
if (ma)
|
||||
pa_modargs_free(ma);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue