One step closer to doing things "properly"...
#include <libsoup/soup.h>
+#include <gst/gstelement.h>
+#include <gst/gstpipeline.h>
+#include <gst/gstutils.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/app/gstappsink.h>
+
struct chime_chat {
/* msgs first as it's a "subclass". Really ought to do proper GTypes here... */
struct chime_msgs m;
ChimeCallAudio *audio;
void *participants_ui;
PurpleMedia *media;
+
+ GstElement *audio_inpipeline;
+ GstElement *audio_outpipeline;
};
/*
g_signal_handlers_disconnect_matched(chat->call, G_SIGNAL_MATCH_FUNC|G_SIGNAL_MATCH_DATA,
0, 0, NULL, G_CALLBACK(on_call_participants), chat);
}
-static void on_audio_state(ChimeCall *call, int audio_state, struct chime_chat *chat)
+static void on_audio_state(ChimeCall *call, ChimeAudioState audio_state, struct chime_chat *chat)
{
purple_debug(PURPLE_DEBUG_INFO, "chime", "Audio state %d\n", audio_state);
+
+ if (audio_state == CHIME_AUDIO_STATE_AUDIO_MUTED && chat->audio_outpipeline) {
+ gst_element_set_state(chat->audio_outpipeline, GST_STATE_PAUSED);
+ } else if (audio_state == CHIME_AUDIO_STATE_AUDIO && chat->audio_outpipeline) {
+ gst_element_set_state(chat->audio_outpipeline, GST_STATE_PLAYING);
+ } else if (audio_state == CHIME_AUDIO_STATE_AUDIO && !chat->audio_inpipeline) {
+ // GStreamer - server-to-speakers
+ chat->audio_inpipeline = gst_pipeline_new("dirt-pipeline");
+
+ GstAppSrc *src = GST_APP_SRC(gst_element_factory_make("appsrc", "appsrc"));
+ GstCaps *audio_caps;
+ audio_caps = gst_caps_from_string("audio/x-opus,channel-mapping-family=0");
+ g_object_set (src, "caps", audio_caps, "format", GST_FORMAT_TIME, NULL);
+ gst_app_src_set_size(src, -1);
+ gst_app_src_set_max_bytes(src, 100);
+ gst_base_src_set_live(GST_BASE_SRC(src), TRUE);
+ gst_app_src_set_stream_type(src, GST_APP_STREAM_TYPE_STREAM);
+
+ GstElement *opusdec = gst_element_factory_make("opusdec", "opusdec");
+ GstElement *convert = gst_element_factory_make("audioconvert", "audioconvert");
+ GstElement *resample = gst_element_factory_make("audioresample", "audioresample");
+ GstElement *sink = gst_element_factory_make("autoaudiosink", "autoaudiosink");
+ gst_bin_add_many(GST_BIN(chat->audio_inpipeline), GST_ELEMENT(src), opusdec, convert, resample, sink, NULL);
+ if(!gst_element_link_many(GST_ELEMENT(src), opusdec, convert, resample, sink, NULL)) {
+ printf("Failed to link incoming pipeline\n");
+ }
+
+ // GStreamer - mic-to-server
+ chat->audio_outpipeline = gst_pipeline_new("upstream-audio");
+ GstElement *mic = gst_element_factory_make("autoaudiosrc", "autoaudiosrc");
+ convert = gst_element_factory_make("audioconvert", "audioconvert");
+ g_object_set(convert, "caps", gst_caps_from_string("audio/x-raw,format=S16,channels=1"), NULL);
+ resample = gst_element_factory_make("audioresample", "audioresample");
+ g_object_set(resample, "caps", gst_caps_from_string("audio/x-raw"), NULL);
+ GstElement *opusenc = gst_element_factory_make("opusenc", "opusenc");
+ g_object_set(opusenc, "caps", gst_caps_from_string("audio/x-raw,format=S16,channels=1"), NULL);
+ g_object_set(opusenc,
+ "bitrate", 16000,
+ "bitrate-type", "vbr",
+ NULL);
+ GstElement *appsink = gst_element_factory_make("appsink", "appsink");
+ g_object_set(appsink, "caps", gst_caps_from_string("audio/x-opus,channels=1,channel-mapping-family=0"), NULL);
+ gst_bin_add_many(GST_BIN(chat->audio_outpipeline), mic, convert, resample, opusenc, appsink, NULL);
+ if(!gst_element_link_many(mic, convert, resample, opusenc, appsink, NULL)) {
+ printf("Failed to link upstream pipeline\n");
+ }
+
+ chime_call_install_gst_app_callbacks(chat->call, src, GST_APP_SINK(appsink));
+ gst_element_set_state(chat->audio_inpipeline, GST_STATE_PLAYING);
+ gst_element_set_state(chat->audio_outpipeline, GST_STATE_PLAYING);
+ }
+
}
static void on_call_participants(ChimeCall *call, GHashTable *participants, struct chime_chat *chat)
chat->media);
chat->media = NULL;
}
-#if 0
- if (chat->audio) {
- chime_connection_call_audio_close(chat->audio);
- chat->audio = NULL;
+
+ if (chat->audio_inpipeline) {
+ GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(chat->audio_inpipeline), GST_DEBUG_GRAPH_SHOW_ALL, "chime-inpipeline");
+
+ gst_element_set_state(chat->audio_inpipeline, GST_STATE_NULL);
+ gst_object_unref(chat->audio_inpipeline);
+ chat->audio_inpipeline = NULL;
}
-#endif
+
+ if (chat->audio_outpipeline) {
+ GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(chat->audio_outpipeline), GST_DEBUG_GRAPH_SHOW_ALL, "chime-outpipeline");
+
+ gst_element_set_state(chat->audio_outpipeline, GST_STATE_NULL);
+ gst_object_unref(chat->audio_outpipeline);
+ chat->audio_outpipeline = NULL;
+ }
+
chime_connection_close_meeting(cxn, chat->meeting);
g_object_unref(chat->meeting);
}
audio->audio_msg.sample_time += (dts - audio->next_dts) / NS_PER_SAMPLE;
}
audio->next_dts = dts + dur;
- if (audio->state == AUDIO_STATE_AUDIO) {
+ if (audio->state == CHIME_AUDIO_STATE_AUDIO) {
printf ("State %d, send audio\n", audio->state);
audio->audio_msg.audio.len = info.size;
audio->audio_msg.audio.data = info.data;
chime_debug("Got AuthMessage authorised %d %d\n", msg->has_authorized, msg->authorized);
if (msg->has_authorized && msg->authorized) {
do_send_rt_packet(audio, NULL);
- chime_call_audio_set_state(audio, audio->muted ? AUDIO_STATE_AUDIOLESS :
- (audio->local_mute ? AUDIO_STATE_AUDIO_MUTED : AUDIO_STATE_AUDIO));
+ chime_call_audio_set_state(audio, audio->muted ? CHIME_AUDIO_STATE_AUDIOLESS :
+ (audio->local_mute ? CHIME_AUDIO_STATE_AUDIO_MUTED : CHIME_AUDIO_STATE_AUDIO));
}
auth_message__free_unpacked(msg, NULL);
g_signal_handlers_disconnect_matched(G_OBJECT(audio->call), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, audio);
chime_debug("close audio\n");
-#ifdef AUDIO_HACKS
- if (audio->pipeline) {
- GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(audio->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "chime-pipeline");
- gst_element_set_state(audio->pipeline, GST_STATE_NULL);
- gst_object_unref(audio->audio_src);
- gst_object_unref(audio->pipeline);
- }
- if (audio->outpipe) {
- GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(audio->outpipe), GST_DEBUG_GRAPH_SHOW_ALL, "chime-outpipe");
-
- gst_element_set_state(audio->outpipe, GST_STATE_NULL);
- gst_object_unref(audio->outpipe);
- }
-#endif
if (audio->data_ack_source)
g_source_remove(audio->data_ack_source);
if (audio->send_rt_source)
g_hash_table_destroy(audio->profiles);
g_slist_free_full(audio->data_messages, (GDestroyNotify) free_msgbuf);
chime_call_transport_disconnect(audio, hangup);
- chime_call_audio_set_state(audio, AUDIO_STATE_HANGUP);
+ chime_call_audio_set_state(audio, CHIME_AUDIO_STATE_HANGUP);
g_free(audio);
}
.enough_data = chime_appsrc_enough_data,
};
-void chime_call_install_gst_app_callbacks(ChimeCallAudio *audio, GstAppSrc *appsrc, GstAppSink *appsink)
+void chime_call_audio_install_gst_app_callbacks(ChimeCallAudio *audio, GstAppSrc *appsrc, GstAppSink *appsink)
{
audio->audio_src = appsrc;
audio->appsrc_need_data = FALSE;
g_mutex_init(&audio->transport_lock);
g_mutex_init(&audio->rt_lock);
-#ifdef AUDIO_HACKS
- if (!audio->muted) {
- // GStreamer - server-to-speakers
- audio->pipeline = gst_pipeline_new("dirt-pipeline");
-
- GstAppSrc *src = GST_APP_SRC(gst_element_factory_make("appsrc", "appsrc"));
- GstCaps *audio_caps;
- audio_caps = gst_caps_from_string("audio/x-opus,channel-mapping-family=0");
- g_object_set (src, "caps", audio_caps, "format", GST_FORMAT_TIME, NULL);
- gst_app_src_set_size(src, -1);
- gst_app_src_set_max_bytes(src, 100);
- gst_base_src_set_live(GST_BASE_SRC(src), TRUE);
- gst_app_src_set_stream_type(src, GST_APP_STREAM_TYPE_STREAM);
-
- GstElement *opusdec = gst_element_factory_make("opusdec", "opusdec");
- GstElement *convert = gst_element_factory_make("audioconvert", "audioconvert");
- GstElement *resample = gst_element_factory_make("audioresample", "audioresample");
- GstElement *sink = gst_element_factory_make("autoaudiosink", "autoaudiosink");
- gst_bin_add_many(GST_BIN(audio->pipeline), GST_ELEMENT(src), opusdec, convert, resample, sink, NULL);
- if(!gst_element_link_many(GST_ELEMENT(src), opusdec, convert, resample, sink, NULL)) {
- printf("Failed to link incoming pipeline\n");
- }
-
-
-
- // GStreamer - mic-to-server
- audio->outpipe = gst_pipeline_new("upstream-audio");
- GstElement *mic = gst_element_factory_make("autoaudiosrc", "autoaudiosrc");
- convert = gst_element_factory_make("audioconvert", "audioconvert");
- g_object_set(convert, "caps", gst_caps_from_string("audio/x-raw,format=S16,channels=1"), NULL);
- resample = gst_element_factory_make("audioresample", "audioresample");
- g_object_set(resample, "caps", gst_caps_from_string("audio/x-raw"), NULL);
- GstElement *opusenc = gst_element_factory_make("opusenc", "opusenc");
- g_object_set(opusenc, "caps", gst_caps_from_string("audio/x-raw,format=S16,channels=1"), NULL);
- g_object_set(opusenc,
- "bitrate", 16000,
- "bitrate-type", "vbr",
- NULL);
- GstElement *appsink = gst_element_factory_make("appsink", "appsink");
- g_object_set(appsink, "caps", gst_caps_from_string("audio/x-opus,channels=1,channel-mapping-family=0"), NULL);
- gst_bin_add_many(GST_BIN(audio->outpipe), mic, convert, resample, opusenc, appsink, NULL);
- if(!gst_element_link_many(mic, convert, resample, opusenc, appsink, NULL)) {
- printf("Failed to link upstream pipeline\n");
- }
- chime_call_install_gst_app_callbacks(audio, src, GST_APP_SINK(appsink));
- gst_element_set_state(audio->pipeline, GST_STATE_PLAYING);
- gst_element_set_state(audio->outpipe, GST_STATE_PLAYING);
-
- }
-#endif
-
rtmessage__init(&audio->rt_msg);
audio_message__init(&audio->audio_msg);
client_status_message__init(&audio->client_status_msg);
audio->audio_msg.sample_time = g_random_int();
chime_call_transport_connect(audio, muted);
- chime_call_audio_set_state(audio, AUDIO_STATE_CONNECTING);
+ chime_call_audio_set_state(audio, CHIME_AUDIO_STATE_CONNECTING);
return audio;
}
g_source_remove(audio->data_ack_source);
chime_call_transport_disconnect(audio, TRUE);
chime_call_transport_connect(audio, muted);
- chime_call_audio_set_state(audio, AUDIO_STATE_CONNECTING);
+ chime_call_audio_set_state(audio, CHIME_AUDIO_STATE_CONNECTING);
}
}
void chime_call_audio_local_mute(ChimeCallAudio *audio, gboolean muted)
{
audio->local_mute = muted;
- if (muted && audio->state == AUDIO_STATE_AUDIO) {
- chime_call_audio_set_state(audio, AUDIO_STATE_AUDIO_MUTED);
- if (audio->outpipe) {
- gst_element_set_state(audio->outpipe, GST_STATE_PAUSED);
- }
- } else if (!muted && audio->state == AUDIO_STATE_AUDIO_MUTED) {
- chime_call_audio_set_state(audio, AUDIO_STATE_AUDIO);
- if (audio->outpipe) {
- gst_element_set_state(audio->outpipe, GST_STATE_PLAYING);
- }
- }
+
+ if (muted && audio->state == CHIME_AUDIO_STATE_AUDIO)
+ chime_call_audio_set_state(audio, CHIME_AUDIO_STATE_AUDIO_MUTED);
+ else if (!muted && audio->state == CHIME_AUDIO_STATE_AUDIO_MUTED)
+ chime_call_audio_set_state(audio, CHIME_AUDIO_STATE_AUDIO);
}
* Lesser General Public License for more details.
*/
-#define AUDIO_HACKS
-
#include "chime-connection.h"
#include "chime-call.h"
#include "chime-connection-private.h"
#include "protobuf/rt_message.pb-c.h"
#include "protobuf/data_message.pb-c.h"
-#ifdef AUDIO_HACKS
-#include <gst/gstelement.h>
-#include <gst/gstpipeline.h>
-#include <gst/gstutils.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>
-#endif
-
-enum audio_state {
- AUDIO_STATE_CONNECTING = 0,
- AUDIO_STATE_FAILED,
- AUDIO_STATE_AUDIOLESS,
- AUDIO_STATE_AUDIO,
- AUDIO_STATE_AUDIO_MUTED,
- AUDIO_STATE_HANGUP,
- AUDIO_STATE_DISCONNECTED,
-};
struct _ChimeCallAudio {
ChimeCall *call;
- enum audio_state state;
+ ChimeAudioState state;
gboolean local_mute;
gboolean muted;
GMutex transport_lock;
gint32 data_next_logical_msg;
GSList *data_messages;
GHashTable *profiles;
-#ifdef AUDIO_HACKS
+
GstClockTime next_dts;
gint64 last_send_local_time;
GstAppSrc *audio_src;
gboolean appsrc_need_data;
- GstElement *pipeline;
- GstElement *outpipe;
-#endif
+
GMutex rt_lock;
guint send_rt_source;
gint64 last_server_time_offset;
ChimeCallAudio *chime_call_audio_open(ChimeConnection *cxn, ChimeCall *call, gboolean muted);
void chime_call_audio_close(ChimeCallAudio *audio, gboolean hangup);
void chime_call_audio_reopen(ChimeCallAudio *audio, gboolean muted);
-void chime_call_audio_set_state(ChimeCallAudio *audio, enum audio_state state);
+void chime_call_audio_set_state(ChimeCallAudio *audio, ChimeAudioState state);
void chime_call_audio_local_mute(ChimeCallAudio *audio, gboolean muted);
/* Called from audio code */
/* Callbacks into audio code from transport */
gboolean audio_receive_packet(ChimeCallAudio *audio, gconstpointer pkt, gsize len);
-void chime_call_install_gst_app_callbacks(ChimeCallAudio *audio, GstAppSrc *appsrc, GstAppSink *appsink);
+void chime_call_audio_install_gst_app_callbacks(ChimeCallAudio *audio, GstAppSrc *appsrc, GstAppSink *appsink);
SoupWebsocketConnection *ws = chime_connection_websocket_connect_finish(cxn, res, &error);
if (!ws) {
chime_debug("audio ws error %s\n", error->message);
- audio->state = AUDIO_STATE_FAILED;
+ audio->state = CHIME_AUDIO_STATE_FAILED;
g_object_unref(cxn);
return;
}
chime_call_audio_reopen(call->audio, muted);
}
-void chime_call_audio_set_state(ChimeCallAudio *audio, enum audio_state state)
+void chime_call_audio_set_state(ChimeCallAudio *audio, ChimeAudioState state)
{
if (audio->state == state)
return;
audio->state = state;
g_signal_emit(audio->call, signals[AUDIO_STATE], 0, state);
}
+
+void chime_call_install_gst_app_callbacks(ChimeCall *call, GstAppSrc *appsrc, GstAppSink *appsink)
+{
+ if (call->audio)
+ chime_call_audio_install_gst_app_callbacks(call->audio, appsrc, appsink);
+}
#include "chime-contact.h"
#include "chime-object.h"
+#include <gst/app/gstappsrc.h>
+#include <gst/app/gstappsink.h>
+
G_BEGIN_DECLS
#define CHIME_TYPE_CALL (chime_call_get_type ())
struct _ChimeCallAudio;
typedef struct _ChimeCallAudio ChimeCallAudio;
+typedef enum {
+ CHIME_AUDIO_STATE_CONNECTING = 0,
+ CHIME_AUDIO_STATE_FAILED,
+ CHIME_AUDIO_STATE_AUDIOLESS,
+ CHIME_AUDIO_STATE_AUDIO,
+ CHIME_AUDIO_STATE_AUDIO_MUTED,
+ CHIME_AUDIO_STATE_HANGUP,
+ CHIME_AUDIO_STATE_DISCONNECTED,
+} ChimeAudioState;
+
+void chime_call_install_gst_app_callbacks(ChimeCall *call, GstAppSrc *appsrc, GstAppSink *appsink);
G_END_DECLS