Skip to content

Commit a33adc9

Browse files
collinssmtwebster
authored andcommitted
libcvc: Add stream monitor functionality
1 parent 6896e22 commit a33adc9

File tree

2 files changed

+175
-1
lines changed

2 files changed

+175
-1
lines changed

libcvc/gvc-mixer-stream.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ enum
8585
PROP_STATE,
8686
};
8787

88+
enum {
89+
MONITOR_UPDATE,
90+
MONITOR_SUSPEND,
91+
LAST_SIGNAL
92+
};
93+
94+
static guint signals [LAST_SIGNAL] = { 0, };
95+
8896
static void gvc_mixer_stream_finalize (GObject *object);
8997

9098
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT)
@@ -883,6 +891,152 @@ gvc_mixer_stream_is_running (GvcMixerStream *stream)
883891
return FALSE;
884892
}
885893

894+
static void
895+
on_monitor_suspended_callback (pa_stream *s,
896+
void *userdata)
897+
{
898+
GvcMixerStream *stream;
899+
900+
stream = userdata;
901+
902+
if (pa_stream_is_suspended (s)) {
903+
g_debug ("Stream suspended");
904+
g_signal_emit (stream, signals[MONITOR_SUSPEND], 0);
905+
}
906+
}
907+
908+
static void
909+
on_monitor_read_callback (pa_stream *s,
910+
size_t length,
911+
void *userdata)
912+
{
913+
GvcMixerStream *stream;
914+
const void *data;
915+
double v;
916+
917+
stream = userdata;
918+
919+
if (pa_stream_peek (s, &data, &length) < 0) {
920+
g_warning ("Failed to read data from stream");
921+
return;
922+
}
923+
924+
assert (length > 0);
925+
assert (length % sizeof (float) == 0);
926+
927+
v = ((const float *) data)[length / sizeof (float) -1];
928+
929+
pa_stream_drop (s);
930+
931+
if (v < 0) {
932+
v = 0;
933+
}
934+
if (v > 1) {
935+
v = 1;
936+
}
937+
g_signal_emit (stream, signals[MONITOR_UPDATE], 0, v);
938+
}
939+
940+
/**
941+
* gvc_mixer_stream_create_monitor:
942+
* @stream:
943+
*/
944+
void
945+
gvc_mixer_stream_create_monitor (GvcMixerStream *stream)
946+
{
947+
pa_stream *s;
948+
char t[16];
949+
pa_buffer_attr attr;
950+
pa_sample_spec ss;
951+
pa_context *context;
952+
int res;
953+
pa_proplist *proplist;
954+
gboolean has_monitor;
955+
956+
if (stream == NULL) {
957+
return;
958+
}
959+
has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor"));
960+
if (has_monitor != FALSE) {
961+
return;
962+
}
963+
964+
g_debug ("Create monitor for %u",
965+
gvc_mixer_stream_get_index (stream));
966+
967+
context = gvc_mixer_stream_get_pa_context (stream);
968+
969+
if (pa_context_get_server_protocol_version (context) < 13) {
970+
return;
971+
}
972+
973+
ss.channels = 1;
974+
ss.format = PA_SAMPLE_FLOAT32;
975+
ss.rate = 25;
976+
977+
memset (&attr, 0, sizeof (attr));
978+
attr.fragsize = sizeof (float);
979+
attr.maxlength = (uint32_t) -1;
980+
981+
snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
982+
983+
proplist = pa_proplist_new ();
984+
pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl");
985+
s = pa_stream_new_with_proplist (context, "Peak detect", &ss, NULL, proplist);
986+
pa_proplist_free (proplist);
987+
if (s == NULL) {
988+
g_warning ("Failed to create monitoring stream");
989+
return;
990+
}
991+
992+
pa_stream_set_read_callback (s, on_monitor_read_callback, stream);
993+
pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, stream);
994+
995+
res = pa_stream_connect_record (s,
996+
t,
997+
&attr,
998+
(pa_stream_flags_t) (PA_STREAM_DONT_MOVE
999+
|PA_STREAM_PEAK_DETECT
1000+
|PA_STREAM_ADJUST_LATENCY));
1001+
if (res < 0) {
1002+
g_warning ("Failed to connect monitoring stream");
1003+
pa_stream_unref (s);
1004+
} else {
1005+
g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE));
1006+
g_object_set_data (G_OBJECT (stream), "pa_stream", s);
1007+
}
1008+
}
1009+
1010+
/**
1011+
* gvc_mixer_stream_remove_monitor:
1012+
* @stream:
1013+
*/
1014+
void
1015+
gvc_mixer_stream_remove_monitor (GvcMixerStream *stream)
1016+
{
1017+
pa_stream *s;
1018+
pa_context *context;
1019+
int res;
1020+
1021+
s = g_object_get_data (G_OBJECT (stream), "pa_stream");
1022+
if (s == NULL)
1023+
return;
1024+
g_assert (stream != NULL);
1025+
1026+
g_debug ("Stopping monitor for %u", pa_stream_get_index (s));
1027+
1028+
context = gvc_mixer_stream_get_pa_context (stream);
1029+
1030+
if (pa_context_get_server_protocol_version (context) < 13) {
1031+
return;
1032+
}
1033+
1034+
res = pa_stream_disconnect (s);
1035+
if (res == 0)
1036+
g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
1037+
g_object_set_data (G_OBJECT (stream), "pa_stream", NULL);
1038+
}
1039+
8861040
static void
8871041
gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
8881042
{
@@ -1031,6 +1185,22 @@ gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
10311185
"The index of the card for this stream",
10321186
PA_INVALID_INDEX, G_MAXLONG, PA_INVALID_INDEX,
10331187
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
1188+
signals [MONITOR_UPDATE] =
1189+
g_signal_new ("monitor-update",
1190+
G_TYPE_FROM_CLASS (klass),
1191+
G_SIGNAL_RUN_LAST,
1192+
G_STRUCT_OFFSET (GvcMixerStreamClass, monitor_update),
1193+
NULL, NULL,
1194+
g_cclosure_marshal_VOID__DOUBLE,
1195+
G_TYPE_NONE, 1, G_TYPE_DOUBLE);
1196+
signals [MONITOR_SUSPEND] =
1197+
g_signal_new ("monitor-suspend",
1198+
G_TYPE_FROM_CLASS (klass),
1199+
G_SIGNAL_RUN_LAST,
1200+
G_STRUCT_OFFSET (GvcMixerStreamClass, monitor_suspend),
1201+
NULL, NULL,
1202+
g_cclosure_marshal_VOID__VOID,
1203+
G_TYPE_NONE, 0, G_TYPE_NONE);
10341204
}
10351205

10361206
static void

libcvc/gvc-mixer-stream.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ typedef struct
5454
gboolean is_muted);
5555
gboolean (*change_port) (GvcMixerStream *stream,
5656
const char *port);
57+
void (*monitor_update) (GvcMixerStream *stream,
58+
gdouble v);
59+
void (*monitor_suspend) (GvcMixerStream *stream);
5760
} GvcMixerStreamClass;
5861

5962
typedef struct
@@ -104,7 +107,8 @@ gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream);
104107
gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream);
105108
guint gvc_mixer_stream_get_card_index (GvcMixerStream *stream);
106109
GvcMixerStreamState gvc_mixer_stream_get_state (GvcMixerStream *stream);
107-
110+
void gvc_mixer_stream_create_monitor (GvcMixerStream *stream);
111+
void gvc_mixer_stream_remove_monitor (GvcMixerStream *stream);
108112
/* private */
109113
gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream,
110114
pa_volume_t volume);

0 commit comments

Comments
 (0)