Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Librem5
debs
callaudiod
Commits
69741042
Commit
69741042
authored
Jan 28, 2021
by
Arnaud Ferraris
Browse files
New upstream version 0.1.0
parents
cb6b77ef
007b3412
Changes
3
Hide whitespace changes
Inline
Side-by-side
.editorconfig
0 → 100644
View file @
69741042
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
[meson.build]
indent_size = 2
tab_size = 2
indent_style = space
[*.{c,h}]
indent_size = 4
tab_size = 4
indent_style = space
max_line_length = 80
[*.xml]
indent_size = 2
tab_size = 2
indent_style = space
meson.build
View file @
69741042
...
...
@@ -8,7 +8,7 @@
project
(
'callaudiod'
,
'c'
,
version
:
'0.
0.5
'
,
version
:
'0.
1.0
'
,
license
:
'LGPLv3+'
,
meson_version
:
'>= 0.50.0'
,
default_options
:
...
...
src/cad-pulse.c
View file @
69741042
...
...
@@ -42,6 +42,9 @@ struct _CadPulse
gboolean
has_voice_profile
;
gchar
*
speaker_port
;
GHashTable
*
sink_ports
;
GHashTable
*
source_ports
;
CallAudioMode
current_mode
;
};
...
...
@@ -53,15 +56,25 @@ typedef struct _CadPulseOperation {
guint
value
;
}
CadPulseOperation
;
static
const
gchar
*
get_available_output
(
const
pa_sink_info
*
sink
,
const
gchar
*
exclude
)
static
void
pulseaudio_cleanup
(
CadPulse
*
self
);
static
gboolean
pulseaudio_connect
(
CadPulse
*
self
);
/******************************************************************************
* Source management
*
* The following functions take care of monitoring and configuring the default
* source (input)
******************************************************************************/
static
const
gchar
*
get_available_source_port
(
const
pa_source_info
*
source
,
const
gchar
*
exclude
)
{
pa_s
ink
_port_info
*
available_port
=
NULL
;
pa_s
ource
_port_info
*
available_port
=
NULL
;
guint
i
;
g_debug
(
"looking for available
por
t excluding '%s'"
,
exclude
);
g_debug
(
"looking for available
inpu
t excluding '%s'"
,
exclude
);
for
(
i
=
0
;
i
<
s
ink
->
n_ports
;
i
++
)
{
pa_s
ink
_port_info
*
port
=
s
ink
->
ports
[
i
];
for
(
i
=
0
;
i
<
s
ource
->
n_ports
;
i
++
)
{
pa_s
ource
_port_info
*
port
=
s
ource
->
ports
[
i
];
if
((
exclude
&&
strcmp
(
port
->
name
,
exclude
)
==
0
)
||
port
->
available
==
PA_PORT_AVAILABLE_NO
)
{
...
...
@@ -73,18 +86,63 @@ static const gchar *get_available_output(const pa_sink_info *sink, const gchar *
}
if
(
available_port
)
{
g_debug
(
"found available
por
t '%s'"
,
available_port
->
name
);
g_debug
(
"found available
inpu
t '%s'"
,
available_port
->
name
);
return
available_port
->
name
;
}
g_warning
(
"no available
por
t found!"
);
g_warning
(
"no available
inpu
t found!"
);
return
NULL
;
}
static
void
change_source_info
(
pa_context
*
ctx
,
const
pa_source_info
*
info
,
int
eol
,
void
*
data
)
{
CadPulse
*
self
=
data
;
const
gchar
*
target_port
;
pa_operation
*
op
;
gboolean
change
=
FALSE
;
guint
i
;
if
(
eol
!=
0
)
return
;
if
(
!
info
)
{
g_critical
(
"PA returned no source info (eol=%d)"
,
eol
);
return
;
}
if
(
info
->
index
!=
self
->
source_id
)
return
;
for
(
i
=
0
;
i
<
info
->
n_ports
;
i
++
)
{
pa_source_port_info
*
port
=
info
->
ports
[
i
];
if
(
port
->
available
!=
PA_PORT_AVAILABLE_UNKNOWN
)
{
enum
pa_port_available
available
;
available
=
GPOINTER_TO_INT
(
g_hash_table_lookup
(
self
->
source_ports
,
port
->
name
));
if
(
available
!=
port
->
available
)
{
g_hash_table_insert
(
self
->
source_ports
,
g_strdup
(
port
->
name
),
GINT_TO_POINTER
(
port
->
available
));
change
=
TRUE
;
}
}
}
if
(
change
)
{
target_port
=
get_available_source_port
(
info
,
NULL
);
if
(
target_port
)
{
op
=
pa_context_set_source_port_by_index
(
ctx
,
self
->
source_id
,
target_port
,
NULL
,
NULL
);
if
(
op
)
pa_operation_unref
(
op
);
}
}
}
static
void
process_new_source
(
CadPulse
*
self
,
const
pa_source_info
*
info
)
{
const
gchar
*
prop
;
int
i
;
prop
=
pa_proplist_gets
(
info
->
proplist
,
PA_PROP_DEVICE_CLASS
);
if
(
prop
&&
strcmp
(
prop
,
SINK_CLASS
)
!=
0
)
...
...
@@ -93,35 +151,134 @@ static void process_new_source(CadPulse *self, const pa_source_info *info)
return
;
self
->
source_id
=
info
->
index
;
if
(
self
->
source_ports
)
g_hash_table_destroy
(
self
->
source_ports
);
self
->
source_ports
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
for
(
i
=
0
;
i
<
info
->
n_ports
;
i
++
)
{
pa_source_port_info
*
port
=
info
->
ports
[
i
];
if
(
port
->
available
!=
PA_PORT_AVAILABLE_UNKNOWN
)
{
g_hash_table_insert
(
self
->
source_ports
,
g_strdup
(
port
->
name
),
GINT_TO_POINTER
(
port
->
available
));
}
}
g_debug
(
"SOURCE: idx=%u name='%s'"
,
info
->
index
,
info
->
name
);
}
static
void
process_sink_ports
(
CadPulse
*
self
,
const
pa_s
ink
_info
*
info
)
static
void
init_source_info
(
pa_context
*
ctx
,
const
pa_s
ource
_info
*
info
,
int
eol
,
void
*
data
)
{
int
i
;
CadPulse
*
self
=
data
;
const
gchar
*
target_port
;
pa_operation
*
op
;
if
(
eol
!=
0
)
return
;
if
(
!
info
)
{
g_critical
(
"PA returned no source info (eol=%d)"
,
eol
);
return
;
}
process_new_source
(
self
,
info
);
if
(
self
->
source_id
<
0
)
return
;
target_port
=
get_available_source_port
(
info
,
NULL
);
if
(
target_port
)
{
op
=
pa_context_set_source_port_by_index
(
ctx
,
self
->
source_id
,
target_port
,
NULL
,
NULL
);
if
(
op
)
pa_operation_unref
(
op
);
}
}
/******************************************************************************
* Sink management
*
* The following functions take care of monitoring and configuring the default
* sink (output)
******************************************************************************/
static
const
gchar
*
get_available_sink_port
(
const
pa_sink_info
*
sink
,
const
gchar
*
exclude
)
{
pa_sink_port_info
*
available_port
=
NULL
;
guint
i
;
g_debug
(
"looking for available output excluding '%s'"
,
exclude
);
for
(
i
=
0
;
i
<
sink
->
n_ports
;
i
++
)
{
pa_sink_port_info
*
port
=
sink
->
ports
[
i
];
if
((
exclude
&&
strcmp
(
port
->
name
,
exclude
)
==
0
)
||
port
->
available
==
PA_PORT_AVAILABLE_NO
)
{
continue
;
}
if
(
!
available_port
||
port
->
priority
>
available_port
->
priority
)
available_port
=
port
;
}
if
(
available_port
)
{
g_debug
(
"found available output '%s'"
,
available_port
->
name
);
return
available_port
->
name
;
}
g_warning
(
"no available output found!"
);
return
NULL
;
}
static
void
change_sink_info
(
pa_context
*
ctx
,
const
pa_sink_info
*
info
,
int
eol
,
void
*
data
)
{
CadPulse
*
self
=
data
;
const
gchar
*
target_port
;
pa_operation
*
op
;
gboolean
change
=
FALSE
;
guint
i
;
if
(
eol
!=
0
)
return
;
if
(
!
info
)
{
g_critical
(
"PA returned no sink info (eol=%d)"
,
eol
);
return
;
}
if
(
info
->
index
!=
self
->
sink_id
)
return
;
for
(
i
=
0
;
i
<
info
->
n_ports
;
i
++
)
{
pa_sink_port_info
*
port
=
info
->
ports
[
i
];
if
(
strstr
(
port
->
name
,
SND_USE_CASE_DEV_SPEAKER
)
!=
NULL
)
{
if
(
self
->
speaker_port
)
{
if
(
strcmp
(
port
->
name
,
self
->
speaker_port
)
!=
0
)
{
g_free
(
self
->
speaker_port
);
self
->
speaker_port
=
g_strdup
(
port
->
name
);
}
}
else
{
self
->
speaker_port
=
g_strdup
(
port
->
name
);
if
(
port
->
available
!=
PA_PORT_AVAILABLE_UNKNOWN
)
{
enum
pa_port_available
available
;
available
=
GPOINTER_TO_INT
(
g_hash_table_lookup
(
self
->
sink_ports
,
port
->
name
));
if
(
available
!=
port
->
available
)
{
g_hash_table_insert
(
self
->
sink_ports
,
g_strdup
(
port
->
name
),
GINT_TO_POINTER
(
port
->
available
));
change
=
TRUE
;
}
}
}
g_debug
(
"SINK: speaker_port='%s'"
,
self
->
speaker_port
);
if
(
change
)
{
target_port
=
get_available_sink_port
(
info
,
NULL
);
if
(
target_port
)
{
op
=
pa_context_set_sink_port_by_index
(
ctx
,
self
->
sink_id
,
target_port
,
NULL
,
NULL
);
if
(
op
)
pa_operation_unref
(
op
);
}
}
}
static
void
process_new_sink
(
CadPulse
*
self
,
const
pa_sink_info
*
info
)
{
const
gchar
*
prop
;
guint
i
;
prop
=
pa_proplist_gets
(
info
->
proplist
,
PA_PROP_DEVICE_CLASS
);
if
(
prop
&&
strcmp
(
prop
,
SINK_CLASS
)
!=
0
)
...
...
@@ -130,30 +287,41 @@ static void process_new_sink(CadPulse *self, const pa_sink_info *info)
return
;
self
->
sink_id
=
info
->
index
;
if
(
self
->
sink_ports
)
g_hash_table_destroy
(
self
->
sink_ports
);
self
->
sink_ports
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
g_debug
(
"SINK: idx=%u name='%s'"
,
info
->
index
,
info
->
name
);
process_sink_ports
(
self
,
info
);
}
static
void
init_source_info
(
pa_context
*
ctx
,
const
pa_source_info
*
info
,
int
eol
,
void
*
data
)
{
CadPulse
*
self
=
data
;
for
(
i
=
0
;
i
<
info
->
n_ports
;
i
++
)
{
pa_sink_port_info
*
port
=
info
->
ports
[
i
];
if
(
eol
!=
0
)
return
;
if
(
strstr
(
port
->
name
,
SND_USE_CASE_DEV_SPEAKER
)
!=
NULL
)
{
if
(
self
->
speaker_port
)
{
if
(
strcmp
(
port
->
name
,
self
->
speaker_port
)
!=
0
)
{
g_free
(
self
->
speaker_port
);
self
->
speaker_port
=
g_strdup
(
port
->
name
);
}
}
else
{
self
->
speaker_port
=
g_strdup
(
port
->
name
);
}
}
if
(
!
info
)
{
g_critical
(
"PA returned no source info (eol=%d)"
,
eol
);
return
;
if
(
port
->
available
!=
PA_PORT_AVAILABLE_UNKNOWN
)
{
g_hash_table_insert
(
self
->
sink_ports
,
g_strdup
(
port
->
name
),
GINT_TO_POINTER
(
port
->
available
));
}
}
process_new_source
(
self
,
info
);
g_debug
(
"SINK: speaker_port='%s'"
,
self
->
speaker_port
);
}
static
void
init_sink_info
(
pa_context
*
ctx
,
const
pa_sink_info
*
info
,
int
eol
,
void
*
data
)
{
CadPulse
*
self
=
data
;
const
gchar
*
target_port
;
pa_operation
*
op
;
if
(
eol
!=
0
)
return
;
...
...
@@ -164,8 +332,26 @@ static void init_sink_info(pa_context *ctx, const pa_sink_info *info, int eol, v
}
process_new_sink
(
self
,
info
);
if
(
self
->
sink_id
<
0
)
return
;
target_port
=
get_available_sink_port
(
info
,
NULL
);
if
(
target_port
)
{
g_debug
(
" Using sink port '%s'"
,
target_port
);
op
=
pa_context_set_sink_port_by_index
(
ctx
,
self
->
sink_id
,
target_port
,
NULL
,
NULL
);
if
(
op
)
pa_operation_unref
(
op
);
}
}
/******************************************************************************
* Card management
*
* The following functions take care of gathering information about the default
* sound card
******************************************************************************/
static
void
init_card_info
(
pa_context
*
ctx
,
const
pa_card_info
*
info
,
int
eol
,
void
*
data
)
{
CadPulse
*
self
=
data
;
...
...
@@ -206,22 +392,55 @@ static void init_card_info(pa_context *ctx, const pa_card_info *info, int eol, v
g_debug
(
"CARD: %s voice profile"
,
self
->
has_voice_profile
?
"has"
:
"doesn't have"
);
}
static
void
init_cards_list
(
CadPulse
*
self
)
{
pa_operation
*
op
;
self
->
card_id
=
self
->
sink_id
=
self
->
source_id
=
-
1
;
op
=
pa_context_get_card_info_list
(
self
->
ctx
,
init_card_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
op
=
pa_context_get_sink_info_list
(
self
->
ctx
,
init_sink_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
op
=
pa_context_get_source_info_list
(
self
->
ctx
,
init_source_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
}
/******************************************************************************
* PulseAudio management
*
* The following functions configure the PulseAudio connection and monitor the
* state of PulseAudio objects
******************************************************************************/
static
void
init_module_info
(
pa_context
*
ctx
,
const
pa_module_info
*
info
,
int
eol
,
void
*
data
)
{
pa_operation
*
op
;
if
(
eol
!=
0
)
return
;
if
(
!
info
)
{
g_critical
(
"PA returned no module info (eol=%d)"
,
eol
);
return
;
}
g_debug
(
"MODULE: idx=%u name='%s'"
,
info
->
index
,
info
->
name
);
if
(
strcmp
(
info
->
name
,
"module-switch-on-port-available"
)
==
0
)
{
g_debug
(
"MODULE: unloading '%s'"
,
info
->
name
);
op
=
pa_context_unload_module
(
ctx
,
info
->
index
,
NULL
,
NULL
);
if
(
op
)
pa_operation_unref
(
op
);
}
}
static
void
init_pulseaudio_objects
(
CadPulse
*
self
)
{
pa_operation
*
op
;
self
->
card_id
=
self
->
sink_id
=
self
->
source_id
=
-
1
;
self
->
sink_ports
=
self
->
source_ports
=
NULL
;
op
=
pa_context_get_card_info_list
(
self
->
ctx
,
init_card_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
op
=
pa_context_get_module_info_list
(
self
->
ctx
,
init_module_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
op
=
pa_context_get_sink_info_list
(
self
->
ctx
,
init_sink_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
op
=
pa_context_get_source_info_list
(
self
->
ctx
,
init_source_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
}
static
void
changed_cb
(
pa_context
*
ctx
,
pa_subscription_event_type_t
type
,
uint32_t
idx
,
void
*
data
)
{
...
...
@@ -234,6 +453,8 @@ static void changed_cb(pa_context *ctx, pa_subscription_event_type_t type, uint3
if
(
idx
==
self
->
sink_id
&&
kind
==
PA_SUBSCRIPTION_EVENT_REMOVE
)
{
g_debug
(
"sink %u removed"
,
idx
);
self
->
sink_id
=
-
1
;
g_hash_table_destroy
(
self
->
sink_ports
);
self
->
sink_ports
=
NULL
;
}
else
if
(
kind
==
PA_SUBSCRIPTION_EVENT_NEW
)
{
g_debug
(
"new sink %u"
,
idx
);
op
=
pa_context_get_sink_info_by_index
(
ctx
,
idx
,
init_sink_info
,
self
);
...
...
@@ -245,6 +466,8 @@ static void changed_cb(pa_context *ctx, pa_subscription_event_type_t type, uint3
if
(
idx
==
self
->
source_id
&&
kind
==
PA_SUBSCRIPTION_EVENT_REMOVE
)
{
g_debug
(
"source %u removed"
,
idx
);
self
->
source_id
=
-
1
;
g_hash_table_destroy
(
self
->
source_ports
);
self
->
source_ports
=
NULL
;
}
else
if
(
kind
==
PA_SUBSCRIPTION_EVENT_NEW
)
{
g_debug
(
"new sink %u"
,
idx
);
op
=
pa_context_get_source_info_by_index
(
ctx
,
idx
,
init_source_info
,
self
);
...
...
@@ -252,16 +475,28 @@ static void changed_cb(pa_context *ctx, pa_subscription_event_type_t type, uint3
pa_operation_unref
(
op
);
}
break
;
case
PA_SUBSCRIPTION_EVENT_CARD
:
if
(
idx
==
self
->
card_id
&&
kind
==
PA_SUBSCRIPTION_EVENT_CHANGE
)
{
g_debug
(
"card %u changed"
,
idx
);
if
(
self
->
sink_id
!=
-
1
)
{
op
=
pa_context_get_sink_info_by_index
(
ctx
,
self
->
sink_id
,
change_sink_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
}
if
(
self
->
source_id
!=
-
1
)
{
op
=
pa_context_get_source_info_by_index
(
ctx
,
self
->
source_id
,
change_source_info
,
self
);
if
(
op
)
pa_operation_unref
(
op
);
}
}
break
;
default:
break
;
}
}
static
void
subscribe_cb
(
pa_context
*
ctx
,
int
success
,
void
*
data
)
{
g_debug
(
"subscribe returned %d"
,
success
);
}
static
void
pulse_state_cb
(
pa_context
*
ctx
,
void
*
data
)
{
CadPulse
*
self
=
data
;
...
...
@@ -276,25 +511,33 @@ static void pulse_state_cb(pa_context *ctx, void *data)
g_debug
(
"PA not ready"
);
break
;
case
PA_CONTEXT_FAILED
:
g_error
(
"Error in PulseAudio context: %s"
,
pa_strerror
(
pa_context_errno
(
ctx
)));
g_critical
(
"Error in PulseAudio context: %s"
,
pa_strerror
(
pa_context_errno
(
ctx
)));
pulseaudio_cleanup
(
self
);
g_idle_add
(
G_SOURCE_FUNC
(
pulseaudio_connect
),
self
);
break
;
case
PA_CONTEXT_TERMINATED
:
case
PA_CONTEXT_READY
:
pa_context_set_state_callback
(
ctx
,
NULL
,
NULL
);
pa_context_set_subscribe_callback
(
ctx
,
changed_cb
,
self
);
pa_context_subscribe
(
ctx
,
PA_SUBSCRIPTION_MASK_SINK
|
PA_SUBSCRIPTION_MASK_SOURCE
,
subscribe_cb
,
self
);
PA_SUBSCRIPTION_MASK_SINK
|
PA_SUBSCRIPTION_MASK_SOURCE
|
PA_SUBSCRIPTION_MASK_CARD
,
NULL
,
self
);
g_debug
(
"PA is ready, initializing cards list"
);
init_
cards_list
(
self
);
init_
pulseaudio_objects
(
self
);
break
;
}
}
static
void
constructed
(
GObject
*
object
)
static
void
pulseaudio_cleanup
(
CadPulse
*
self
)
{
if
(
self
->
ctx
)
{
pa_context_disconnect
(
self
->
ctx
);
pa_context_unref
(
self
->
ctx
);
self
->
ctx
=
NULL
;
}
}
static
gboolean
pulseaudio_connect
(
CadPulse
*
self
)
{
GObjectClass
*
parent_class
=
g_type_class_peek
(
G_TYPE_OBJECT
);
CadPulse
*
self
=
CAD_PULSE
(
object
);
pa_proplist
*
props
;
int
err
;
...
...
@@ -305,11 +548,13 @@ static void constructed(GObject *object)
err
=
pa_proplist_sets
(
props
,
PA_PROP_APPLICATION_NAME
,
APPLICATION_NAME
);
err
=
pa_proplist_sets
(
props
,
PA_PROP_APPLICATION_ID
,
APPLICATION_ID
);
self
->
loop
=
pa_glib_mainloop_new
(
NULL
);
if
(
!
self
->
loop
)
self
->
loop
=
pa_glib_mainloop_new
(
NULL
);
if
(
!
self
->
loop
)
g_error
(
"Error creating PulseAudio main loop"
);
self
->
ctx
=
pa_context_new
(
pa_glib_mainloop_get_api
(
self
->
loop
),
APPLICATION_NAME
);
if
(
!
self
->
ctx
)
self
->
ctx
=
pa_context_new
(
pa_glib_mainloop_get_api
(
self
->
loop
),
APPLICATION_NAME
);
if
(
!
self
->
ctx
)
g_error
(
"Error creating PulseAudio context"
);
...
...
@@ -318,6 +563,20 @@ static void constructed(GObject *object)
if
(
err
<
0
)
g_error
(
"Error connecting to PulseAudio context: %s"
,
pa_strerror
(
err
));
return
G_SOURCE_REMOVE
;
}
/******************************************************************************
* GObject base functions
******************************************************************************/
static
void
constructed
(
GObject
*
object
)
{
GObjectClass
*
parent_class
=
g_type_class_peek
(
G_TYPE_OBJECT
);
CadPulse
*
self
=
CAD_PULSE
(
object
);
pulseaudio_connect
(
self
);
parent_class
->
constructed
(
object
);
}
...
...
@@ -330,11 +589,9 @@ static void dispose(GObject *object)
if
(
self
->
speaker_port
)
g_free
(
self
->
speaker_port
);
if
(
self
->
ctx
)
{
pa_context_disconnect
(
self
->
ctx
);
pa_context_unref
(
self
->
ctx
);
self
->
ctx
=
NULL
;
pulseaudio_cleanup
(
self
);
if
(
self
->
loop
)
{
pa_glib_mainloop_free
(
self
->
loop
);
self
->
loop
=
NULL
;
}
...
...
@@ -367,6 +624,13 @@ CadPulse *cad_pulse_get_default(void)
return
pulse
;
}
/******************************************************************************
* Commands management
*
* The following functions handle external requests to switch mode, output port
* or microphone status
******************************************************************************/
static
void
operation_complete_cb
(
pa_context
*
ctx
,
int
success
,
void
*
data
)
{
CadPulseOperation
*
operation
=
data
;
...
...
@@ -453,9 +717,9 @@ static void set_output_port(pa_context *ctx, const pa_sink_info *info, int eol,
* be selected anyway.
*/
if
(
operation
->
value
==
CALL_AUDIO_MODE_CALL
)
target_port
=
get_available_
outpu
t
(
info
,
operation
->
pulse
->
speaker_port
);
target_port
=
get_available_
sink_por
t
(
info
,
operation
->
pulse
->
speaker_port
);
else
target_port
=
get_available_
outpu
t
(
info
,
NULL
);
target_port
=
get_available_
sink_por
t
(
info
,
NULL
);
}
else
{
/*
* When forcing speaker output, we simply select the speaker port.
...
...
@@ -466,7 +730,7 @@ static void set_output_port(pa_context *ctx, const pa_sink_info *info, int eol,
if
(
operation
->
value
)
target_port
=
operation
->
pulse
->
speaker_port
;
else
target_port
=
get_available_
outpu
t
(
info
,
operation
->
pulse
->
speaker_port
);
target_port
=
get_available_
sink_por
t
(
info
,
operation
->
pulse
->
speaker_port
);
}
g_debug
(
"active port is '%s', target port is '%s'"
,
info
->
active_port
->
name
,
target_port
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment